Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / methodjit / MethodJIT.h
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=4 sw=4 et tw=99:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18  * May 28, 2008.
19  *
20  * The Initial Developer of the Original Code is
21  *   Brendan Eich <brendan@mozilla.org>
22  *
23  * Contributor(s):
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the MPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the MPL, the GPL or the LGPL.
36  *
37  * ***** END LICENSE BLOCK ***** */
38
39 #if !defined jsjaeger_h__ && defined JS_METHODJIT
40 #define jsjaeger_h__
41
42 #include "jscntxt.h"
43
44 #include "assembler/assembler/MacroAssemblerCodeRef.h"
45
46 #if !defined JS_CPU_X64 && \
47     !defined JS_CPU_X86 && \
48     !defined JS_CPU_ARM
49 # error "Oh no, you should define a platform so this compiles."
50 #endif
51
52 #if !defined(JS_NUNBOX32) && !defined(JS_PUNBOX64)
53 # error "No boxing format selected."
54 #endif
55
56 namespace js {
57
58 namespace mjit { struct JITScript; }
59
60 struct VMFrame
61 {
62     union Arguments {
63         struct {
64             void *ptr;
65             void *ptr2;
66             void *ptr3;
67         } x;
68         struct {
69             uint32 lazyArgsObj;
70             uint32 dynamicArgc;
71         } call;
72     } u;
73
74     VMFrame      *previous;
75     void         *unused;
76     JSFrameRegs  regs;
77     JSContext    *cx;
78     Value        *stackLimit;
79     JSStackFrame *entryfp;
80
81 #if defined(JS_CPU_X86)
82     void *savedEBX;
83     void *savedEDI;
84     void *savedESI;
85     void *savedEBP;
86     void *savedEIP;
87
88 # ifdef JS_NO_FASTCALL
89     inline void** returnAddressLocation() {
90         return reinterpret_cast<void**>(this) - 5;
91     }
92 # else
93     inline void** returnAddressLocation() {
94         return reinterpret_cast<void**>(this) - 1;
95     }
96 # endif
97 #elif defined(JS_CPU_X64)
98     void *savedRBX;
99 # ifdef _WIN64
100     void *savedRSI;
101     void *savedRDI;
102 # endif
103     void *savedR15;
104     void *savedR14;
105     void *savedR13;
106     void *savedR12;
107     void *savedRBP;
108     void *savedRIP;
109
110 # ifdef _WIN64
111     inline void** returnAddressLocation() {
112         return reinterpret_cast<void**>(this) - 5;
113     }
114 # else
115     inline void** returnAddressLocation() {
116         return reinterpret_cast<void**>(this) - 1;
117     }
118 # endif
119
120 #elif defined(JS_CPU_ARM)
121     void *savedR4;
122     void *savedR5;
123     void *savedR6;
124     void *savedR7;
125     void *savedR8;
126     void *savedR9;
127     void *savedR10;
128     void *savedR11;
129     void *savedLR;
130
131     inline void** returnAddressLocation() {
132         return reinterpret_cast<void**>(this) - 1;
133     }
134 #else
135 # error "The VMFrame layout isn't defined for your processor architecture!"
136 #endif
137
138     JSRuntime *runtime() { return cx->runtime; }
139
140     JSStackFrame *&fp() { return regs.fp; }
141     mjit::JITScript *jit() { return fp()->jit(); }
142 };
143
144 #ifdef JS_CPU_ARM
145 // WARNING: Do not call this function directly from C(++) code because it is not ABI-compliant.
146 extern "C" void JaegerStubVeneer(void);
147 #endif
148
149 namespace mjit {
150
151 /*
152  * Trampolines to force returns from jit code.
153  * See also TrampolineCompiler::generateForceReturn(Fast).
154  */
155 struct Trampolines {
156     typedef void (*TrampolinePtr)();
157
158     TrampolinePtr       forceReturn;
159     JSC::ExecutablePool *forceReturnPool;
160
161 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
162     TrampolinePtr       forceReturnFast;
163     JSC::ExecutablePool *forceReturnFastPool;
164 #endif
165 };
166
167 /*
168  * Method JIT compartment data. Currently, there is exactly one per
169  * JS compartment. It would be safe for multiple JS compartments to
170  * share a JaegerCompartment as long as only one thread can enter
171  * the JaegerCompartment at a time.
172  */
173 class JaegerCompartment {
174     JSC::ExecutableAllocator *execAlloc;     // allocator for jit code
175     Trampolines              trampolines;    // force-return trampolines
176     VMFrame                  *activeFrame_;  // current active VMFrame
177
178     void Finish();
179
180   public:
181     bool Initialize();
182
183     ~JaegerCompartment() { Finish(); }
184
185     JSC::ExecutablePool *poolForSize(size_t size) {
186         return execAlloc->poolForSize(size);
187     }
188
189     VMFrame *activeFrame() {
190         return activeFrame_;
191     }
192
193     void pushActiveFrame(VMFrame *f) {
194         f->previous = activeFrame_;
195         activeFrame_ = f;
196     }
197
198     void popActiveFrame() {
199         JS_ASSERT(activeFrame_);
200         activeFrame_ = activeFrame_->previous;
201     }
202
203     Trampolines::TrampolinePtr forceReturnTrampoline() const {
204         return trampolines.forceReturn;
205     }
206
207 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
208     Trampolines::TrampolinePtr forceReturnFastTrampoline() const {
209         return trampolines.forceReturnFast;
210     }
211 #endif
212 };
213
214 /*
215  * Allocation policy for compiler jstl objects. The goal is to free the
216  * compiler from having to check and propagate OOM after every time we
217  * append to a vector. We do this by reporting OOM to the engine and
218  * setting a flag on the compiler when OOM occurs. The compiler is required
219  * to check for OOM only before trying to use the contents of the list.
220  */
221 class CompilerAllocPolicy : public ContextAllocPolicy
222 {
223     bool *oomFlag;
224
225     void *checkAlloc(void *p) {
226         if (!p)
227             *oomFlag = true;
228         return p;
229     }
230
231   public:
232     CompilerAllocPolicy(JSContext *cx, bool *oomFlag)
233     : ContextAllocPolicy(cx), oomFlag(oomFlag) {}
234     CompilerAllocPolicy(JSContext *cx, Compiler &compiler);
235
236     void *malloc(size_t bytes) { return checkAlloc(ContextAllocPolicy::malloc(bytes)); }
237     void *realloc(void *p, size_t bytes) {
238         return checkAlloc(ContextAllocPolicy::realloc(p, bytes));
239     }
240 };
241
242 namespace ic {
243 # if defined JS_POLYIC
244     struct PICInfo;
245     struct GetElementIC;
246     struct SetElementIC;
247 # endif
248 # if defined JS_MONOIC
249     struct GetGlobalNameIC;
250     struct SetGlobalNameIC;
251     struct EqualityICInfo;
252     struct TraceICInfo;
253     struct CallICInfo;
254 # endif
255 }
256 }
257
258 typedef void (JS_FASTCALL *VoidStub)(VMFrame &);
259 typedef void (JS_FASTCALL *VoidVpStub)(VMFrame &, Value *);
260 typedef void (JS_FASTCALL *VoidStubUInt32)(VMFrame &, uint32);
261 typedef void (JS_FASTCALL *VoidStubInt32)(VMFrame &, int32);
262 typedef JSBool (JS_FASTCALL *BoolStub)(VMFrame &);
263 typedef void * (JS_FASTCALL *VoidPtrStub)(VMFrame &);
264 typedef void * (JS_FASTCALL *VoidPtrStubPC)(VMFrame &, jsbytecode *);
265 typedef void * (JS_FASTCALL *VoidPtrStubUInt32)(VMFrame &, uint32);
266 typedef JSObject * (JS_FASTCALL *JSObjStub)(VMFrame &);
267 typedef JSObject * (JS_FASTCALL *JSObjStubUInt32)(VMFrame &, uint32);
268 typedef JSObject * (JS_FASTCALL *JSObjStubFun)(VMFrame &, JSFunction *);
269 typedef void (JS_FASTCALL *VoidStubFun)(VMFrame &, JSFunction *);
270 typedef JSObject * (JS_FASTCALL *JSObjStubJSObj)(VMFrame &, JSObject *);
271 typedef void (JS_FASTCALL *VoidStubAtom)(VMFrame &, JSAtom *);
272 typedef JSString * (JS_FASTCALL *JSStrStub)(VMFrame &);
273 typedef JSString * (JS_FASTCALL *JSStrStubUInt32)(VMFrame &, uint32);
274 typedef void (JS_FASTCALL *VoidStubJSObj)(VMFrame &, JSObject *);
275 typedef void (JS_FASTCALL *VoidStubPC)(VMFrame &, jsbytecode *);
276 typedef JSBool (JS_FASTCALL *BoolStubUInt32)(VMFrame &f, uint32);
277 #ifdef JS_MONOIC
278 typedef void (JS_FASTCALL *VoidStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *);
279 typedef void * (JS_FASTCALL *VoidPtrStubCallIC)(VMFrame &, js::mjit::ic::CallICInfo *);
280 typedef void (JS_FASTCALL *VoidStubGetGlobal)(VMFrame &, js::mjit::ic::GetGlobalNameIC *);
281 typedef void (JS_FASTCALL *VoidStubSetGlobal)(VMFrame &, js::mjit::ic::SetGlobalNameIC *);
282 typedef JSBool (JS_FASTCALL *BoolStubEqualityIC)(VMFrame &, js::mjit::ic::EqualityICInfo *);
283 typedef void * (JS_FASTCALL *VoidPtrStubTraceIC)(VMFrame &, js::mjit::ic::TraceICInfo *);
284 #endif
285 #ifdef JS_POLYIC
286 typedef void (JS_FASTCALL *VoidStubPIC)(VMFrame &, js::mjit::ic::PICInfo *);
287 typedef void (JS_FASTCALL *VoidStubGetElemIC)(VMFrame &, js::mjit::ic::GetElementIC *);
288 typedef void (JS_FASTCALL *VoidStubSetElemIC)(VMFrame &f, js::mjit::ic::SetElementIC *);
289 #endif
290
291 namespace mjit {
292
293 struct CallSite;
294
295 struct NativeMapEntry {
296     size_t          bcOff;  /* bytecode offset in script */
297     void            *ncode; /* pointer to native code */
298 };
299
300 struct JITScript {
301     typedef JSC::MacroAssemblerCodeRef CodeRef;
302     CodeRef         code;       /* pool & code addresses */
303
304
305     void            *invokeEntry;       /* invoke address */
306     void            *fastEntry;         /* cached entry, fastest */
307     void            *arityCheckEntry;   /* arity check address */
308
309     /*
310      * This struct has several variable-length sections that are allocated on
311      * the end:  nmaps, MICs, callICs, etc.  To save space -- worthwhile
312      * because JITScripts are common -- we only record their lengths.  We can
313      * find any of the sections from the lengths because we know their order.
314      * Therefore, do not change the section ordering in finishThisUp() without
315      * changing nMICs() et al as well.
316      */
317     uint32          nNmapPairs:31;      /* The NativeMapEntrys are sorted by .bcOff.
318                                            .ncode values may not be NULL. */
319     bool            singleStepMode:1;   /* compiled in "single step mode" */
320 #ifdef JS_MONOIC
321     uint32          nGetGlobalNames;
322     uint32          nSetGlobalNames;
323     uint32          nCallICs;
324     uint32          nEqualityICs;
325     uint32          nTraceICs;
326 #endif
327 #ifdef JS_POLYIC
328     uint32          nGetElems;
329     uint32          nSetElems;
330     uint32          nPICs;
331 #endif
332     uint32          nCallSites;
333
334 #ifdef JS_MONOIC
335     // Additional ExecutablePools that IC stubs were generated into.
336     typedef Vector<JSC::ExecutablePool *, 0, SystemAllocPolicy> ExecPoolVector;
337     ExecPoolVector execPools;
338 #endif
339
340     NativeMapEntry *nmap() const;
341 #ifdef JS_MONOIC
342     ic::GetGlobalNameIC *getGlobalNames() const;
343     ic::SetGlobalNameIC *setGlobalNames() const;
344     ic::CallICInfo *callICs() const;
345     ic::EqualityICInfo *equalityICs() const;
346     ic::TraceICInfo *traceICs() const;
347 #endif
348 #ifdef JS_POLYIC
349     ic::GetElementIC *getElems() const;
350     ic::SetElementIC *setElems() const;
351     ic::PICInfo     *pics() const;
352 #endif
353     js::mjit::CallSite *callSites() const;
354
355     ~JITScript();
356
357     bool isValidCode(void *ptr) {
358         char *jitcode = (char *)code.m_code.executableAddress();
359         char *jcheck = (char *)ptr;
360         return jcheck >= jitcode && jcheck < jitcode + code.m_size;
361     }
362
363     void nukeScriptDependentICs();
364     void sweepCallICs(JSContext *cx, bool purgeAll);
365     void purgeMICs();
366     void purgePICs();
367
368     size_t scriptDataSize();
369
370     size_t mainCodeSize() { return code.m_size; } /* doesn't account for fragmentation */
371
372     jsbytecode *nativeToPC(void *returnAddress) const;
373
374   private:
375     /* Helpers used to navigate the variable-length sections. */
376     char *nmapSectionLimit() const;
377     char *monoICSectionsLimit() const;
378     char *polyICSectionsLimit() const;
379 };
380
381 /*
382  * Execute the given mjit code. This is a low-level call and callers must
383  * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
384  */
385 JSBool EnterMethodJIT(JSContext *cx, JSStackFrame *fp, void *code, Value *stackLimit);
386
387 /* Execute a method that has been JIT compiled. */
388 JSBool JaegerShot(JSContext *cx);
389
390 /* Drop into the middle of a method at an arbitrary point, and execute. */
391 JSBool JaegerShotAtSafePoint(JSContext *cx, void *safePoint);
392
393 enum CompileStatus
394 {
395     Compile_Okay,
396     Compile_Abort,
397     Compile_Error,
398     Compile_Skipped
399 };
400
401 void JS_FASTCALL
402 ProfileStubCall(VMFrame &f);
403
404 CompileStatus JS_NEVER_INLINE
405 TryCompile(JSContext *cx, JSStackFrame *fp);
406
407 void
408 ReleaseScriptCode(JSContext *cx, JSScript *script);
409
410 struct CallSite
411 {
412     uint32 codeOffset;
413     uint32 pcOffset;
414     uint32 id;
415
416     // Normally, callsite ID is the __LINE__ in the program that added the
417     // callsite. Since traps can be removed, we make sure they carry over
418     // from each compilation, and identify them with a single, canonical
419     // ID. Hopefully a SpiderMonkey file won't have two billion source lines.
420     static const uint32 MAGIC_TRAP_ID = 0xFEDCBABC;
421
422     void initialize(uint32 codeOffset, uint32 pcOffset, uint32 id) {
423         this->codeOffset = codeOffset;
424         this->pcOffset = pcOffset;
425         this->id = id;
426     }
427
428     bool isTrap() const {
429         return id == MAGIC_TRAP_ID;
430     }
431 };
432
433 /*
434  * Re-enables a tracepoint in the method JIT. When full is true, we
435  * also reset the iteration counter.
436  */
437 void
438 ResetTraceHint(JSScript *script, jsbytecode *pc, uint16_t index, bool full);
439
440 uintN
441 GetCallTargetCount(JSScript *script, jsbytecode *pc);
442
443 inline void * bsearch_nmap(NativeMapEntry *nmap, size_t nPairs, size_t bcOff)
444 {
445     size_t lo = 1, hi = nPairs;
446     while (1) {
447         /* current unsearched space is from lo-1 to hi-1, inclusive. */
448         if (lo > hi)
449             return NULL; /* not found */
450         size_t mid       = (lo + hi) / 2;
451         size_t bcOff_mid = nmap[mid-1].bcOff;
452         if (bcOff < bcOff_mid) {
453             hi = mid-1;
454             continue;
455         } 
456         if (bcOff > bcOff_mid) {
457             lo = mid+1;
458             continue;
459         }
460         return nmap[mid-1].ncode;
461     }
462 }
463
464 } /* namespace mjit */
465
466 } /* namespace js */
467
468 inline void *
469 JSScript::maybeNativeCodeForPC(bool constructing, jsbytecode *pc)
470 {
471     js::mjit::JITScript *jit = getJIT(constructing);
472     if (!jit)
473         return NULL;
474     JS_ASSERT(pc >= code && pc < code + length);
475     return bsearch_nmap(jit->nmap(), jit->nNmapPairs, (size_t)(pc - code));
476 }
477
478 inline void *
479 JSScript::nativeCodeForPC(bool constructing, jsbytecode *pc)
480 {
481     js::mjit::JITScript *jit = getJIT(constructing);
482     JS_ASSERT(pc >= code && pc < code + length);
483     void* native = bsearch_nmap(jit->nmap(), jit->nNmapPairs, (size_t)(pc - code));
484     JS_ASSERT(native);
485     return native;
486 }
487
488 #ifdef _MSC_VER
489 extern "C" void *JaegerThrowpoline(js::VMFrame *vmFrame);
490 #else
491 extern "C" void JaegerThrowpoline();
492 #endif
493 extern "C" void InjectJaegerReturn();
494
495 #endif /* jsjaeger_h__ */
496