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 499914 : static StateRemat FromInt32(int32_t i32) {
70 : StateRemat sr;
71 499914 : sr.offset_ = i32;
72 : return sr;
73 : }
74 154777 : static StateRemat FromRegister(RegisterID reg) {
75 : StateRemat sr;
76 154777 : sr.reg_ = reg;
77 154777 : 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 654348 : bool inRegister() const { return offset_ >= 0 &&
98 654348 : 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 161788 : int32_t toInt32() const { return offset_; }
105 343 : Address address() const {
106 343 : JS_ASSERT(inMemory());
107 343 : return Address(JSFrameReg, offset_);
108 : }
109 499571 : RegisterID reg() const {
110 499571 : JS_ASSERT(inRegister());
111 499571 : 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 34419 : static ValueRemat FromConstant(const Value &v) {
137 : ValueRemat vr;
138 34419 : vr.isConstant_ = true;
139 34419 : vr.isFPRegister_ = false;
140 34419 : 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 34522 : static ValueRemat FromKnownType(JSValueType type, RegisterID dataReg) {
151 : ValueRemat vr;
152 34522 : vr.isConstant_ = false;
153 34522 : vr.isFPRegister_ = false;
154 34522 : vr.u.s.type.knownType_ = type;
155 34522 : vr.u.s.isTypeKnown_ = true;
156 34522 : vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
157 :
158 : // Assert bitfields are okay.
159 34522 : JS_ASSERT(vr.dataReg() == dataReg);
160 : return vr;
161 : }
162 57941 : static ValueRemat FromRegisters(RegisterID typeReg, RegisterID dataReg) {
163 : ValueRemat vr;
164 57941 : vr.isConstant_ = false;
165 57941 : vr.isFPRegister_ = false;
166 57941 : vr.u.s.isTypeKnown_ = false;
167 57941 : vr.u.s.type.typeRemat_ = StateRemat::FromRegister(typeReg).toInt32();
168 57941 : vr.u.s.dataRemat_ = StateRemat::FromRegister(dataReg).toInt32();
169 :
170 : // Assert bitfields are okay.
171 57941 : JS_ASSERT(vr.dataReg() == dataReg);
172 57941 : 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 285852 : RegisterID dataReg() const {
181 285852 : JS_ASSERT(!isConstant() && !isFPRegister());
182 285852 : return dataRemat().reg();
183 : }
184 212883 : RegisterID typeReg() const {
185 212883 : JS_ASSERT(!isTypeKnown());
186 212883 : return typeRemat().reg();
187 : }
188 :
189 1606278 : bool isConstant() const { return isConstant_; }
190 1171995 : bool isFPRegister() const { return isFPRegister_; }
191 718295 : bool isTypeKnown() const { return isConstant() || isFPRegister() || u.s.isTypeKnown_; }
192 :
193 285852 : StateRemat dataRemat() const {
194 285852 : JS_ASSERT(!isConstant());
195 285852 : return StateRemat::FromInt32(u.s.dataRemat_);
196 : }
197 212883 : StateRemat typeRemat() const {
198 212883 : JS_ASSERT(!isTypeKnown());
199 212883 : 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 49738 : JSValueType knownType() const {
206 49738 : JS_ASSERT(isTypeKnown());
207 49738 : if (isConstant()) {
208 10489 : const Value v = value();
209 10489 : if (v.isDouble())
210 221 : return JSVAL_TYPE_DOUBLE;
211 10268 : return v.extractNonDoubleType();
212 : }
213 39249 : if (isFPRegister())
214 0 : return JSVAL_TYPE_DOUBLE;
215 39249 : return u.s.type.knownType_;
216 : }
217 11666 : bool isType(JSValueType type_) const {
218 11666 : 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 10455594 : void setRegister(RegisterID reg) {
260 10455594 : reg_ = reg;
261 10455594 : location_ = PhysLoc_Register;
262 10455594 : }
263 :
264 135072211 : RegisterID reg() const {
265 135072211 : JS_ASSERT(inRegister());
266 135072211 : 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 11323833 : void setMemory() {
280 11323833 : location_ = PhysLoc_Memory;
281 11323833 : sync_ = SYNCED;
282 11323833 : }
283 :
284 : #ifdef DEBUG
285 65620090 : void invalidate() {
286 65620090 : location_ = PhysLoc_Invalid;
287 65620090 : }
288 : #else
289 : void invalidate() {}
290 : #endif
291 :
292 7347251 : void setConstant() { location_ = PhysLoc_Constant; }
293 :
294 166800945 : bool isConstant() const {
295 166800945 : JS_ASSERT(location_ != PhysLoc_Invalid);
296 166800945 : return location_ == PhysLoc_Constant;
297 : }
298 :
299 1109692249 : bool inRegister() const {
300 1109692249 : JS_ASSERT(location_ != PhysLoc_Invalid);
301 1109692249 : return location_ == PhysLoc_Register;
302 : }
303 :
304 449661502 : bool inFPRegister() const {
305 449661502 : JS_ASSERT(location_ != PhysLoc_Invalid);
306 449661502 : return location_ == PhysLoc_FPRegister;
307 : }
308 :
309 15792655 : bool inMemory() const {
310 15792655 : JS_ASSERT(location_ != PhysLoc_Invalid);
311 15792655 : return location_ == PhysLoc_Memory;
312 : }
313 :
314 74371928 : bool synced() const { return sync_ == SYNCED; }
315 6107199 : void sync() {
316 6107199 : JS_ASSERT(!synced());
317 6107199 : sync_ = SYNCED;
318 6107199 : }
319 25260165 : void unsync() {
320 25260165 : sync_ = UNSYNCED;
321 25260165 : }
322 :
323 972834 : void inherit(const RematInfo &other) {
324 : JS_STATIC_ASSERT(sizeof(RegisterID) == sizeof(FPRegisterID));
325 972834 : reg_ = other.reg_;
326 972834 : location_ = other.location_;
327 972834 : }
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 4840118 : MaybeRegister()
352 4840118 : : reg_((T)0), set(false)
353 4840118 : { }
354 :
355 270820 : MaybeRegister(T reg)
356 270820 : : reg_(reg), set(true)
357 270820 : { }
358 :
359 10831767 : inline T reg() const { JS_ASSERT(set); return reg_; }
360 3199162 : inline void setReg(T r) { reg_ = r; set = true; }
361 6743253 : inline bool isSet() const { return set; }
362 :
363 164348 : MaybeRegister<T> & operator =(const MaybeRegister<T> &other) {
364 164348 : set = other.set;
365 164348 : reg_ = other.reg_;
366 164348 : return *this;
367 : }
368 :
369 3196808 : MaybeRegister<T> & operator =(T r) {
370 3196808 : setReg(r);
371 3196808 : 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 8037742 : MaybeJump()
386 8037742 : : set(false)
387 8037742 : { }
388 :
389 35562 : inline Jump getJump() const { JS_ASSERT(set); return jump; }
390 4111040 : inline Jump get() const { JS_ASSERT(set); return jump; }
391 4126330 : inline void setJump(const Jump &j) { jump = j; set = true; }
392 6627198 : inline bool isSet() const { return set; }
393 :
394 3905985 : 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 :
|