Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / methodjit / MachineRegs.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  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either of the GNU General Public License Version 2 or later (the "GPL"),
28  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 #if !defined jsjaeger_regstate_h__ && defined JS_METHODJIT
41 #define jsjaeger_regstate_h__
42
43 #include "jsbit.h"
44 #include "assembler/assembler/MacroAssembler.h"
45
46 namespace js {
47
48 namespace mjit {
49
50 struct Registers {
51     enum CallConvention {
52         NormalCall,
53         FastCall
54     };
55
56     typedef JSC::MacroAssembler::RegisterID RegisterID;
57
58     // Homed and scratch registers for working with Values on x64.
59 #if defined(JS_CPU_X64)
60     static const RegisterID TypeMaskReg = JSC::X86Registers::r13;
61     static const RegisterID PayloadMaskReg = JSC::X86Registers::r14;
62     static const RegisterID ValueReg = JSC::X86Registers::r10;
63 #endif
64
65     // Register that homes the current JSStackFrame.
66 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
67     static const RegisterID JSFrameReg = JSC::X86Registers::ebx;
68 #elif defined(JS_CPU_ARM)
69     static const RegisterID JSFrameReg = JSC::ARMRegisters::r11;
70 #endif
71
72 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
73     static const RegisterID ReturnReg = JSC::X86Registers::eax;
74 # if defined(JS_CPU_X86) || defined(_MSC_VER)
75     static const RegisterID ArgReg0 = JSC::X86Registers::ecx;
76     static const RegisterID ArgReg1 = JSC::X86Registers::edx;
77 #  if defined(JS_CPU_X64)
78     static const RegisterID ArgReg2 = JSC::X86Registers::r8;
79 #  endif
80 # else
81     static const RegisterID ArgReg0 = JSC::X86Registers::edi;
82     static const RegisterID ArgReg1 = JSC::X86Registers::esi;
83     static const RegisterID ArgReg2 = JSC::X86Registers::edx;
84 # endif
85 #elif JS_CPU_ARM
86     static const RegisterID ReturnReg = JSC::ARMRegisters::r0;
87     static const RegisterID ArgReg0 = JSC::ARMRegisters::r0;
88     static const RegisterID ArgReg1 = JSC::ARMRegisters::r1;
89     static const RegisterID ArgReg2 = JSC::ARMRegisters::r2;
90 #endif
91
92     static const RegisterID StackPointer = JSC::MacroAssembler::stackPointerRegister;
93
94     static inline uint32 maskReg(RegisterID reg) {
95         return (1 << reg);
96     }
97
98     static inline uint32 mask2Regs(RegisterID reg1, RegisterID reg2) {
99         return maskReg(reg1) | maskReg(reg2);
100     }
101
102     static inline uint32 mask3Regs(RegisterID reg1, RegisterID reg2, RegisterID reg3) {
103         return maskReg(reg1) | maskReg(reg2) | maskReg(reg3);
104     }
105
106 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
107     static const uint32 TempRegs =
108           (1 << JSC::X86Registers::eax)
109         | (1 << JSC::X86Registers::ecx)
110         | (1 << JSC::X86Registers::edx)
111 # if defined(JS_CPU_X64)
112         | (1 << JSC::X86Registers::r8)
113         | (1 << JSC::X86Registers::r9)
114 #  if !defined(_MSC_VER)
115         | (1 << JSC::X86Registers::esi)
116         | (1 << JSC::X86Registers::edi)
117 #  endif
118 # endif
119         ;
120
121 # if defined(JS_CPU_X64)
122     static const uint32 SavedRegs =
123         /* r11 is scratchRegister, used by JSC. */
124           (1 << JSC::X86Registers::r12)
125     // r13 is TypeMaskReg.
126     // r14 is PayloadMaskReg.
127         | (1 << JSC::X86Registers::r15)
128 #  if defined(_MSC_VER)
129         | (1 << JSC::X86Registers::esi)
130         | (1 << JSC::X86Registers::edi)
131 #  endif
132 # else
133     static const uint32 SavedRegs =
134           (1 << JSC::X86Registers::esi)
135         | (1 << JSC::X86Registers::edi)
136 # endif
137         ;
138
139 # if defined(JS_CPU_X86)
140     static const uint32 SingleByteRegs = (TempRegs | SavedRegs) &
141         ~((1 << JSC::X86Registers::esi) |
142           (1 << JSC::X86Registers::edi) |
143           (1 << JSC::X86Registers::ebp) |
144           (1 << JSC::X86Registers::esp));
145 # elif defined(JS_CPU_X64)
146     static const uint32 SingleByteRegs = TempRegs | SavedRegs;
147 # endif
148
149 #elif defined(JS_CPU_ARM)
150     static const uint32 TempRegs =
151           (1 << JSC::ARMRegisters::r0)
152         | (1 << JSC::ARMRegisters::r1)
153         | (1 << JSC::ARMRegisters::r2);
154     // r3 is reserved as a scratch register for the assembler.
155
156     static const uint32 SavedRegs =
157           (1 << JSC::ARMRegisters::r4)
158         | (1 << JSC::ARMRegisters::r5)
159         | (1 << JSC::ARMRegisters::r6)
160         | (1 << JSC::ARMRegisters::r7)
161     // r8 is reserved as a scratch register for the assembler.
162         | (1 << JSC::ARMRegisters::r9)
163         | (1 << JSC::ARMRegisters::r10);
164     // r11 is reserved for JSFrameReg.
165     // r12 is IP, and is used for stub calls.
166     // r13 is SP and must always point to VMFrame whilst in generated code.
167     // r14 is LR and is used for return sequences.
168     // r15 is PC (program counter).
169
170     static const uint32 SingleByteRegs = TempRegs | SavedRegs;
171 #else
172 # error "Unsupported platform"
173 #endif
174
175     static const uint32 AvailRegs = SavedRegs | TempRegs;
176
177     static bool isSaved(RegisterID reg) {
178         uint32 mask = maskReg(reg);
179         JS_ASSERT(mask & AvailRegs);
180         return bool(mask & SavedRegs);
181     }
182
183     static inline uint32 numArgRegs(CallConvention convention) {
184 #if defined(JS_CPU_X86)
185 # if defined(JS_NO_FASTCALL)
186         return 0;
187 # else
188         return (convention == FastCall) ? 2 : 0;
189 # endif
190 #elif defined(JS_CPU_X64)
191 # ifdef _WIN64
192         return 4;
193 # else
194         return 6;
195 # endif
196 #elif defined(JS_CPU_ARM)
197         return 4;
198 #endif
199     }
200
201     static inline bool regForArg(CallConvention conv, uint32 i, RegisterID *reg) {
202 #if defined(JS_CPU_X86)
203         static const RegisterID regs[] = {
204             JSC::X86Registers::ecx,
205             JSC::X86Registers::edx
206         };
207
208 # if defined(JS_NO_FASTCALL)
209         return false;
210 # else
211         if (conv == NormalCall)
212             return false;
213 # endif
214 #elif defined(JS_CPU_X64)
215 # ifdef _WIN64
216         static const RegisterID regs[] = {
217             JSC::X86Registers::ecx,
218             JSC::X86Registers::edx,
219             JSC::X86Registers::r8,
220             JSC::X86Registers::r9
221         };
222 # else
223         static const RegisterID regs[] = {
224             JSC::X86Registers::edi,
225             JSC::X86Registers::esi,
226             JSC::X86Registers::edx,
227             JSC::X86Registers::ecx,
228             JSC::X86Registers::r8,
229             JSC::X86Registers::r9
230         };
231 # endif
232 #elif defined(JS_CPU_ARM)
233         static const RegisterID regs[] = {
234             JSC::ARMRegisters::r0,
235             JSC::ARMRegisters::r1,
236             JSC::ARMRegisters::r2,
237             JSC::ARMRegisters::r3
238         };
239 #endif
240         JS_ASSERT(numArgRegs(conv) == JS_ARRAY_LENGTH(regs));
241         if (i > JS_ARRAY_LENGTH(regs))
242             return false;
243         *reg = regs[i];
244         return true;
245     }
246
247     Registers()
248       : freeMask(AvailRegs)
249     { }
250
251     Registers(uint32 freeMask)
252       : freeMask(freeMask)
253     { }
254
255     Registers(const Registers &other)
256       : freeMask(other.freeMask)
257     { }
258
259     Registers & operator =(const Registers &other)
260     {
261         freeMask = other.freeMask;
262         return *this;
263     }
264
265     void reset() {
266         freeMask = AvailRegs;
267     }
268
269     bool empty() const {
270         return !freeMask;
271     }
272
273     bool empty(uint32 mask) const {
274         return !(freeMask & mask);
275     }
276
277     RegisterID peekReg() {
278         JS_ASSERT(!empty());
279         int ireg;
280         JS_FLOOR_LOG2(ireg, freeMask);
281         RegisterID reg = (RegisterID)ireg;
282         return reg;
283     }
284
285     RegisterID takeAnyReg() {
286         RegisterID reg = peekReg();
287         takeReg(reg);
288         return reg;
289     }
290
291     bool hasRegInMask(uint32 mask) const {
292         Registers temp(freeMask & mask);
293         return !temp.empty();
294     }
295
296     RegisterID takeRegInMask(uint32 mask) {
297         Registers temp(freeMask & mask);
298         RegisterID reg = temp.takeAnyReg();
299         takeReg(reg);
300         return reg;
301     }
302
303     bool hasReg(RegisterID reg) const {
304         return !!(freeMask & (1 << reg));
305     }
306
307     void putRegUnchecked(RegisterID reg) {
308         freeMask |= (1 << reg);
309     }
310
311     void putReg(RegisterID reg) {
312         JS_ASSERT(!hasReg(reg));
313         putRegUnchecked(reg);
314     }
315
316     void takeReg(RegisterID reg) {
317         JS_ASSERT(hasReg(reg));
318         takeRegUnchecked(reg);
319     }
320
321     void takeRegUnchecked(RegisterID reg) {
322         freeMask &= ~(1 << reg);
323     }
324
325     bool operator ==(const Registers &other) {
326         return freeMask == other.freeMask;
327     }
328
329     uint32 freeMask;
330 };
331
332
333 struct FPRegisters {
334
335     typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
336
337 #if defined(JS_CPU_X86) || defined(JS_CPU_X64)
338     static const uint32 TotalFPRegisters = 8;
339     static const uint32 TempFPRegs =
340           (1 << JSC::X86Registers::xmm0)
341         | (1 << JSC::X86Registers::xmm1)
342         | (1 << JSC::X86Registers::xmm2)
343         | (1 << JSC::X86Registers::xmm3)
344         | (1 << JSC::X86Registers::xmm4)
345         | (1 << JSC::X86Registers::xmm5)
346         | (1 << JSC::X86Registers::xmm6)
347         | (1 << JSC::X86Registers::xmm7);
348     /* FIXME: Temporary hack until FPRegister allocation exists. */
349     static const FPRegisterID First  = JSC::X86Registers::xmm0;
350     static const FPRegisterID Second = JSC::X86Registers::xmm1;
351     static const FPRegisterID Temp0 = JSC::X86Registers::xmm2;
352     static const FPRegisterID Temp1 = JSC::X86Registers::xmm3;
353 #elif defined(JS_CPU_ARM)
354     static const uint32 TotalFPRegisters = 4;
355     static const uint32 TempFPRegs = 
356           (1 << JSC::ARMRegisters::d0)
357         | (1 << JSC::ARMRegisters::d1)
358         | (1 << JSC::ARMRegisters::d2)
359         | (1 << JSC::ARMRegisters::d3);
360     /* FIXME: Temporary hack until FPRegister allocation exists. */
361     static const FPRegisterID First  = JSC::ARMRegisters::d0;
362     static const FPRegisterID Second = JSC::ARMRegisters::d1;
363     static const FPRegisterID Temp0 = JSC::ARMRegisters::d2;
364     static const FPRegisterID Temp1 = JSC::ARMRegisters::d3;
365 #else
366 # error "Unsupported platform"
367 #endif
368
369     static const uint32 AvailFPRegs = TempFPRegs;
370
371     FPRegisters()
372       : freeFPMask(AvailFPRegs)
373     { }
374
375     FPRegisters(uint32 freeFPMask)
376       : freeFPMask(freeFPMask)
377     { }
378
379     FPRegisters(const FPRegisters &other)
380       : freeFPMask(other.freeFPMask)
381     { }
382
383     FPRegisters & operator =(const FPRegisters &other)
384     {
385         freeFPMask = other.freeFPMask;
386         return *this;
387     }
388
389     void reset() {
390         freeFPMask = AvailFPRegs;
391     }
392
393     bool empty() const {
394         return !freeFPMask;
395     }
396
397     bool empty(uint32 mask) const {
398         return !(freeFPMask & mask);
399     }
400
401     FPRegisterID takeAnyReg() {
402         JS_ASSERT(!empty());
403         int ireg;
404         JS_FLOOR_LOG2(ireg, freeFPMask);
405         FPRegisterID reg = (FPRegisterID)ireg;
406         takeReg(reg);
407         return reg;
408     }
409
410     bool hasRegInMask(uint32 mask) const {
411         FPRegisters temp(freeFPMask & mask);
412         return !temp.empty();
413     }
414
415     FPRegisterID takeRegInMask(uint32 mask) {
416         FPRegisters temp(freeFPMask & mask);
417         FPRegisterID reg = temp.takeAnyReg();
418         takeReg(reg);
419         return reg;
420     }
421
422     bool hasReg(FPRegisterID fpreg) const {
423         return !!(freeFPMask & (1 << fpreg));
424     }
425
426     void putRegUnchecked(FPRegisterID fpreg) {
427         freeFPMask |= (1 << fpreg);
428     }
429
430     void putReg(FPRegisterID fpreg) {
431         JS_ASSERT(!hasReg(fpreg));
432         putRegUnchecked(fpreg);
433     }
434
435     void takeReg(FPRegisterID fpreg) {
436         JS_ASSERT(hasReg(fpreg));
437         freeFPMask &= ~(1 << fpreg);
438     }
439
440     bool operator ==(const FPRegisters &other) {
441         return freeFPMask == other.freeFPMask;
442     }
443
444     uint32 freeFPMask;
445 };
446
447 static const JSC::MacroAssembler::RegisterID JSFrameReg = Registers::JSFrameReg;
448
449 } /* namespace mjit */
450
451 } /* namespace js */
452
453 #endif /* jsjaeger_regstate_h__ */
454