Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / methodjit / BaseCompiler.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  *   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 "jstl.h"
45 #include "assembler/assembler/MacroAssembler.h"
46 #include "assembler/assembler/LinkBuffer.h"
47 #include "assembler/assembler/RepatchBuffer.h"
48 #include "assembler/jit/ExecutableAllocator.h"
49 #include <limits.h>
50
51 #if defined JS_CPU_ARM
52 # define POST_INST_OFFSET(__expr) ((__expr) - sizeof(ARMWord))
53 #else
54 # define POST_INST_OFFSET(__expr) (__expr)
55 #endif
56
57 namespace js {
58 namespace mjit {
59
60 struct MacroAssemblerTypedefs {
61     typedef JSC::MacroAssembler::Label Label;
62     typedef JSC::MacroAssembler::Imm32 Imm32;
63     typedef JSC::MacroAssembler::ImmPtr ImmPtr;
64     typedef JSC::MacroAssembler::RegisterID RegisterID;
65     typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
66     typedef JSC::MacroAssembler::Address Address;
67     typedef JSC::MacroAssembler::BaseIndex BaseIndex;
68     typedef JSC::MacroAssembler::AbsoluteAddress AbsoluteAddress;
69     typedef JSC::MacroAssembler MacroAssembler;
70     typedef JSC::MacroAssembler::Jump Jump;
71     typedef JSC::MacroAssembler::JumpList JumpList;
72     typedef JSC::MacroAssembler::Call Call;
73     typedef JSC::MacroAssembler::DataLabelPtr DataLabelPtr;
74     typedef JSC::MacroAssembler::DataLabel32 DataLabel32;
75     typedef JSC::FunctionPtr FunctionPtr;
76     typedef JSC::RepatchBuffer RepatchBuffer;
77     typedef JSC::CodeLocationLabel CodeLocationLabel;
78     typedef JSC::CodeLocationDataLabel32 CodeLocationDataLabel32;
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     BaseCompiler(JSContext *cx) : cx(cx)
100     { }
101
102   protected:
103
104     JSC::ExecutablePool *
105     getExecPool(JSScript *script, size_t size) {
106         return BaseCompiler::GetExecPool(cx, script, size);
107     }
108
109   public:
110     static JSC::ExecutablePool *
111     GetExecPool(JSContext *cx, JSScript *script, size_t size) {
112         JaegerCompartment *jc = script->compartment->jaegerCompartment;
113         JSC::ExecutablePool *pool = jc->poolForSize(size);
114         if (!pool)
115             js_ReportOutOfMemory(cx);
116         return pool;
117     }
118 };
119
120 // This class wraps JSC::LinkBuffer for Mozilla-specific memory handling.
121 // Every return |false| guarantees an OOM that has been correctly propagated,
122 // and should continue to propagate.
123 class LinkerHelper : public JSC::LinkBuffer
124 {
125   protected:
126     Assembler &masm;
127 #ifdef DEBUG
128     bool verifiedRange;
129 #endif
130
131   public:
132     LinkerHelper(Assembler &masm) : masm(masm)
133 #ifdef DEBUG
134         , verifiedRange(false)
135 #endif
136     { }
137
138     ~LinkerHelper() {
139         JS_ASSERT(verifiedRange);
140     }
141
142     bool verifyRange(const JSC::JITCode &other) {
143 #ifdef DEBUG
144         verifiedRange = true;
145 #endif
146 #ifdef JS_CPU_X64
147         uintptr_t lowest = JS_MIN(uintptr_t(m_code), uintptr_t(other.start()));
148
149         uintptr_t myEnd = uintptr_t(m_code) + m_size;
150         uintptr_t otherEnd = uintptr_t(other.start()) + other.size();
151         uintptr_t highest = JS_MAX(myEnd, otherEnd);
152
153         return (highest - lowest < INT_MAX);
154 #else
155         return true;
156 #endif
157     }
158
159     bool verifyRange(JITScript *jit) {
160         return verifyRange(JSC::JITCode(jit->code.m_code.executableAddress(), jit->code.m_size));
161     }
162
163     JSC::ExecutablePool *init(JSContext *cx) {
164         // The pool is incref'd after this call, so it's necessary to release()
165         // on any failure.
166         JSScript *script = cx->fp()->script();
167         JSC::ExecutablePool *ep = BaseCompiler::GetExecPool(cx, script, masm.size());
168         if (!ep)
169             return ep;
170
171         m_code = executableCopy(masm, ep);
172         if (!m_code) {
173             ep->release();
174             js_ReportOutOfMemory(cx);
175             return NULL;
176         }
177         m_size = masm.size();   // must come after the call to executableCopy()
178         return ep;
179     }
180
181     JSC::CodeLocationLabel finalize() {
182         masm.finalize(*this);
183         return finalizeCodeAddendum();
184     }
185
186     void maybeLink(MaybeJump jump, JSC::CodeLocationLabel label) {
187         if (!jump.isSet())
188             return;
189         link(jump.get(), label);
190     }
191
192     size_t size() const {
193         return m_size;
194     }
195 };
196
197 /*
198  * On ARM, we periodically flush a constant pool into the instruction stream
199  * where constants are found using PC-relative addressing. This is necessary
200  * because the fixed-width instruction set doesn't support wide immediates.
201  *
202  * ICs perform repatching on the inline (fast) path by knowing small and
203  * generally fixed code location offset values where the patchable instructions
204  * live. Dumping a huge constant pool into the middle of an IC's inline path
205  * makes the distance between emitted instructions potentially variable and/or
206  * large, which makes the IC offsets invalid. We must reserve contiguous space
207  * up front to prevent this from happening.
208  */
209 #ifdef JS_CPU_ARM
210 template <size_t reservedSpace>
211 class AutoReserveICSpace {
212     typedef Assembler::Label Label;
213
214     Assembler           &masm;
215 #ifdef DEBUG
216     Label               startLabel;
217     bool                didCheck;
218 #endif
219
220   public:
221     AutoReserveICSpace(Assembler &masm) : masm(masm) {
222         masm.ensureSpace(reservedSpace);
223 #ifdef DEBUG
224         didCheck = false;
225
226         startLabel = masm.label();
227
228         /* Assert that the constant pool is not flushed until we reach a safe point. */
229         masm.allowPoolFlush(false);
230
231         JaegerSpew(JSpew_Insns, " -- BEGIN CONSTANT-POOL-FREE REGION -- \n");
232 #endif
233     }
234
235     /* Allow manual IC space checks so that non-patchable code at the end of an IC section can be
236      * free to use constant pools. */
237     void check() {
238 #ifdef DEBUG
239         JS_ASSERT(!didCheck);
240         didCheck = true;
241
242         Label endLabel = masm.label();
243         int spaceUsed = masm.differenceBetween(startLabel, endLabel);
244
245         /* Spew the space used, to help tuning of reservedSpace. */
246         JaegerSpew(JSpew_Insns,
247                    " -- END CONSTANT-POOL-FREE REGION: %u bytes used of %u reserved. -- \n",
248                    spaceUsed, reservedSpace);
249
250         /* Assert that we didn't emit more code than we protected. */
251         JS_ASSERT(spaceUsed >= 0);
252         JS_ASSERT(size_t(spaceUsed) <= reservedSpace);
253
254         /* Allow the pool to be flushed. */
255         masm.allowPoolFlush(true);
256 #endif
257     }
258
259     ~AutoReserveICSpace() {
260 #ifdef DEBUG
261         /* Automatically check the IC space if we didn't already do it manually. */
262         if (!didCheck) {
263             check();
264         }
265 #endif
266     }
267 };
268
269 # define RESERVE_IC_SPACE(__masm)       AutoReserveICSpace<128> arics(__masm)
270 # define CHECK_IC_SPACE()               arics.check()
271
272 /* The OOL path can need a lot of space because we save and restore a lot of registers. The actual
273  * sequene varies. However, dumping the literal pool before an OOL block is probably a good idea
274  * anyway, as we branch directly to the start of the block from the fast path. */
275 # define RESERVE_OOL_SPACE(__masm)      AutoReserveICSpace<256> arics_ool(__masm)
276
277 /* Allow the OOL patch to be checked before object destruction. Often, non-patchable epilogues or
278  * rejoining sequences are emitted, and it isn't necessary to protect these from literal pools. */
279 # define CHECK_OOL_SPACE()              arics_ool.check()
280 #else
281 # define RESERVE_IC_SPACE(__masm)       /* Do nothing. */
282 # define CHECK_IC_SPACE()               /* Do nothing. */
283 # define RESERVE_OOL_SPACE(__masm)      /* Do nothing. */
284 # define CHECK_OOL_SPACE()              /* Do nothing. */
285 #endif
286
287 } /* namespace js */
288 } /* namespace mjit */
289
290 #endif