Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / methodjit / RematInfo.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_remat_h__ && defined JS_METHODJIT
41 #define jsjaeger_remat_h__
42
43 #include "jscntxt.h"
44 #include "MachineRegs.h"
45 #include "assembler/assembler/MacroAssembler.h"
46
47 namespace js {
48 namespace mjit {
49
50 // Lightweight, union-able components of FrameEntry.
51 struct StateRemat {
52     typedef JSC::MacroAssembler::RegisterID RegisterID;
53     typedef JSC::MacroAssembler::Address Address;
54
55     static const int32 CONSTANT = -int(UINT16_LIMIT * sizeof(Value));
56
57     // This union encodes the fastest rematerialization of a non-constant
58     // value. The |offset| field can be used to recover information
59     // without this struct's helpers:
60     //  1) A value in (CONSTANT, 0) is an argument slot.
61     //  2) A value in [0, fp) is a register ID.
62     //  3) A value in [fp, inf) is a local slot.
63     union {
64         RegisterID  reg_;
65         int32       offset_;
66     };
67
68     static StateRemat FromInt32(int32 i32) {
69         StateRemat sr;
70         sr.offset_ = i32;
71         return sr;
72     }
73     static StateRemat FromRegister(RegisterID reg) {
74         StateRemat sr;
75         sr.reg_ = reg;
76         JS_ASSERT(sr.inRegister());
77         return sr;
78     }
79     static StateRemat FromAddress(Address address) {
80         JS_ASSERT(address.base == JSFrameReg);
81         StateRemat sr;
82         sr.offset_ = address.offset;
83         JS_ASSERT(sr.inMemory());
84         return sr;
85     }
86
87     // Minimum number of bits needed to compactly store the int32
88     // representation in a struct or union. This prevents bloating the IC
89     // structs by an extra 8 bytes in some cases. 16 bits are needed to encode
90     // the largest local:
91     //   ((UINT16_LIMIT - 1) * sizeof(Value) + sizeof(JSStackFrame),
92     // And an extra bit for the sign on arguments.
93 #define MIN_STATE_REMAT_BITS        21
94
95     bool isConstant() const { return offset_ == CONSTANT; }
96     bool inRegister() const { return offset_ >= 0 &&
97                                      offset_ <= int32(JSC::MacroAssembler::TotalRegisters); }
98     bool inMemory() const {
99         return offset_ >= int32(sizeof(JSStackFrame)) ||
100                offset_ < 0;
101     }
102
103     int32 toInt32() const { return offset_; }
104     Address address() const {
105         JS_ASSERT(inMemory());
106         return Address(JSFrameReg, offset_);
107     }
108     RegisterID reg() const {
109         JS_ASSERT(inRegister());
110         return reg_;
111     }
112 };
113
114 /* Lightweight version of FrameEntry. */
115 struct ValueRemat {
116     typedef JSC::MacroAssembler::RegisterID RegisterID;
117     union {
118         struct {
119             union {
120                 int32       typeRemat_;
121                 JSValueType knownType_;
122             } type;
123             int32   dataRemat_   : MIN_STATE_REMAT_BITS;
124             bool    isTypeKnown_ : 1;
125         } s;
126         jsval v_;
127     } u;
128     bool isConstant_    : 1;
129     bool isDataSynced   : 1;
130     bool isTypeSynced   : 1;
131
132     static ValueRemat FromConstant(const Value &v) {
133         ValueRemat vr;
134         vr.isConstant_ = true;
135         vr.u.v_ = Jsvalify(v);
136         return vr;
137     }
138     static ValueRemat FromKnownType(JSValueType type, RegisterID dataReg) {
139         ValueRemat vr;
140         vr.isConstant_ = false;
141         vr.u.s.type.knownType_ = type;
142         vr.u.s.isTypeKnown_ = true;
143         vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
144
145         // Assert bitfields are okay.
146         JS_ASSERT(vr.dataReg() == dataReg);
147         return vr;
148     }
149     static ValueRemat FromRegisters(RegisterID typeReg, RegisterID dataReg) {
150         ValueRemat vr;
151         vr.isConstant_ = false;
152         vr.u.s.isTypeKnown_ = false;
153         vr.u.s.type.typeRemat_ = StateRemat::FromRegister(typeReg).toInt32();
154         vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
155
156         // Assert bitfields are okay.
157         JS_ASSERT(vr.dataReg() == dataReg);
158         JS_ASSERT(vr.typeReg() == typeReg);
159         return vr;
160     }
161
162     RegisterID dataReg() const {
163         JS_ASSERT(!isConstant());
164         return dataRemat().reg();
165     }
166     RegisterID typeReg() const {
167         JS_ASSERT(!isTypeKnown());
168         return typeRemat().reg();
169     }
170
171     bool isConstant() const { return isConstant_; }
172     bool isTypeKnown() const { return isConstant() || u.s.isTypeKnown_; }
173
174     StateRemat dataRemat() const {
175         JS_ASSERT(!isConstant());
176         return StateRemat::FromInt32(u.s.dataRemat_);
177     }
178     StateRemat typeRemat() const {
179         JS_ASSERT(!isTypeKnown());
180         return StateRemat::FromInt32(u.s.type.typeRemat_);
181     }
182     Value value() const {
183         JS_ASSERT(isConstant());
184         return Valueify(u.v_);
185     }
186     JSValueType knownType() const {
187         JS_ASSERT(isTypeKnown());
188         if (isConstant()) {
189             const Value v = value();
190             if (v.isDouble())
191                 return JSVAL_TYPE_DOUBLE;
192             return v.extractNonDoubleType();
193         }
194         return u.s.type.knownType_;
195     }
196     bool isType(JSValueType type_) const {
197         return isTypeKnown() && knownType() == type_;
198     }
199 };
200
201 /*
202  * Describes how to rematerialize a value during compilation.
203  */
204 struct RematInfo {
205     typedef JSC::MacroAssembler::RegisterID RegisterID;
206
207     enum SyncState {
208         SYNCED,
209         UNSYNCED
210     };
211
212     enum RematType {
213         TYPE,
214         DATA
215     };
216
217     /* Physical location. */
218     enum PhysLoc {
219         /*
220          * Backing bits are in memory. No fast remat.
221          */
222         PhysLoc_Memory = 0,
223
224         /* Backing bits are known at compile time. */
225         PhysLoc_Constant,
226
227         /* Backing bits are in a register. */
228         PhysLoc_Register,
229
230         /* Backing bits are invalid/unknown. */
231         PhysLoc_Invalid
232     };
233
234     void setRegister(RegisterID reg) {
235         reg_ = reg;
236         location_ = PhysLoc_Register;
237     }
238
239     RegisterID reg() const {
240         JS_ASSERT(inRegister());
241         return reg_;
242     }
243
244     void setMemory() {
245         location_ = PhysLoc_Memory;
246         sync_ = SYNCED;
247     }
248
249     void invalidate() {
250         location_ = PhysLoc_Invalid;
251     }
252
253     void setConstant() { location_ = PhysLoc_Constant; }
254
255     bool isConstant() const { return location_ == PhysLoc_Constant; }
256     bool inRegister() const { return location_ == PhysLoc_Register; }
257     bool inMemory() const { return location_ == PhysLoc_Memory; }
258     bool synced() const { return sync_ == SYNCED; }
259     void sync() {
260         JS_ASSERT(!synced());
261         sync_ = SYNCED;
262     }
263     void unsync() {
264         sync_ = UNSYNCED;
265     }
266
267     void inherit(const RematInfo &other) {
268         reg_ = other.reg_;
269         location_ = other.location_;
270     }
271
272   private:
273     /* Set if location is PhysLoc_Register. */
274     RegisterID reg_;
275
276     /* Remat source. */
277     PhysLoc location_;
278
279     /* Sync state. */
280     SyncState sync_;
281 };
282
283 } /* namespace mjit */
284 } /* namespace js */
285
286 #endif
287