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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
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 ***** */
52 #include "jsbuiltins.h"
55 class Queue
: public GCObject
{
60 void ensure(unsigned size
) {
63 _data
= (T
*)realloc(_data
, _max
* sizeof(T
));
66 Queue(unsigned max
= 16) {
69 this->_data
= (T
*)malloc(max
* sizeof(T
));
77 for (unsigned n
= 0; n
< _len
; ++n
)
85 JS_ASSERT(_len
<= _max
);
89 void add(T
* chunk
, unsigned size
) {
91 JS_ASSERT(_len
<= _max
);
92 memcpy(&_data
[_len
], chunk
, size
* sizeof(T
));
101 void setLength(unsigned len
) {
110 unsigned length() const {
120 * Tracker is used to keep track of values being manipulated by the interpreter
121 * during trace recording.
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
);
138 bool has(const void* v
) const;
139 nanojit::LIns
* get(const void* v
) const;
140 void set(const void* v
, nanojit::LIns
* ins
);
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
153 avmplus::BitSet _dontDemote
;
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;
162 typedef Queue
<uint16
> SlotList
;
164 class TypeMap
: public Queue
<uint8
> {
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
;
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
;
189 JSObject
* callee
; // callee function object
190 jsbytecode
* callpc
; // pc of JSOP_CALL in caller script
191 uint8
* typemap
; // typemap for the stack frame
194 uint16 spdist
; // distance from fp->slots to fp->regs->sp at JSOP_CALL
195 uint16 argc
; // actual argument count, may be < fun->nargs
197 uint32 word
; // for spdist/argc LIR store in record_JSOP_CALL
201 class TraceRecorder
: public GCObject
{
203 JSTraceMonitor
* traceMonitor
;
206 Tracker nativeFrameTracker
;
210 nanojit::GuardRecord
* anchor
;
211 nanojit::Fragment
* fragment
;
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
;
221 nanojit::LirWriter
* float_filter
;
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
;
231 bool applyingArguments
;
233 nanojit::Fragment
* whichTreeToTrash
;
234 Queue
<jsbytecode
*> cfgMerges
;
235 jsval
* global_dslots
;
236 JSTraceableNative
* pendingTraceableNative
;
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
);
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
,
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
);
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
);
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) \
371 # include "jsopcode.tbl"
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) \
382 TraceRecorder* tr_ = TRACE_RECORDER(cx); \
383 if (!js_MonitorRecording(tr_)) \
386 TRACE_ARGS_(tr_,x,args); \
389 #define TRACE_ARGS_(tr,x,args) \
391 if (!tr->record_##x args) { \
392 js_AbortRecording(cx, #x); \
397 #define TRACE_ARGS(x,args) \
399 TraceRecorder* tr_ = TRACE_RECORDER(cx); \
401 TRACE_ARGS_(tr_, x, args); \
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))
410 js_MonitorLoopEdge(JSContext
* cx
, uintN
& inlineCallCount
);
413 js_MonitorRecording(TraceRecorder
*tr
);
416 js_AbortRecording(JSContext
* cx
, const char* reason
);
419 js_InitJIT(JSTraceMonitor
*tm
);
422 js_FinishJIT(JSTraceMonitor
*tm
);
425 js_FlushJITCache(JSContext
* cx
);
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___ */