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 : #include "vm/Stack.h"
47 :
48 : namespace js {
49 : namespace mjit {
50 :
51 : // Lightweight, union-able components of FrameEntry.
52 : struct StateRemat {
53 : typedef JSC::MacroAssembler::RegisterID RegisterID;
54 : typedef JSC::MacroAssembler::Address Address;
55 :
56 : static const int32_t CONSTANT = -int(UINT16_LIMIT * sizeof(Value));
57 :
58 : // This union encodes the fastest rematerialization of a non-constant
59 : // value. The |offset| field can be used to recover information
60 : // without this struct's helpers:
61 : // 1) A value in (CONSTANT, 0) is an argument slot.
62 : // 2) A value in [0, fp) is a register ID.
63 : // 3) A value in [fp, inf) is a local slot.
64 : union {
65 : RegisterID reg_;
66 : int32_t offset_;
67 : };
68 :
69 500164 : static StateRemat FromInt32(int32_t i32) {
70 : StateRemat sr;
71 500164 : sr.offset_ = i32;
72 : return sr;
73 : }
74 154845 : static StateRemat FromRegister(RegisterID reg) {
75 : StateRemat sr;
76 154845 : sr.reg_ = reg;
77 154845 : JS_ASSERT(sr.inRegister());
78 : return sr;
79 : }
80 1319 : static StateRemat FromAddress(Address address) {
81 1319 : JS_ASSERT(address.base == JSFrameReg);
82 : StateRemat sr;
83 1319 : sr.offset_ = address.offset;
84 1319 : JS_ASSERT(sr.inMemory());
85 : return sr;
86 : }
87 :
88 : // Minimum number of bits needed to compactly store the int32_t
89 : // representation in a struct or union. This prevents bloating the IC
90 : // structs by an extra 8 bytes in some cases. 16 bits are needed to encode
91 : // the largest local:
92 : // ((UINT16_LIMIT - 1) * sizeof(Value) + sizeof(StackFrame),
93 : // And an extra bit for the sign on arguments.
94 : #define MIN_STATE_REMAT_BITS 21
95 :
96 : bool isConstant() const { return offset_ == CONSTANT; }
97 654666 : bool inRegister() const { return offset_ >= 0 &&
98 654666 : offset_ <= int32_t(JSC::MacroAssembler::TotalRegisters); }
99 2841 : bool inMemory() const {
100 : return offset_ >= int32_t(sizeof(StackFrame)) ||
101 2841 : offset_ < 0;
102 : }
103 :
104 161856 : int32_t toInt32() const { return offset_; }
105 343 : Address address() const {
106 343 : JS_ASSERT(inMemory());
107 343 : return Address(JSFrameReg, offset_);
108 : }
109 499821 : RegisterID reg() const {
110 499821 : JS_ASSERT(inRegister());
111 499821 : return reg_;
112 : }
113 : };
114 :
115 : /* Lightweight version of FrameEntry. */
116 : struct ValueRemat {
117 : typedef JSC::MacroAssembler::RegisterID RegisterID;
118 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
119 : union {
120 : struct {
121 : union {
122 : int32_t typeRemat_;
123 : JSValueType knownType_;
124 : } type;
125 : int32_t dataRemat_ : MIN_STATE_REMAT_BITS;
126 : bool isTypeKnown_ : 1;
127 : } s;
128 : jsval v_;
129 : FPRegisterID fpreg_;
130 : } u;
131 : bool isConstant_ : 1;
132 : bool isFPRegister_ : 1;
133 : bool isDataSynced : 1;
134 : bool isTypeSynced : 1;
135 :
136 34416 : static ValueRemat FromConstant(const Value &v) {
137 : ValueRemat vr;
138 34416 : vr.isConstant_ = true;
139 34416 : vr.isFPRegister_ = false;
140 34416 : vr.u.v_ = v;
141 : return vr;
142 : }
143 1462 : static ValueRemat FromFPRegister(FPRegisterID fpreg) {
144 : ValueRemat vr;
145 1462 : vr.isConstant_ = false;
146 1462 : vr.isFPRegister_ = true;
147 1462 : vr.u.fpreg_ = fpreg;
148 : return vr;
149 : }
150 34516 : static ValueRemat FromKnownType(JSValueType type, RegisterID dataReg) {
151 : ValueRemat vr;
152 34516 : vr.isConstant_ = false;
153 34516 : vr.isFPRegister_ = false;
154 34516 : vr.u.s.type.knownType_ = type;
155 34516 : vr.u.s.isTypeKnown_ = true;
156 34516 : vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
157 :
158 : // Assert bitfields are okay.
159 34516 : JS_ASSERT(vr.dataReg() == dataReg);
160 : return vr;
161 : }
162 57978 : static ValueRemat FromRegisters(RegisterID typeReg, RegisterID dataReg) {
163 : ValueRemat vr;
164 57978 : vr.isConstant_ = false;
165 57978 : vr.isFPRegister_ = false;
166 57978 : vr.u.s.isTypeKnown_ = false;
167 57978 : vr.u.s.type.typeRemat_ = StateRemat::FromRegister(typeReg).toInt32();
168 57978 : vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
169 :
170 : // Assert bitfields are okay.
171 57978 : JS_ASSERT(vr.dataReg() == dataReg);
172 57978 : JS_ASSERT(vr.typeReg() == typeReg);
173 : return vr;
174 : }
175 :
176 2841 : FPRegisterID fpReg() const {
177 2841 : JS_ASSERT(isFPRegister());
178 2841 : return u.fpreg_;
179 : }
180 285951 : RegisterID dataReg() const {
181 285951 : JS_ASSERT(!isConstant() && !isFPRegister());
182 285951 : return dataRemat().reg();
183 : }
184 213034 : RegisterID typeReg() const {
185 213034 : JS_ASSERT(!isTypeKnown());
186 213034 : return typeRemat().reg();
187 : }
188 :
189 1606856 : bool isConstant() const { return isConstant_; }
190 1172455 : bool isFPRegister() const { return isFPRegister_; }
191 718639 : bool isTypeKnown() const { return isConstant() || isFPRegister() || u.s.isTypeKnown_; }
192 :
193 285951 : StateRemat dataRemat() const {
194 285951 : JS_ASSERT(!isConstant());
195 285951 : return StateRemat::FromInt32(u.s.dataRemat_);
196 : }
197 213034 : StateRemat typeRemat() const {
198 213034 : JS_ASSERT(!isTypeKnown());
199 213034 : return StateRemat::FromInt32(u.s.type.typeRemat_);
200 : }
201 39126 : Value value() const {
202 39126 : JS_ASSERT(isConstant());
203 39126 : return u.v_;
204 : }
205 49734 : JSValueType knownType() const {
206 49734 : JS_ASSERT(isTypeKnown());
207 49734 : if (isConstant()) {
208 10491 : const Value v = value();
209 10491 : if (v.isDouble())
210 221 : return JSVAL_TYPE_DOUBLE;
211 10270 : return v.extractNonDoubleType();
212 : }
213 39243 : if (isFPRegister())
214 0 : return JSVAL_TYPE_DOUBLE;
215 39243 : return u.s.type.knownType_;
216 : }
217 11673 : bool isType(JSValueType type_) const {
218 11673 : return isTypeKnown() && knownType() == type_;
219 : }
220 : };
221 :
222 : /*
223 : * Describes how to rematerialize a value during compilation.
224 : */
225 : struct RematInfo {
226 : typedef JSC::MacroAssembler::RegisterID RegisterID;
227 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
228 :
229 : enum SyncState {
230 : SYNCED,
231 : UNSYNCED
232 : };
233 :
234 : enum RematType {
235 : TYPE,
236 : DATA
237 : };
238 :
239 : /* Physical location. */
240 : enum PhysLoc {
241 : /*
242 : * Backing bits are in memory. No fast remat.
243 : */
244 : PhysLoc_Memory = 0,
245 :
246 : /* Backing bits are known at compile time. */
247 : PhysLoc_Constant,
248 :
249 : /* Backing bits are in a general purpose register. */
250 : PhysLoc_Register,
251 :
252 : /* Backing bits are part of a floating point register. */
253 : PhysLoc_FPRegister,
254 :
255 : /* Backing bits are invalid/unknown. */
256 : PhysLoc_Invalid
257 : };
258 :
259 10459409 : void setRegister(RegisterID reg) {
260 10459409 : reg_ = reg;
261 10459409 : location_ = PhysLoc_Register;
262 10459409 : }
263 :
264 135110621 : RegisterID reg() const {
265 135110621 : JS_ASSERT(inRegister());
266 135110621 : return reg_;
267 : }
268 :
269 23702 : void setFPRegister(FPRegisterID reg) {
270 23702 : fpreg_ = reg;
271 23702 : location_ = PhysLoc_FPRegister;
272 23702 : }
273 :
274 473919 : FPRegisterID fpreg() const {
275 473919 : JS_ASSERT(inFPRegister());
276 473919 : return fpreg_;
277 : }
278 :
279 11326948 : void setMemory() {
280 11326948 : location_ = PhysLoc_Memory;
281 11326948 : sync_ = SYNCED;
282 11326948 : }
283 :
284 : #ifdef DEBUG
285 65645894 : void invalidate() {
286 65645894 : location_ = PhysLoc_Invalid;
287 65645894 : }
288 : #else
289 : void invalidate() {}
290 : #endif
291 :
292 7349451 : void setConstant() { location_ = PhysLoc_Constant; }
293 :
294 166848659 : bool isConstant() const {
295 166848659 : JS_ASSERT(location_ != PhysLoc_Invalid);
296 166848659 : return location_ == PhysLoc_Constant;
297 : }
298 :
299 1109781667 : bool inRegister() const {
300 1109781667 : JS_ASSERT(location_ != PhysLoc_Invalid);
301 1109781667 : return location_ == PhysLoc_Register;
302 : }
303 :
304 449677916 : bool inFPRegister() const {
305 449677916 : JS_ASSERT(location_ != PhysLoc_Invalid);
306 449677916 : return location_ == PhysLoc_FPRegister;
307 : }
308 :
309 15798178 : bool inMemory() const {
310 15798178 : JS_ASSERT(location_ != PhysLoc_Invalid);
311 15798178 : return location_ == PhysLoc_Memory;
312 : }
313 :
314 74391675 : bool synced() const { return sync_ == SYNCED; }
315 6109344 : void sync() {
316 6109344 : JS_ASSERT(!synced());
317 6109344 : sync_ = SYNCED;
318 6109344 : }
319 25270393 : void unsync() {
320 25270393 : sync_ = UNSYNCED;
321 25270393 : }
322 :
323 973326 : void inherit(const RematInfo &other) {
324 : JS_STATIC_ASSERT(sizeof(RegisterID) == sizeof(FPRegisterID));
325 973326 : reg_ = other.reg_;
326 973326 : location_ = other.location_;
327 973326 : }
328 :
329 : private:
330 : union {
331 : /* Set if location is PhysLoc_Register. */
332 : RegisterID reg_;
333 :
334 : /*
335 : * Set if location is PhysLoc_FPRegister. This must be the data for a FE,
336 : * and the known type is JSVAL_TYPE_DOUBLE.
337 : */
338 : FPRegisterID fpreg_;
339 : };
340 :
341 : /* Remat source. */
342 : PhysLoc location_;
343 :
344 : /* Sync state. */
345 : SyncState sync_;
346 : };
347 :
348 : template <class T>
349 : class MaybeRegister {
350 : public:
351 4840942 : MaybeRegister()
352 4840942 : : reg_((T)0), set(false)
353 4840942 : { }
354 :
355 270824 : MaybeRegister(T reg)
356 270824 : : reg_(reg), set(true)
357 270824 : { }
358 :
359 10832865 : inline T reg() const { JS_ASSERT(set); return reg_; }
360 3199430 : inline void setReg(T r) { reg_ = r; set = true; }
361 6744310 : inline bool isSet() const { return set; }
362 :
363 164322 : MaybeRegister<T> & operator =(const MaybeRegister<T> &other) {
364 164322 : set = other.set;
365 164322 : reg_ = other.reg_;
366 164322 : return *this;
367 : }
368 :
369 3197076 : MaybeRegister<T> & operator =(T r) {
370 3197076 : setReg(r);
371 3197076 : return *this;
372 : }
373 :
374 : private:
375 : T reg_;
376 : bool set;
377 : };
378 :
379 : typedef MaybeRegister<JSC::MacroAssembler::RegisterID> MaybeRegisterID;
380 : typedef MaybeRegister<JSC::MacroAssembler::FPRegisterID> MaybeFPRegisterID;
381 :
382 : class MaybeJump {
383 : typedef JSC::MacroAssembler::Jump Jump;
384 : public:
385 8039523 : MaybeJump()
386 8039523 : : set(false)
387 8039523 : { }
388 :
389 35568 : inline Jump getJump() const { JS_ASSERT(set); return jump; }
390 4111735 : inline Jump get() const { JS_ASSERT(set); return jump; }
391 4127031 : inline void setJump(const Jump &j) { jump = j; set = true; }
392 6628684 : inline bool isSet() const { return set; }
393 :
394 3906684 : inline MaybeJump &operator=(Jump j) { setJump(j); return *this; }
395 :
396 : private:
397 : Jump jump;
398 : bool set;
399 : };
400 :
401 : } /* namespace mjit */
402 : } /* namespace js */
403 :
404 : #endif
405 :
|