1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99:
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>
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.
37 * ***** END LICENSE BLOCK ***** */
39 #if !defined jsjaeger_h__ && defined JS_METHODJIT
44 #include "assembler/assembler/MacroAssemblerCodeRef.h"
46 #if !defined JS_CPU_X64 && \
47 !defined JS_CPU_X86 && \
49 # error "Oh no, you should define a platform so this compiles."
52 #if !defined(JS_NUNBOX32) && !defined(JS_PUNBOX64)
53 # error "No boxing format selected."
58 namespace mjit
{ struct JITScript
; }
79 JSStackFrame
*entryfp
;
81 #if defined(JS_CPU_X86)
88 # ifdef JS_NO_FASTCALL
89 inline void** returnAddressLocation() {
90 return reinterpret_cast<void**>(this) - 5;
93 inline void** returnAddressLocation() {
94 return reinterpret_cast<void**>(this) - 1;
97 #elif defined(JS_CPU_X64)
111 inline void** returnAddressLocation() {
112 return reinterpret_cast<void**>(this) - 5;
115 inline void** returnAddressLocation() {
116 return reinterpret_cast<void**>(this) - 1;
120 #elif defined(JS_CPU_ARM)
131 inline void** returnAddressLocation() {
132 return reinterpret_cast<void**>(this) - 1;
135 # error "The VMFrame layout isn't defined for your processor architecture!"
138 JSRuntime
*runtime() { return cx
->runtime
; }
140 JSStackFrame
*&fp() { return regs
.fp
; }
141 mjit::JITScript
*jit() { return fp()->jit(); }
145 // WARNING: Do not call this function directly from C(++) code because it is not ABI-compliant.
146 extern "C" void JaegerStubVeneer(void);
152 * Trampolines to force returns from jit code.
153 * See also TrampolineCompiler::generateForceReturn(Fast).
156 typedef void (*TrampolinePtr
)();
158 TrampolinePtr forceReturn
;
159 JSC::ExecutablePool
*forceReturnPool
;
161 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
162 TrampolinePtr forceReturnFast
;
163 JSC::ExecutablePool
*forceReturnFastPool
;
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.
173 class JaegerCompartment
{
174 JSC::ExecutableAllocator
*execAlloc
; // allocator for jit code
175 Trampolines trampolines
; // force-return trampolines
176 VMFrame
*activeFrame_
; // current active VMFrame
183 ~JaegerCompartment() { Finish(); }
185 JSC::ExecutablePool
*poolForSize(size_t size
) {
186 return execAlloc
->poolForSize(size
);
189 VMFrame
*activeFrame() {
193 void pushActiveFrame(VMFrame
*f
) {
194 f
->previous
= activeFrame_
;
198 void popActiveFrame() {
199 JS_ASSERT(activeFrame_
);
200 activeFrame_
= activeFrame_
->previous
;
203 Trampolines::TrampolinePtr
forceReturnTrampoline() const {
204 return trampolines
.forceReturn
;
207 #if (defined(JS_NO_FASTCALL) && defined(JS_CPU_X86)) || defined(_WIN64)
208 Trampolines::TrampolinePtr
forceReturnFastTrampoline() const {
209 return trampolines
.forceReturnFast
;
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.
221 class CompilerAllocPolicy
: public ContextAllocPolicy
225 void *checkAlloc(void *p
) {
232 CompilerAllocPolicy(JSContext
*cx
, bool *oomFlag
)
233 : ContextAllocPolicy(cx
), oomFlag(oomFlag
) {}
234 CompilerAllocPolicy(JSContext
*cx
, Compiler
&compiler
);
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
));
243 # if defined JS_POLYIC
248 # if defined JS_MONOIC
249 struct GetGlobalNameIC
;
250 struct SetGlobalNameIC
;
251 struct EqualityICInfo
;
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
);
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
*);
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
*);
295 struct NativeMapEntry
{
296 size_t bcOff
; /* bytecode offset in script */
297 void *ncode
; /* pointer to native code */
301 typedef JSC::MacroAssemblerCodeRef CodeRef
;
302 CodeRef code
; /* pool & code addresses */
305 void *invokeEntry
; /* invoke address */
306 void *fastEntry
; /* cached entry, fastest */
307 void *arityCheckEntry
; /* arity check address */
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.
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" */
321 uint32 nGetGlobalNames
;
322 uint32 nSetGlobalNames
;
335 // Additional ExecutablePools that IC stubs were generated into.
336 typedef Vector
<JSC::ExecutablePool
*, 0, SystemAllocPolicy
> ExecPoolVector
;
337 ExecPoolVector execPools
;
340 NativeMapEntry
*nmap() const;
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;
349 ic::GetElementIC
*getElems() const;
350 ic::SetElementIC
*setElems() const;
351 ic::PICInfo
*pics() const;
353 js::mjit::CallSite
*callSites() const;
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
;
363 void nukeScriptDependentICs();
364 void sweepCallICs(JSContext
*cx
, bool purgeAll
);
368 size_t scriptDataSize();
370 size_t mainCodeSize() { return code
.m_size
; } /* doesn't account for fragmentation */
372 jsbytecode
*nativeToPC(void *returnAddress
) const;
375 /* Helpers used to navigate the variable-length sections. */
376 char *nmapSectionLimit() const;
377 char *monoICSectionsLimit() const;
378 char *polyICSectionsLimit() const;
382 * Execute the given mjit code. This is a low-level call and callers must
383 * provide the same guarantees as JaegerShot/CheckStackAndEnterMethodJIT.
385 JSBool
EnterMethodJIT(JSContext
*cx
, JSStackFrame
*fp
, void *code
, Value
*stackLimit
);
387 /* Execute a method that has been JIT compiled. */
388 JSBool
JaegerShot(JSContext
*cx
);
390 /* Drop into the middle of a method at an arbitrary point, and execute. */
391 JSBool
JaegerShotAtSafePoint(JSContext
*cx
, void *safePoint
);
402 ProfileStubCall(VMFrame
&f
);
404 CompileStatus JS_NEVER_INLINE
405 TryCompile(JSContext
*cx
, JSStackFrame
*fp
);
408 ReleaseScriptCode(JSContext
*cx
, JSScript
*script
);
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;
422 void initialize(uint32 codeOffset
, uint32 pcOffset
, uint32 id
) {
423 this->codeOffset
= codeOffset
;
424 this->pcOffset
= pcOffset
;
428 bool isTrap() const {
429 return id
== MAGIC_TRAP_ID
;
434 * Re-enables a tracepoint in the method JIT. When full is true, we
435 * also reset the iteration counter.
438 ResetTraceHint(JSScript
*script
, jsbytecode
*pc
, uint16_t index
, bool full
);
441 GetCallTargetCount(JSScript
*script
, jsbytecode
*pc
);
443 inline void * bsearch_nmap(NativeMapEntry
*nmap
, size_t nPairs
, size_t bcOff
)
445 size_t lo
= 1, hi
= nPairs
;
447 /* current unsearched space is from lo-1 to hi-1, inclusive. */
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
) {
456 if (bcOff
> bcOff_mid
) {
460 return nmap
[mid
-1].ncode
;
464 } /* namespace mjit */
469 JSScript::maybeNativeCodeForPC(bool constructing
, jsbytecode
*pc
)
471 js::mjit::JITScript
*jit
= getJIT(constructing
);
474 JS_ASSERT(pc
>= code
&& pc
< code
+ length
);
475 return bsearch_nmap(jit
->nmap(), jit
->nNmapPairs
, (size_t)(pc
- code
));
479 JSScript::nativeCodeForPC(bool constructing
, jsbytecode
*pc
)
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
));
489 extern "C" void *JaegerThrowpoline(js::VMFrame
*vmFrame
);
491 extern "C" void JaegerThrowpoline();
493 extern "C" void InjectJaegerReturn();
495 #endif /* jsjaeger_h__ */