CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / js / src / jstracer.h
blob823d3ab161e5f948c0c5dced67b4af23e7c69bda
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
15 * License.
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 * May 28, 2008.
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
23 * Contributor(s):
24 * Andreas Gal <gal@mozilla.com>
25 * Mike Shaver <shaver@mozilla.org>
26 * David Anderson <danderson@mozilla.com>
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.
40 * ***** END LICENSE BLOCK ***** */
42 #ifndef jstracer_h___
43 #define jstracer_h___
45 #ifdef JS_TRACER
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"
58 namespace js {
60 template <typename T>
61 class Queue {
62 T* _data;
63 unsigned _len;
64 unsigned _max;
65 nanojit::Allocator* alloc;
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));
81 #if defined(DEBUG)
82 memset(&_data[_len], 0xcd, _max - _len);
83 #endif
86 Queue(nanojit::Allocator* alloc)
87 : alloc(alloc)
89 this->_max =
90 this->_len = 0;
91 this->_data = NULL;
94 ~Queue() {
95 if (!alloc)
96 js_free(_data);
99 bool contains(T a) {
100 for (unsigned n = 0; n < _len; ++n) {
101 if (_data[n] == a)
102 return true;
104 return false;
107 void add(T a) {
108 ensure(_len + 1);
109 JS_ASSERT(_len <= _max);
110 _data[_len++] = a;
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;
120 void addUnique(T a) {
121 if (!contains(a))
122 add(a);
125 void setLength(unsigned len) {
126 ensure(len + 1);
127 _len = len;
130 void clear() {
131 _len = 0;
134 T & get(unsigned i) {
135 JS_ASSERT(i < length());
136 return _data[i];
139 const T & get(unsigned i) const {
140 JS_ASSERT(i < length());
141 return _data[i];
144 T & operator [](unsigned i) {
145 return get(i);
148 const T & operator [](unsigned i) const {
149 return get(i);
152 unsigned length() const {
153 return _len;
156 T* data() const {
157 return _data;
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;
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.
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:
187 * page = page in pagelist such that Base(address) == page->base,
188 * page->map[Offset(address)]
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)
195 struct TrackerPage {
196 struct TrackerPage* next;
197 jsuword base;
198 nanojit::LIns* map[TRACKER_PAGE_ENTRIES];
200 struct TrackerPage* pagelist;
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();
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();
216 class VMFragment : public nanojit::Fragment {
217 public:
218 VMFragment(const void* _ip verbose_only(, uint32_t profFragID))
219 : Fragment(_ip verbose_only(, profFragID))
223 * If this is anchored off a TreeFragment, this points to that tree fragment.
224 * Otherwise, it is |this|.
226 TreeFragment* root;
228 TreeFragment* toTreeFragment();
231 #ifdef NJ_NO_VARIADIC_MACROS
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
237 #elif defined(JS_JIT_SPEW)
239 // Top level logging controller object.
240 extern nanojit::LogControl LogController;
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*);
246 #define debug_only_stmt(stmt) \
247 stmt
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); \
255 JS_END_MACRO
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); \
263 JS_END_MACRO
265 #else
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
271 #endif
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.
280 #define ORACLE_SIZE 4096
282 class Oracle {
283 avmplus::BitSet _stackDontDemote;
284 avmplus::BitSet _globalDontDemote;
285 avmplus::BitSet _pcDontDemote;
286 avmplus::BitSet _pcSlowZeroTest;
287 public:
288 Oracle();
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;
301 void clearDemotability();
302 void clear() {
303 clearDemotability();
307 typedef Queue<uint16> SlotList;
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)
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);
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)
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
371 struct FrameInfo;
373 struct VMSideExit : public nanojit::SideExit
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;
387 inline JSValueType* stackTypeMap() {
388 return (JSValueType*)(this + 1);
391 inline JSValueType& stackType(unsigned i) {
392 JS_ASSERT(i < numStackSlots);
393 return stackTypeMap()[i];
396 inline JSValueType* globalTypeMap() {
397 return (JSValueType*)(this + 1) + this->numStackSlots;
400 inline JSValueType* fullTypeMap() {
401 return stackTypeMap();
404 inline VMFragment* fromFrag() {
405 return (VMFragment*)from;
408 inline TreeFragment* root() {
409 return fromFrag()->root;
413 class VMAllocator : public nanojit::Allocator
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))
422 ~VMAllocator() {
423 js_free(mReserve);
426 size_t size() {
427 return mSize;
430 bool outOfMemory() {
431 return mOutOfMemory;
434 struct Mark
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;
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)
452 ~Mark()
454 if (!committed)
455 vma.rewind(*this);
458 void commit() { committed = true; }
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;
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);
473 bool mOutOfMemory;
474 size_t mSize;
476 /* See nanojit::Allocator::allocChunk() for details on these. */
477 char* mReserve;
478 uintptr_t mReserveCurr;
479 uintptr_t mReserveLimit;
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
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.
493 uint32 argc;
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).
502 uint32 callerHeight;
504 /* argc of the caller */
505 uint32 callerArgc;
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);
512 uint16 get_argc() const { return uint16(argc & ~CONSTRUCTING_FLAG); }
513 bool is_constructing() const { return (argc & CONSTRUCTING_FLAG) != 0; }
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); }
520 struct UnstableExit
522 VMFragment* fragment;
523 VMSideExit* exit;
524 UnstableExit* next;
527 struct LinkableFragment : public VMFragment
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)
534 uint32 branchCount;
535 TypeMap typeMap;
536 unsigned nStackTypes;
537 unsigned spOffsetAtEntry;
538 SlotList* globalSlots;
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.
550 struct TreeFragment : public LinkableFragment
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)
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;
597 inline unsigned nGlobalTypes() {
598 return typeMap.length() - nStackTypes;
600 inline JSValueType* globalTypeMap() {
601 return typeMap.data() + nStackTypes;
603 inline JSValueType* stackTypeMap() {
604 return typeMap.data();
607 JS_REQUIRES_STACK void initialize(JSContext* cx, SlotList *globalSlots, bool speculate);
608 UnstableExit* removeUnstableExit(VMSideExit* exit);
611 inline TreeFragment*
612 VMFragment::toTreeFragment()
614 JS_ASSERT(root == this);
615 return static_cast<TreeFragment*>(this);
618 enum MonitorResult {
619 MONITOR_RECORDING,
620 MONITOR_NOT_RECORDING,
621 MONITOR_ERROR
624 const uintN PROFILE_MAX_INNER_LOOPS = 8;
625 const uintN PROFILE_MAX_STACK = 6;
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.
631 class LoopProfile
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
650 /* The TraceMonitor for which we're profiling. */
651 TraceMonitor *traceMonitor;
653 /* The script in which the loop header lives. */
654 JSScript *entryScript;
656 /* The stack frame where we started profiling. Only valid while profiling! */
657 JSStackFrame *entryfp;
659 /* The bytecode locations of the loop header and the back edge. */
660 jsbytecode *top, *bottom;
662 /* Number of times we have seen this loop executed; used to decide when to profile. */
663 uintN hits;
665 /* Whether we have run a complete profile of the loop. */
666 bool profiled;
668 /* Sometimes we can't decide in one profile run whether to trace, so we set undecided. */
669 bool undecided;
671 /* If we have profiled the loop, this saves the decision of whether to trace it. */
672 bool traceOK;
674 /* Memoized value of isCompilationUnprofitable. */
675 bool unprofitable;
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.
683 bool execOK;
685 /* Instruction mix for the loop and total number of instructions. */
686 uintN allOps[OP_LIMIT];
687 uintN numAllOps;
689 /* Instruction mix and total for the loop, excluding nested inner loops. */
690 uintN selfOps[OP_LIMIT];
691 uintN numSelfOps;
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.
699 double numSelfOpsMult;
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).
707 double branchMultiplier;
709 /* Set to true if the loop is short (i.e., has fewer than 8 iterations). */
710 bool shortLoop;
712 /* Set to true if the loop may be short (has few iterations at profiling time). */
713 bool maybeShortLoop;
716 * When we hit a nested loop while profiling, we record where it occurs
717 * and how many iterations we execute it.
719 struct InnerLoop {
720 JSStackFrame *entryfp;
721 jsbytecode *top, *bottom;
722 uintN iters;
724 InnerLoop() {}
725 InnerLoop(JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom)
726 : entryfp(entryfp), top(top), bottom(bottom), iters(0) {}
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;
734 * These two variables track the loops that we are currently nested
735 * inside while profiling. Loops get popped off here when they exit.
737 InnerLoop loopStack[PROFILE_MAX_INNER_LOOPS];
738 uintN loopStackDepth;
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().
745 struct StackValue {
746 bool isConst;
747 bool hasValue;
748 int value;
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) {}
754 StackValue stack[PROFILE_MAX_STACK];
755 uintN sp;
757 inline void stackClear() { sp = 0; }
759 inline void stackPush(const StackValue &v) {
760 if (sp < PROFILE_MAX_STACK)
761 stack[sp++] = v;
762 else
763 stackClear();
766 inline void stackPop() { if (sp > 0) sp--; }
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);
776 LoopProfile(TraceMonitor *tm, JSStackFrame *entryfp, jsbytecode *top, jsbytecode *bottom);
778 void reset();
780 enum ProfileAction {
781 ProfContinue,
782 ProfComplete
785 /* These two functions track the instruction mix. */
786 inline void increment(OpKind kind)
788 allOps[kind]++;
789 if (loopStackDepth == 0)
790 selfOps[kind]++;
793 inline uintN count(OpKind kind) { return allOps[kind]; }
795 /* Called for every back edge being profiled. */
796 MonitorResult profileLoopEdge(JSContext* cx, uintN& inlineCallCount);
798 /* Called for every instruction being profiled. */
799 ProfileAction profileOperation(JSContext *cx, JSOp op);
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);
806 void stopProfiling(JSContext *cx);
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.
814 typedef enum BuiltinStatus {
815 BUILTIN_BAILED = 1,
816 BUILTIN_ERROR = 2
817 } BuiltinStatus;
819 static JS_INLINE void
820 SetBuiltinError(TraceMonitor *tm)
822 tm->tracerState->builtinStatus |= BUILTIN_ERROR;
825 static JS_INLINE bool
826 WasBuiltinSuccessful(TraceMonitor *tm)
828 return tm->tracerState->builtinStatus == 0;
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; };
838 enum RecordingStatusCodes {
839 RECORD_ERROR_code = 0,
840 RECORD_STOP_code = 1,
842 RECORD_CONTINUE_code = 3,
843 RECORD_IMACRO_code = 4
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 };
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; };
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
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 };
872 static inline AbortableRecordingStatus
873 InjectStatus(RecordingStatus rs)
875 AbortableRecordingStatus ars = { rs.code };
876 return ars;
878 static inline AbortableRecordingStatus
879 InjectStatus(AbortableRecordingStatus ars)
881 return ars;
884 static inline bool
885 StatusAbortsRecorderIfActive(AbortableRecordingStatus ars)
887 return ars == ARECORD_ERROR || ars == ARECORD_STOP;
889 #else
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.
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.
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.
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
935 static JS_ALWAYS_INLINE AbortableRecordingStatus
936 InjectStatus(RecordingStatus rs)
938 return static_cast<AbortableRecordingStatus>(rs);
941 static JS_ALWAYS_INLINE AbortableRecordingStatus
942 InjectStatus(AbortableRecordingStatus ars)
944 return ars;
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'.
953 static JS_ALWAYS_INLINE bool
954 StatusAbortsRecorderIfActive(AbortableRecordingStatus ars)
956 return ars <= ARECORD_ERROR;
958 #endif
960 class SlotMap;
961 class SlurpInfo;
963 /* Results of trying to compare two typemaps together */
964 enum TypeConsensus
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 */
971 enum TracePointAction {
972 TPA_Nothing,
973 TPA_RanStuff,
974 TPA_Recorded,
975 TPA_Error
978 typedef HashMap<nanojit::LIns*, JSObject*> GuardedShapeTable;
980 #ifdef DEBUG
981 # define AbortRecording(cx, reason) AbortRecordingImpl(cx, reason)
982 #else
983 # define AbortRecording(cx, reason) AbortRecordingImpl(cx)
984 #endif
986 void
987 AbortProfiling(JSContext *cx);
989 class TraceRecorder
991 /*************************************************************** Recording session constants */
993 /* The context in which recording started. */
994 JSContext* const cx;
996 /* Cached value of JS_TRACE_MONITOR(cx). */
997 TraceMonitor* const traceMonitor;
999 /* Cached oracle keeps track of hit counts for program counter locations */
1000 Oracle* oracle;
1002 /* The Fragment being recorded by this recording session. */
1003 VMFragment* const fragment;
1005 /* The root fragment representing the tree. */
1006 TreeFragment* const tree;
1008 /* The global object from the start of recording until now. */
1009 JSObject* const globalObj;
1011 /* If non-null, the script of outer loop aborted to start recording this loop. */
1012 JSScript* const outerScript;
1014 /* If non-null, the pc of the outer loop aborted to start recording this loop. */
1015 jsbytecode* const outerPC;
1017 /* If |outerPC|, the argc to use when looking up |outerPC| in the fragments table. */
1018 uint32 const outerArgc;
1020 /* If non-null, the side exit from which we are growing. */
1021 VMSideExit* const anchor;
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;
1029 /* Lazy slot import state. */
1030 unsigned importStackSlots;
1031 unsigned importGlobalSlots;
1032 TypeMap importTypeMap;
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.
1038 nanojit::LirBuffer* const lirbuf;
1041 * Remembers traceAlloc state before recording started; automatically rewinds when mark is
1042 * destroyed on a failed compilation.
1044 VMAllocator::Mark mark;
1046 /* Remembers the number of sideExits in treeInfo before recording started. */
1047 const unsigned numSideExitsBefore;
1049 /*********************************************************** Recording session mutable state */
1051 /* Maps interpreter stack values to the instruction generating that value. */
1052 Tracker tracker;
1054 /* Maps interpreter stack values to the instruction writing back to the native stack. */
1055 Tracker nativeFrameTracker;
1057 /* The start of the global object's slots we assume for the trackers. */
1058 Value* global_slots;
1060 /* The number of interpreted calls entered (and not yet left) since recording began. */
1061 unsigned callDepth;
1063 /* The current atom table, mirroring the interpreter loop's variable of the same name. */
1064 JSAtom** atoms;
1065 Value* consts;
1067 /* An instruction yielding the current script's strict mode code flag. */
1068 nanojit::LIns* strictModeCode_ins;
1070 /* FIXME: Dead, but soon to be used for something or other. */
1071 Queue<jsbytecode*> cfgMerges;
1073 /* Indicates whether the current tree should be trashed when the recording session ends. */
1074 bool trashSelf;
1076 /* A list of trees to trash at the end of the recording session. */
1077 Queue<TreeFragment*> whichTreesToTrash;
1079 /* The set of objects whose shapes already have been guarded. */
1080 GuardedShapeTable guardedShapeTable;
1082 /* Current initializer depth, and whether any of the initializers are unoptimized NEWINIT. */
1083 int initDepth;
1084 bool hadNewInit;
1086 #ifdef DEBUG
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.
1091 const js::Shape* addPropShapeBefore;
1092 #endif
1094 /***************************************** Temporal state hoisted into the recording session */
1096 /* Carry the return value from a STOP/RETURN to the subsequent record_LeaveFrame. */
1097 nanojit::LIns* rval_ins;
1099 /* Carry the return value from a native call to the record_NativeCallComplete. */
1100 nanojit::LIns* native_rval_ins;
1102 /* Carry the return value of js_CreateThis to record_NativeCallComplete. */
1103 nanojit::LIns* newobj_ins;
1105 /* Carry the JSSpecializedNative used to generate a call to record_NativeCallComplete. */
1106 JSSpecializedNative* pendingSpecializedNative;
1108 /* Carry whether this is a jsval on the native stack from finishGetProp to monitorRecording. */
1109 Value* pendingUnboxSlot;
1111 /* Carry a guard condition to the beginning of the next monitorRecording. */
1112 nanojit::LIns* pendingGuardCondition;
1114 /* See AbortRecordingIfUnexpectedGlobalWrite. */
1115 js::Vector<unsigned> pendingGlobalSlotsToSet;
1117 /* Carry whether we have an always-exit from emitIf to checkTraceEnd. */
1118 bool pendingLoop;
1120 /* Temporary JSSpecializedNative used to describe non-specialized fast natives. */
1121 JSSpecializedNative generatedSpecializedNative;
1123 /* Temporary JSValueType array used to construct temporary typemaps. */
1124 js::Vector<JSValueType, 256> tempTypeMap;
1126 /* Used to generate LIR. Has a short name because it's used a lot. */
1127 tjit::Writer w;
1129 /************************************************************* 10 bajillion member functions */
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.").
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);
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)
1150 * Examines current interpreter state to record information suitable for returning to the
1151 * interpreter through a side exit of the given type.
1153 JS_REQUIRES_STACK VMSideExit* snapshot(ExitType exitType);
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.
1159 JS_REQUIRES_STACK VMSideExit* copy(VMSideExit* exit);
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.
1166 JS_REQUIRES_STACK nanojit::GuardRecord* createGuardRecord(VMSideExit* exit);
1168 JS_REQUIRES_STACK JS_INLINE void markSlotUndemotable(LinkableFragment* f, unsigned slot);
1170 JS_REQUIRES_STACK JS_INLINE void markSlotUndemotable(LinkableFragment* f, unsigned slot, const void* pc);
1172 JS_REQUIRES_STACK unsigned findUndemotesInTypemaps(const TypeMap& typeMap, LinkableFragment* f,
1173 Queue<unsigned>& undemotes);
1175 JS_REQUIRES_STACK void assertDownFrameIsConsistent(VMSideExit* anchor, FrameInfo* fi);
1177 JS_REQUIRES_STACK void captureStackTypes(unsigned callDepth, JSValueType* typeMap);
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);
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);
1201 void ensureCond(nanojit::LIns** ins, bool* cond);
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);
1210 nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset,
1211 bool shouldDemoteToInt32);
1213 #ifdef DEBUG
1214 bool isValidFrameObjPtr(void *obj);
1215 #endif
1216 void assertInsideLoop();
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);
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);
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.
1238 JS_REQUIRES_STACK void checkForGlobalObjectReallocation() {
1239 if (global_slots != globalObj->getSlots())
1240 checkForGlobalObjectReallocationHelper();
1242 JS_REQUIRES_STACK void checkForGlobalObjectReallocationHelper();
1244 JS_REQUIRES_STACK TypeConsensus selfTypeStability(SlotMap& smap);
1245 JS_REQUIRES_STACK TypeConsensus peerTypeStability(SlotMap& smap, const void* ip,
1246 TreeFragment** peer);
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;
1252 JS_REQUIRES_STACK void updateAtoms();
1253 JS_REQUIRES_STACK void updateAtoms(JSScript *script);
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
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);
1272 JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr);
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);
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);
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);
1293 JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins, bool strict);
1295 JS_REQUIRES_STACK bool canCallImacro() const;
1296 JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
1297 JS_REQUIRES_STACK RecordingStatus callImacroInfallibly(jsbytecode* imacro);
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);
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);
1324 JS_REQUIRES_STACK RecordingStatus unary(nanojit::LOpcode op);
1325 JS_REQUIRES_STACK RecordingStatus binary(nanojit::LOpcode op);
1327 JS_REQUIRES_STACK RecordingStatus guardShape(nanojit::LIns* obj_ins, JSObject* obj,
1328 uint32 shape, const char* name, VMSideExit* exit);
1330 #if defined DEBUG_notme && defined XP_UNIX
1331 void dumpGuardedShapes(const char* prefix);
1332 #endif
1334 void forgetGuardedShapes();
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);
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);
1351 nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot,
1352 VMSideExit *exit);
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);
1373 JS_REQUIRES_STACK void storeMagic(JSWhyMagic why, tjit::Address addr);
1374 JS_REQUIRES_STACK AbortableRecordingStatus unboxNextValue(nanojit::LIns* &v_ins);
1376 JS_REQUIRES_STACK VMSideExit* enterDeepBailCall();
1377 JS_REQUIRES_STACK void leaveDeepBailCall();
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);
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);
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);
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);
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
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);
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);
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);
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.
1464 nanojit::LIns* box_value_for_native_call(const Value& v, nanojit::LIns* v_ins);
1466 /* Box a slot into insAlloc'd memory. */
1467 nanojit::LIns* box_value_into_alloc(const Value& v, nanojit::LIns* v_ins);
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 void 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);
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);
1523 AbortableRecordingStatus hasMethod(JSObject* obj, jsid id, bool& found);
1524 JS_REQUIRES_STACK AbortableRecordingStatus hasIteratorMethod(JSObject* obj, bool& found);
1526 JS_REQUIRES_STACK jsatomid getFullIndex(ptrdiff_t pcoff = 0);
1528 JS_REQUIRES_STACK JSValueType determineSlotType(Value* vp);
1530 JS_REQUIRES_STACK RecordingStatus setUpwardTrackedVar(Value* stackVp, const Value& v,
1531 nanojit::LIns* v_ins);
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);
1547 static JS_REQUIRES_STACK MonitorResult recordLoopEdge(JSContext* cx, TraceRecorder* r,
1548 uintN& inlineCallCount);
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; }
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
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);
1567 /* The destructor should only be called through finish*, not directly. */
1568 ~TraceRecorder();
1569 JS_REQUIRES_STACK AbortableRecordingStatus finishSuccessfully();
1571 enum AbortResult { NORMAL_ABORT, JIT_RESET };
1572 JS_REQUIRES_STACK AbortResult finishAbort(const char* reason);
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);
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);
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; }
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);
1617 bool globalSetExpected(unsigned slot) {
1618 unsigned *pi = Find(pendingGlobalSlotsToSet, slot);
1619 if (pi == pendingGlobalSlotsToSet.end()) {
1621 * Do slot arithmetic manually to avoid getSlotRef assertions which
1622 * do not need to be satisfied for this purpose.
1624 Value *vp = globalObj->getSlots() + slot;
1626 /* If this global is definitely being tracked, then the write is unexpected. */
1627 if (tracker.has(vp))
1628 return false;
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.
1637 return tree->globalSlots->offsetOf((uint16)nativeGlobalSlot(vp)) == -1;
1639 pendingGlobalSlotsToSet.erase(pi);
1640 return true;
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
1665 #define TRACING_ENABLED(cx) ((cx)->traceJitEnabled)
1666 #define REGEX_JIT_ENABLED(cx) ((cx)->traceJitEnabled || (cx)->methodJitEnabled)
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)
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); \
1682 if (status == ARECORD_ERROR) \
1683 goto error; \
1685 JS_ASSERT(status != ARECORD_IMACRO); \
1687 JS_END_MACRO
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))
1694 extern JS_REQUIRES_STACK MonitorResult
1695 MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount, JSInterpMode interpMode);
1697 extern JS_REQUIRES_STACK TracePointAction
1698 RecordTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist);
1700 extern JS_REQUIRES_STACK TracePointAction
1701 MonitorTracePoint(JSContext*, uintN& inlineCallCount, bool* blacklist,
1702 void** traceData, uintN *traceEpoch, uint32 *loopCounter, uint32 hits);
1704 extern JS_REQUIRES_STACK TraceRecorder::AbortResult
1705 AbortRecording(JSContext* cx, const char* reason);
1707 extern bool
1708 InitJIT(TraceMonitor *tm);
1710 extern void
1711 FinishJIT(TraceMonitor *tm);
1713 extern void
1714 PurgeScriptFragments(TraceMonitor* tm, JSScript* script);
1716 extern bool
1717 OverfullJITCache(JSContext *cx, TraceMonitor* tm);
1719 extern void
1720 FlushJITCache(JSContext* cx, TraceMonitor* tm);
1722 extern JSObject *
1723 GetBuiltinFunction(JSContext *cx, uintN index);
1725 extern void
1726 SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes);
1728 extern void
1729 ExternNativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot);
1731 #ifdef MOZ_TRACEVIS
1733 extern JS_FRIEND_API(bool)
1734 StartTraceVis(const char* filename);
1736 extern JS_FRIEND_API(JSBool)
1737 StartTraceVisNative(JSContext *cx, uintN argc, jsval *vp);
1739 extern JS_FRIEND_API(bool)
1740 StopTraceVis();
1742 extern JS_FRIEND_API(JSBool)
1743 StopTraceVisNative(JSContext *cx, uintN argc, jsval *vp);
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
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
1789 enum TraceVisFlushReason {
1790 FR_DEEP_BAIL,
1791 FR_OOM,
1792 FR_GLOBAL_SHAPE_MISMATCH,
1793 FR_GLOBALS_FULL
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);
1800 extern FILE* traceVisLogFile;
1801 extern JSHashTable *traceVisScriptTable;
1803 extern JS_FRIEND_API(void)
1804 StoreTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r);
1806 static inline void
1807 LogTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
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);
1815 if (traceVisScriptTable) {
1816 StoreTraceVisState(cx, s, r);
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.
1825 static inline void
1826 LogTraceVisEvent(JSContext *cx, TraceVisState s, TraceVisFlushReason r)
1828 LogTraceVisState(cx, s, (TraceVisExitReason) r);
1831 static inline void
1832 EnterTraceVisState(JSContext *cx, TraceVisState s, TraceVisExitReason r)
1834 LogTraceVisState(cx, s, r);
1837 static inline void
1838 ExitTraceVisState(JSContext *cx, TraceVisExitReason r)
1840 LogTraceVisState(cx, S_EXITLAST, r);
1843 struct TraceVisStateObj {
1844 TraceVisExitReason r;
1845 JSContext *mCx;
1847 inline TraceVisStateObj(JSContext *cx, TraceVisState s) : r(R_NONE)
1849 EnterTraceVisState(cx, s, R_NONE);
1850 mCx = cx;
1852 inline ~TraceVisStateObj()
1854 ExitTraceVisState(mCx, r);
1858 #endif /* MOZ_TRACEVIS */
1860 } /* namespace js */
1862 #else /* !JS_TRACER */
1864 #define TRACE_0(x) ((void)0)
1865 #define TRACE_1(x,a) ((void)0)
1866 #define TRACE_2(x,a,b) ((void)0)
1868 #endif /* !JS_TRACER */
1870 namespace js {
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.
1882 static JS_INLINE void
1883 AbortRecordingIfUnexpectedGlobalWrite(JSContext *cx, JSObject *obj, unsigned slot)
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");
1890 #endif
1893 } /* namespace js */
1895 #endif /* jstracer_h___ */