Bug 449522 - Context menu for HTML5 <video> elements. r=gavin, ui-r=boriss
[wine-gecko.git] / js / src / jstracer.h
blob0692cc24775076134fb8b070ce86f68aaa2932f7
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 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 "jsstddef.h"
48 #include "jstypes.h"
49 #include "jslock.h"
50 #include "jsnum.h"
51 #include "jsinterp.h"
52 #include "jsbuiltins.h"
54 template <typename T>
55 class Queue : public GCObject {
56 T* _data;
57 unsigned _len;
58 unsigned _max;
60 void ensure(unsigned size) {
61 while (_max < size)
62 _max <<= 1;
63 _data = (T*)realloc(_data, _max * sizeof(T));
65 public:
66 Queue(unsigned max = 16) {
67 this->_max = max;
68 this->_len = 0;
69 this->_data = (T*)malloc(max * sizeof(T));
72 ~Queue() {
73 free(_data);
76 bool contains(T a) {
77 for (unsigned n = 0; n < _len; ++n)
78 if (_data[n] == a)
79 return true;
80 return false;
83 void add(T a) {
84 ensure(_len + 1);
85 JS_ASSERT(_len <= _max);
86 _data[_len++] = a;
89 void add(T* chunk, unsigned size) {
90 ensure(_len + size);
91 JS_ASSERT(_len <= _max);
92 memcpy(&_data[_len], chunk, size * sizeof(T));
93 _len += size;
96 void addUnique(T a) {
97 if (!contains(a))
98 add(a);
101 void setLength(unsigned len) {
102 ensure(len + 1);
103 _len = len;
106 void clear() {
107 _len = 0;
110 unsigned length() const {
111 return _len;
114 T* data() const {
115 return _data;
120 * Tracker is used to keep track of values being manipulated by the interpreter
121 * during trace recording.
123 class Tracker {
124 struct Page {
125 struct Page* next;
126 jsuword base;
127 nanojit::LIns* map[1];
129 struct Page* pagelist;
131 jsuword getPageBase(const void* v) const;
132 struct Page* findPage(const void* v) const;
133 struct Page* addPage(const void* v);
134 public:
135 Tracker();
136 ~Tracker();
138 bool has(const void* v) const;
139 nanojit::LIns* get(const void* v) const;
140 void set(const void* v, nanojit::LIns* ins);
141 void clear();
145 * The oracle keeps track of slots that should not be demoted to int because we know them
146 * to overflow or they result in type-unstable traces. We are using a simple hash table.
147 * Collisions lead to loss of optimization (demotable slots are not demoted) but have no
148 * correctness implications.
150 #define ORACLE_SIZE 4096
152 class Oracle {
153 avmplus::BitSet _dontDemote;
154 public:
155 void markGlobalSlotUndemotable(JSScript* script, unsigned slot);
156 bool isGlobalSlotUndemotable(JSScript* script, unsigned slot) const;
157 void markStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot);
158 bool isStackSlotUndemotable(JSScript* script, jsbytecode* ip, unsigned slot) const;
159 void clear();
162 typedef Queue<uint16> SlotList;
164 class TypeMap : public Queue<uint8> {
165 public:
166 void captureGlobalTypes(JSContext* cx, SlotList& slots);
167 void captureStackTypes(JSContext* cx, unsigned callDepth);
168 bool matches(TypeMap& other) const;
171 class TreeInfo MMGC_SUBCLASS_DECL {
172 nanojit::Fragment* fragment;
173 public:
174 JSScript* script;
175 unsigned maxNativeStackSlots;
176 ptrdiff_t nativeStackBase;
177 unsigned maxCallDepth;
178 TypeMap stackTypeMap;
179 unsigned mismatchCount;
180 Queue<nanojit::Fragment*> dependentTrees;
181 unsigned branchCount;
183 TreeInfo(nanojit::Fragment* _fragment) {
184 fragment = _fragment;
188 struct FrameInfo {
189 JSObject* callee; // callee function object
190 jsbytecode* callpc; // pc of JSOP_CALL in caller script
191 uint8* typemap; // typemap for the stack frame
192 union {
193 struct {
194 uint16 spdist; // distance from fp->slots to fp->regs->sp at JSOP_CALL
195 uint16 argc; // actual argument count, may be < fun->nargs
196 } s;
197 uint32 word; // for spdist/argc LIR store in record_JSOP_CALL
201 class TraceRecorder : public GCObject {
202 JSContext* cx;
203 JSTraceMonitor* traceMonitor;
204 JSObject* globalObj;
205 Tracker tracker;
206 Tracker nativeFrameTracker;
207 char* entryTypeMap;
208 unsigned callDepth;
209 JSAtom** atoms;
210 nanojit::GuardRecord* anchor;
211 nanojit::Fragment* fragment;
212 TreeInfo* treeInfo;
213 nanojit::LirBuffer* lirbuf;
214 nanojit::LirWriter* lir;
215 nanojit::LirBufWriter* lir_buf_writer;
216 nanojit::LirWriter* verbose_filter;
217 nanojit::LirWriter* cse_filter;
218 nanojit::LirWriter* expr_filter;
219 nanojit::LirWriter* func_filter;
220 #ifdef NJ_SOFTFLOAT
221 nanojit::LirWriter* float_filter;
222 #endif
223 nanojit::LIns* cx_ins;
224 nanojit::LIns* gp_ins;
225 nanojit::LIns* eos_ins;
226 nanojit::LIns* eor_ins;
227 nanojit::LIns* rval_ins;
228 nanojit::LIns* inner_sp_ins;
229 nanojit::SideExit exit;
230 bool deepAborted;
231 bool applyingArguments;
232 bool trashTree;
233 nanojit::Fragment* whichTreeToTrash;
234 Queue<jsbytecode*> cfgMerges;
235 jsval* global_dslots;
236 JSTraceableNative* pendingTraceableNative;
237 bool terminate;
239 bool isGlobal(jsval* p) const;
240 ptrdiff_t nativeGlobalOffset(jsval* p) const;
241 ptrdiff_t nativeStackOffset(jsval* p) const;
242 void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, uint8& t,
243 const char *prefix, uintN index, JSStackFrame *fp);
244 void import(TreeInfo* treeInfo, nanojit::LIns* sp, unsigned ngslots, unsigned callDepth,
245 uint8* globalTypeMap, uint8* stackTypeMap);
246 void trackNativeStackUse(unsigned slots);
248 bool lazilyImportGlobalSlot(unsigned slot);
250 nanojit::LIns* guard(bool expected, nanojit::LIns* cond, nanojit::ExitType exitType);
251 nanojit::LIns* addName(nanojit::LIns* ins, const char* name);
253 nanojit::LIns* get(jsval* p) const;
254 nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset);
255 void set(jsval* p, nanojit::LIns* l, bool initializing = false);
257 bool checkType(jsval& v, uint8 type, bool& recompile);
258 bool verifyTypeStability();
260 jsval& argval(unsigned n) const;
261 jsval& varval(unsigned n) const;
262 jsval& stackval(int n) const;
264 nanojit::LIns* scopeChain() const;
265 bool activeCallOrGlobalSlot(JSObject* obj, jsval*& vp);
267 nanojit::LIns* arg(unsigned n);
268 void arg(unsigned n, nanojit::LIns* i);
269 nanojit::LIns* var(unsigned n);
270 void var(unsigned n, nanojit::LIns* i);
271 nanojit::LIns* stack(int n);
272 void stack(int n, nanojit::LIns* i);
274 nanojit::LIns* f2i(nanojit::LIns* f);
275 nanojit::LIns* makeNumberInt32(nanojit::LIns* f);
277 bool ifop();
278 bool switchop();
279 bool inc(jsval& v, jsint incr, bool pre = true);
280 bool inc(jsval& v, nanojit::LIns*& v_ins, jsint incr, bool pre = true);
281 bool incProp(jsint incr, bool pre = true);
282 bool incElem(jsint incr, bool pre = true);
283 bool incName(jsint incr, bool pre = true);
285 enum { CMP_NEGATE = 1, CMP_TRY_BRANCH_AFTER_COND = 2, CMP_CASE = 4, CMP_STRICT = 8 };
286 bool cmp(nanojit::LOpcode op, int flags = 0);
288 bool unary(nanojit::LOpcode op);
289 bool binary(nanojit::LOpcode op);
291 bool ibinary(nanojit::LOpcode op);
292 bool iunary(nanojit::LOpcode op);
293 bool bbinary(nanojit::LOpcode op);
294 void demote(jsval& v, jsdouble result);
296 bool map_is_native(JSObjectMap* map, nanojit::LIns* map_ins, nanojit::LIns*& ops_ins,
297 size_t op_offset = 0);
298 bool test_property_cache(JSObject* obj, nanojit::LIns* obj_ins, JSObject*& obj2,
299 jsuword& pcval);
300 bool test_property_cache_direct_slot(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot);
301 void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot,
302 nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
303 nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot);
304 nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot,
305 nanojit::LIns*& dslots_ins);
306 bool native_set(nanojit::LIns* obj_ins, JSScopeProperty* sprop,
307 nanojit::LIns*& dslots_ins, nanojit::LIns* v_ins);
308 bool native_get(nanojit::LIns* obj_ins, nanojit::LIns* pobj_ins, JSScopeProperty* sprop,
309 nanojit::LIns*& dslots_ins, nanojit::LIns*& v_ins);
311 bool name(jsval*& vp);
312 bool prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot, nanojit::LIns*& v_ins);
313 bool elem(jsval& oval, jsval& idx, jsval*& vp, nanojit::LIns*& v_ins, nanojit::LIns*& addr_ins);
315 bool getProp(JSObject* obj, nanojit::LIns* obj_ins);
316 bool getProp(jsval& v);
317 bool getThis(nanojit::LIns*& this_ins);
319 bool box_jsval(jsval v, nanojit::LIns*& v_ins);
320 bool unbox_jsval(jsval v, nanojit::LIns*& v_ins);
321 bool guardClass(JSObject* obj, nanojit::LIns* obj_ins, JSClass* clasp);
322 bool guardDenseArray(JSObject* obj, nanojit::LIns* obj_ins);
323 bool guardDenseArrayIndex(JSObject* obj, jsint idx, nanojit::LIns* obj_ins,
324 nanojit::LIns* dslots_ins, nanojit::LIns* idx_ins);
325 bool guardElemOp(JSObject* obj, nanojit::LIns* obj_ins, jsid id, size_t op_offset, jsval* vp);
326 void clearFrameSlotsFromCache();
327 bool guardShapelessCallee(jsval& callee);
328 bool interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing);
329 bool functionCall(bool constructing);
330 bool forInLoop(jsval* vp);
332 void trackCfgMerges(jsbytecode* pc);
333 void flipIf(jsbytecode* pc, bool& cond);
334 void fuseIf(jsbytecode* pc, bool cond, nanojit::LIns* x);
336 public:
337 friend bool js_MonitorRecording(TraceRecorder* tr);
339 TraceRecorder(JSContext* cx, nanojit::GuardRecord*, nanojit::Fragment*, TreeInfo*,
340 unsigned ngslots, uint8* globalTypeMap, uint8* stackTypeMap,
341 nanojit::GuardRecord* expectedInnerExit);
342 ~TraceRecorder();
344 uint8 determineSlotType(jsval* vp) const;
345 nanojit::SideExit* snapshot(nanojit::ExitType exitType);
346 nanojit::Fragment* getFragment() const { return fragment; }
347 bool isLoopHeader(JSContext* cx) const;
348 void compile(nanojit::Fragmento* fragmento);
349 void closeLoop(nanojit::Fragmento* fragmento);
350 void endLoop(nanojit::Fragmento* fragmento);
351 void blacklist() { fragment->blacklist(); }
352 bool adjustCallerTypes(nanojit::Fragment* f);
353 bool selectCallablePeerFragment(nanojit::Fragment** first);
354 void prepareTreeCall(nanojit::Fragment* inner);
355 void emitTreeCall(nanojit::Fragment* inner, nanojit::GuardRecord* lr);
356 unsigned getCallDepth() const;
358 bool record_EnterFrame();
359 bool record_LeaveFrame();
360 bool record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop);
361 bool record_SetPropMiss(JSPropCacheEntry* entry);
362 bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
363 bool record_FastNativeCallComplete();
365 void deepAbort() { deepAborted = true; }
366 bool wasDeepAborted() { return deepAborted; }
367 bool walkedOutOfLoop() { return terminate; }
369 #define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \
370 bool record_##op();
371 # include "jsopcode.tbl"
372 #undef OPDEF
375 #define TRACING_ENABLED(cx) JS_HAS_OPTION(cx, JSOPTION_JIT)
376 #define TRACE_RECORDER(cx) (JS_TRACE_MONITOR(cx).recorder)
377 #define SET_TRACE_RECORDER(cx,tr) (JS_TRACE_MONITOR(cx).recorder = (tr))
379 // See jsinterp.cpp for the ENABLE_TRACER definition.
380 #define RECORD_ARGS(x,args) \
381 JS_BEGIN_MACRO \
382 TraceRecorder* tr_ = TRACE_RECORDER(cx); \
383 if (!js_MonitorRecording(tr_)) \
384 ENABLE_TRACER(0); \
385 else \
386 TRACE_ARGS_(tr_,x,args); \
387 JS_END_MACRO
389 #define TRACE_ARGS_(tr,x,args) \
390 JS_BEGIN_MACRO \
391 if (!tr->record_##x args) { \
392 js_AbortRecording(cx, #x); \
393 ENABLE_TRACER(0); \
395 JS_END_MACRO
397 #define TRACE_ARGS(x,args) \
398 JS_BEGIN_MACRO \
399 TraceRecorder* tr_ = TRACE_RECORDER(cx); \
400 if (tr_) \
401 TRACE_ARGS_(tr_, x, args); \
402 JS_END_MACRO
404 #define RECORD(x) RECORD_ARGS(x, ())
405 #define TRACE_0(x) TRACE_ARGS(x, ())
406 #define TRACE_1(x,a) TRACE_ARGS(x, (a))
407 #define TRACE_2(x,a,b) TRACE_ARGS(x, (a, b))
409 extern bool
410 js_MonitorLoopEdge(JSContext* cx, uintN& inlineCallCount);
412 extern bool
413 js_MonitorRecording(TraceRecorder *tr);
415 extern void
416 js_AbortRecording(JSContext* cx, const char* reason);
418 extern void
419 js_InitJIT(JSTraceMonitor *tm);
421 extern void
422 js_FinishJIT(JSTraceMonitor *tm);
424 extern void
425 js_FlushJITCache(JSContext* cx);
427 extern void
428 js_FlushJITOracle(JSContext* cx);
430 #else /* !JS_TRACER */
432 #define RECORD(x) ((void)0)
433 #define TRACE_0(x) ((void)0)
434 #define TRACE_1(x,a) ((void)0)
435 #define TRACE_2(x,a,b) ((void)0)
437 #endif /* !JS_TRACER */
439 #endif /* jstracer_h___ */