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 Jaegermonkey.
19 * The Initial Developer of the Original Code is the Mozilla Foundation.
21 * Portions created by the Initial Developer are Copyright (C) 2010
22 * the Initial Developer. All Rights Reserved.
25 * Andrew Drake <drakedevel@gmail.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
44 #include "MethodJIT.h"
49 #include "jscntxtinlines.h"
52 using namespace js::mjit
;
57 AutoScriptRetrapper::~AutoScriptRetrapper()
59 while (!traps
.empty()) {
60 jsbytecode
*pc
= traps
.back();
67 AutoScriptRetrapper::untrap(jsbytecode
*pc
)
69 if (!traps
.append(pc
))
71 *pc
= JS_GetTrapOpcode(cx
, script
, pc
);
75 Recompiler::PatchableAddress
76 Recompiler::findPatch(JITScript
*jit
, void **location
)
78 uint8
* codeStart
= (uint8
*)jit
->code
.m_code
.executableAddress();
79 CallSite
*callSites_
= jit
->callSites();
80 for (uint32 i
= 0; i
< jit
->nCallSites
; i
++) {
81 if (callSites_
[i
].codeOffset
+ codeStart
== *location
) {
82 PatchableAddress result
;
83 result
.location
= location
;
84 result
.callSite
= callSites_
[i
];
89 JS_NOT_REACHED("failed to find call site");
90 return PatchableAddress();
94 Recompiler::applyPatch(Compiler
& c
, PatchableAddress
& toPatch
)
96 void *result
= c
.findCallSite(toPatch
.callSite
);
98 *toPatch
.location
= result
;
101 Recompiler::Recompiler(JSContext
*cx
, JSScript
*script
)
102 : cx(cx
), script(script
)
107 * The strategy for this goes as follows:
109 * 1) Scan the stack, looking at all return addresses that could go into JIT
111 * 2) If an address corresponds to a call site registered by |callSite| during
112 * the last compilation, remember it.
113 * 3) Purge the old compiled state and return if there were no active frames of
114 * this script on the stack.
115 * 4) Fix up the stack by replacing all saved addresses with the addresses the
116 * new compiler gives us for the call sites.
119 Recompiler::recompile()
121 JS_ASSERT(script
->hasJITCode());
123 Vector
<PatchableAddress
> normalPatches(cx
);
124 Vector
<PatchableAddress
> ctorPatches(cx
);
126 JSStackFrame
*firstCtorFrame
= NULL
;
127 JSStackFrame
*firstNormalFrame
= NULL
;
129 // Find all JIT'd stack frames to account for return addresses that will
130 // need to be patched after recompilation.
131 for (VMFrame
*f
= script
->compartment
->jaegerCompartment
->activeFrame();
135 // Scan all frames owned by this VMFrame.
136 JSStackFrame
*end
= f
->entryfp
->prev();
137 for (JSStackFrame
*fp
= f
->fp(); fp
!= end
; fp
= fp
->prev()) {
138 // Remember the latest frame for each type of JIT'd code, so the
139 // compiler will have a frame to re-JIT from.
140 if (!firstCtorFrame
&& fp
->script() == script
&& fp
->isConstructing())
142 else if (!firstNormalFrame
&& fp
->script() == script
&& !fp
->isConstructing())
143 firstNormalFrame
= fp
;
145 void **addr
= fp
->addressOfNativeReturnAddress();
146 if (script
->jitCtor
&& script
->jitCtor
->isValidCode(*addr
)) {
147 if (!ctorPatches
.append(findPatch(script
->jitCtor
, addr
)))
149 } else if (script
->jitNormal
&& script
->jitNormal
->isValidCode(*addr
)) {
150 if (!normalPatches
.append(findPatch(script
->jitNormal
, addr
)))
155 void **addr
= f
->returnAddressLocation();
156 if (script
->jitCtor
&& script
->jitCtor
->isValidCode(*addr
)) {
157 if (!ctorPatches
.append(findPatch(script
->jitCtor
, addr
)))
159 } else if (script
->jitNormal
&& script
->jitNormal
->isValidCode(*addr
)) {
160 if (!normalPatches
.append(findPatch(script
->jitNormal
, addr
)))
165 Vector
<CallSite
> normalSites(cx
);
166 Vector
<CallSite
> ctorSites(cx
);
168 if (script
->jitNormal
&& !saveTraps(script
->jitNormal
, &normalSites
))
170 if (script
->jitCtor
&& !saveTraps(script
->jitCtor
, &ctorSites
))
173 ReleaseScriptCode(cx
, script
);
175 if (normalPatches
.length() &&
176 !recompile(firstNormalFrame
, normalPatches
, normalSites
)) {
180 if (ctorPatches
.length() &&
181 !recompile(firstCtorFrame
, ctorPatches
, ctorSites
)) {
189 Recompiler::saveTraps(JITScript
*jit
, Vector
<CallSite
> *sites
)
191 CallSite
*callSites_
= jit
->callSites();
192 for (uint32 i
= 0; i
< jit
->nCallSites
; i
++) {
193 CallSite
&site
= callSites_
[i
];
194 if (site
.isTrap() && !sites
->append(site
))
201 Recompiler::recompile(JSStackFrame
*fp
, Vector
<PatchableAddress
> &patches
,
202 Vector
<CallSite
> &sites
)
204 /* If we get this far, the script is live, and we better be safe to re-jit. */
205 JS_ASSERT(cx
->compartment
->debugMode
);
209 if (!c
.loadOldTraps(sites
))
211 if (c
.compile() != Compile_Okay
)
214 /* Perform the earlier scanned patches */
215 for (uint32 i
= 0; i
< patches
.length(); i
++)
216 applyPatch(c
, patches
[i
]);
221 } /* namespace mjit */
224 #endif /* JS_METHODJIT */