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 : * David Anderson <danderson@mozilla.com>
25 : * David Mandelin <dmandelin@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or 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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 : #if !defined jsjaeger_compilerbase_h__ && defined JS_METHODJIT
41 : #define jsjaeger_compilerbase_h__
42 :
43 : #include "jscntxt.h"
44 : #include "assembler/assembler/MacroAssembler.h"
45 : #include "assembler/assembler/LinkBuffer.h"
46 : #include "assembler/assembler/RepatchBuffer.h"
47 : #include "assembler/jit/ExecutableAllocator.h"
48 : #include <limits.h>
49 :
50 : #if defined JS_CPU_ARM
51 : # define POST_INST_OFFSET(__expr) ((__expr) - sizeof(ARMWord))
52 : #else
53 : # define POST_INST_OFFSET(__expr) (__expr)
54 : #endif
55 :
56 : namespace js {
57 : namespace mjit {
58 :
59 2067462 : struct MacroAssemblerTypedefs {
60 : typedef JSC::MacroAssembler::Label Label;
61 : typedef JSC::MacroAssembler::Imm32 Imm32;
62 : typedef JSC::MacroAssembler::ImmPtr ImmPtr;
63 : typedef JSC::MacroAssembler::RegisterID RegisterID;
64 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
65 : typedef JSC::MacroAssembler::Address Address;
66 : typedef JSC::MacroAssembler::BaseIndex BaseIndex;
67 : typedef JSC::MacroAssembler::AbsoluteAddress AbsoluteAddress;
68 : typedef JSC::MacroAssembler MacroAssembler;
69 : typedef JSC::MacroAssembler::Jump Jump;
70 : typedef JSC::MacroAssembler::JumpList JumpList;
71 : typedef JSC::MacroAssembler::Call Call;
72 : typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
73 : typedef JSC::MacroAssembler::DataLabel32 DataLabel32;
74 : typedef JSC::FunctionPtr FunctionPtr;
75 : typedef JSC::RepatchBuffer RepatchBuffer;
76 : typedef JSC::CodeLocationLabel CodeLocationLabel;
77 : typedef JSC::CodeLocationDataLabel32 CodeLocationDataLabel32;
78 : typedef JSC::CodeLocationDataLabelPtr CodeLocationDataLabelPtr;
79 : typedef JSC::CodeLocationJump CodeLocationJump;
80 : typedef JSC::CodeLocationCall CodeLocationCall;
81 : typedef JSC::CodeLocationInstruction CodeLocationInstruction;
82 : typedef JSC::ReturnAddressPtr ReturnAddressPtr;
83 : typedef JSC::MacroAssemblerCodePtr MacroAssemblerCodePtr;
84 : typedef JSC::JITCode JITCode;
85 : #if defined JS_CPU_ARM
86 : typedef JSC::ARMWord ARMWord;
87 : #endif
88 : };
89 :
90 : class BaseCompiler : public MacroAssemblerTypedefs
91 : {
92 : protected:
93 : JSContext *cx;
94 :
95 : public:
96 : BaseCompiler() : cx(NULL)
97 : { }
98 :
99 1183264 : BaseCompiler(JSContext *cx) : cx(cx)
100 1183264 : { }
101 : };
102 :
103 : #ifdef JS_CPU_X64
104 : inline bool
105 : VerifyRange(void *start1, size_t size1, void *start2, size_t size2)
106 : {
107 : uintptr_t end1 = uintptr_t(start1) + size1;
108 : uintptr_t end2 = uintptr_t(start2) + size2;
109 :
110 : uintptr_t lowest = JS_MIN(uintptr_t(start1), uintptr_t(start2));
111 : uintptr_t highest = JS_MAX(end1, end2);
112 :
113 : return (highest - lowest < INT_MAX);
114 : }
115 : #endif
116 :
117 : // This class wraps JSC::LinkBuffer for Mozilla-specific memory handling.
118 : // Every return |false| guarantees an OOM that has been correctly propagated,
119 : // and should continue to propagate.
120 : class LinkerHelper : public JSC::LinkBuffer
121 : {
122 : protected:
123 : Assembler &masm;
124 : #ifdef DEBUG
125 : bool verifiedRange;
126 : #endif
127 :
128 : public:
129 306058 : LinkerHelper(Assembler &masm, JSC::CodeKind kind) : JSC::LinkBuffer(kind)
130 : , masm(masm)
131 : #ifdef DEBUG
132 306058 : , verifiedRange(false)
133 : #endif
134 306058 : { }
135 :
136 612116 : ~LinkerHelper() {
137 306058 : JS_ASSERT(verifiedRange);
138 306058 : }
139 :
140 566218 : bool verifyRange(const JSC::JITCode &other) {
141 : #ifdef DEBUG
142 566218 : verifiedRange = true;
143 : #endif
144 : #ifdef JS_CPU_X64
145 : return VerifyRange(m_code, m_size, other.start(), other.size());
146 : #else
147 566218 : return true;
148 : #endif
149 : }
150 :
151 305824 : bool verifyRange(JITChunk *chunk) {
152 : return verifyRange(JSC::JITCode(chunk->code.m_code.executableAddress(),
153 305824 : chunk->code.m_size));
154 : }
155 :
156 306058 : JSC::ExecutablePool *init(JSContext *cx) {
157 : // The pool is incref'd after this call, so it's necessary to release()
158 : // on any failure.
159 306058 : JSScript *script = cx->fp()->script();
160 306058 : JSC::ExecutableAllocator *allocator = script->compartment()->jaegerCompartment()->execAlloc();
161 306058 : allocator->setDestroyCallback(Probes::discardExecutableRegion);
162 : JSC::ExecutablePool *pool;
163 306058 : m_code = executableAllocAndCopy(masm, allocator, &pool);
164 306058 : if (!m_code) {
165 0 : js_ReportOutOfMemory(cx);
166 0 : return NULL;
167 : }
168 306058 : m_size = masm.size(); // must come after call to executableAllocAndCopy()!
169 306058 : return pool;
170 : }
171 :
172 303936 : JSC::CodeLocationLabel finalize(VMFrame &f) {
173 303936 : masm.finalize(*this);
174 303936 : JSC::CodeLocationLabel label = finalizeCodeAddendum();
175 : Probes::registerICCode(f.cx, f.jit(), f.script(), f.pc(),
176 303936 : label.executableAddress(), masm.size());
177 : return label;
178 : }
179 :
180 17862 : void maybeLink(MaybeJump jump, JSC::CodeLocationLabel label) {
181 17862 : if (!jump.isSet())
182 11072 : return;
183 6790 : link(jump.get(), label);
184 : }
185 :
186 245847 : size_t size() const {
187 245847 : return m_size;
188 : }
189 : };
190 :
191 : class NativeStubLinker : public LinkerHelper
192 35521 : {
193 : public:
194 : #ifdef JS_CPU_X64
195 : typedef JSC::MacroAssembler::DataLabelPtr FinalJump;
196 : #else
197 : typedef JSC::MacroAssembler::Jump FinalJump;
198 : #endif
199 :
200 35521 : NativeStubLinker(Assembler &masm, JITChunk *chunk, jsbytecode *pc, FinalJump done)
201 35521 : : LinkerHelper(masm, JSC::METHOD_CODE), chunk(chunk), pc(pc), done(done)
202 35521 : {}
203 :
204 : bool init(JSContext *cx);
205 :
206 35521 : void patchJump(JSC::CodeLocationLabel target) {
207 : #ifdef JS_CPU_X64
208 : patch(done, target);
209 : #else
210 35521 : link(done, target);
211 : #endif
212 35521 : }
213 :
214 : private:
215 : JITChunk *chunk;
216 : jsbytecode *pc;
217 : FinalJump done;
218 : };
219 :
220 : bool
221 : NativeStubEpilogue(VMFrame &f, Assembler &masm, NativeStubLinker::FinalJump *result,
222 : int32_t initialFrameDepth, int32_t vpOffset,
223 : MaybeRegisterID typeReg, MaybeRegisterID dataReg);
224 :
225 : /*
226 : * On ARM, we periodically flush a constant pool into the instruction stream
227 : * where constants are found using PC-relative addressing. This is necessary
228 : * because the fixed-width instruction set doesn't support wide immediates.
229 : *
230 : * ICs perform repatching on the inline (fast) path by knowing small and
231 : * generally fixed code location offset values where the patchable instructions
232 : * live. Dumping a huge constant pool into the middle of an IC's inline path
233 : * makes the distance between emitted instructions potentially variable and/or
234 : * large, which makes the IC offsets invalid. We must reserve contiguous space
235 : * up front to prevent this from happening.
236 : */
237 : #ifdef JS_CPU_ARM
238 : template <size_t reservedSpace>
239 : class AutoReserveICSpace {
240 : typedef Assembler::Label Label;
241 :
242 : Assembler &masm;
243 : bool didCheck;
244 : bool *overflowSpace;
245 : int flushCount;
246 :
247 : public:
248 : AutoReserveICSpace(Assembler &masm, bool *overflowSpace)
249 : : masm(masm), didCheck(false), overflowSpace(overflowSpace)
250 : {
251 : masm.ensureSpace(reservedSpace);
252 : flushCount = masm.flushCount();
253 : }
254 :
255 : /* Allow manual IC space checks so that non-patchable code at the end of an IC section can be
256 : * free to use constant pools. */
257 : void check() {
258 : JS_ASSERT(!didCheck);
259 : didCheck = true;
260 :
261 : if (masm.flushCount() != flushCount)
262 : *overflowSpace = true;
263 : }
264 :
265 : ~AutoReserveICSpace() {
266 : /* Automatically check the IC space if we didn't already do it manually. */
267 : if (!didCheck) {
268 : check();
269 : }
270 : }
271 : };
272 :
273 : # define RESERVE_IC_SPACE(__masm) AutoReserveICSpace<256> arics(__masm, &this->overflowICSpace)
274 : # define CHECK_IC_SPACE() arics.check()
275 :
276 : /* The OOL path can need a lot of space because we save and restore a lot of registers. The actual
277 : * sequene varies. However, dumping the literal pool before an OOL block is probably a good idea
278 : * anyway, as we branch directly to the start of the block from the fast path. */
279 : # define RESERVE_OOL_SPACE(__masm) AutoReserveICSpace<2048> arics_ool(__masm, &this->overflowICSpace)
280 :
281 : /* Allow the OOL patch to be checked before object destruction. Often, non-patchable epilogues or
282 : * rejoining sequences are emitted, and it isn't necessary to protect these from literal pools. */
283 : # define CHECK_OOL_SPACE() arics_ool.check()
284 : #else
285 : # define RESERVE_IC_SPACE(__masm) /* Do nothing. */
286 : # define CHECK_IC_SPACE() /* Do nothing. */
287 : # define RESERVE_OOL_SPACE(__masm) /* Do nothing. */
288 : # define CHECK_OOL_SPACE() /* Do nothing. */
289 : #endif
290 :
291 : } /* namespace js */
292 : } /* namespace mjit */
293 :
294 : #endif
|