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_framestate_h__ && defined JS_METHODJIT
41 : #define jsjaeger_framestate_h__
42 :
43 : #include "jsanalyze.h"
44 : #include "jsapi.h"
45 : #include "methodjit/MachineRegs.h"
46 : #include "methodjit/FrameEntry.h"
47 : #include "CodeGenIncludes.h"
48 : #include "ImmutableSync.h"
49 : #include "jscompartment.h"
50 :
51 : namespace js {
52 : namespace mjit {
53 :
54 : struct Uses {
55 13075680 : explicit Uses(uint32_t nuses)
56 13075680 : : nuses(nuses)
57 13075680 : { }
58 : uint32_t nuses;
59 : };
60 :
61 : struct Changes {
62 3017272 : explicit Changes(uint32_t nchanges)
63 3017272 : : nchanges(nchanges)
64 3017272 : { }
65 : uint32_t nchanges;
66 : };
67 :
68 130 : struct TemporaryCopy {
69 110 : TemporaryCopy(JSC::MacroAssembler::Address copy, JSC::MacroAssembler::Address temporary)
70 110 : : copy(copy), temporary(temporary)
71 110 : {}
72 : JSC::MacroAssembler::Address copy;
73 : JSC::MacroAssembler::Address temporary;
74 : };
75 :
76 : class StubCompiler;
77 : class LoopState;
78 :
79 : /*
80 : * The FrameState keeps track of values on the frame during compilation.
81 : * The compiler can query FrameState for information about arguments, locals,
82 : * and stack slots (all hereby referred to as "slots"). Slot information can
83 : * be requested in constant time. For each slot there is a FrameEntry *. If
84 : * this is non-NULL, it contains valid information and can be returned.
85 : *
86 : * The register allocator keeps track of registers as being in one of two
87 : * states. These are:
88 : *
89 : * 1) Unowned. Some code in the compiler is working on a register.
90 : * 2) Owned. The FrameState owns the register, and may spill it at any time.
91 : *
92 : * ------------------ Implementation Details ------------------
93 : *
94 : * Observations:
95 : *
96 : * 1) Every time we need a slow call, we must sync everything.
97 : * 2) Efficient side-exits need to quickly deltize state snapshots.
98 : * 3) Syncing is limited to constants and registers.
99 : * 4) Entries are not forgotten unless they are entirely in memory and are
100 : * not constants or copies.
101 : *
102 : * With these in mind, we want to make sure that the compiler doesn't degrade
103 : * badly as functions get larger.
104 : *
105 : * If the FE is NULL, a new one is allocated, initialized, and stored. They
106 : * are allocated from a pool such that (fe - pool) can be used to compute
107 : * the slot's Address.
108 : *
109 : * We keep a side vector of all tracked FrameEntry * to quickly generate
110 : * memory stores and clear the tracker.
111 : *
112 : * It is still possible to get really bad behavior with a very large script
113 : * that doesn't have branches or calls. That's okay, having this code in
114 : * minimizes damage and lets us introduce a hard cut-off point.
115 : */
116 : class FrameState
117 : {
118 : friend class ImmutableSync;
119 :
120 : typedef JSC::MacroAssembler::RegisterID RegisterID;
121 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
122 : typedef JSC::MacroAssembler::Address Address;
123 : typedef JSC::MacroAssembler::AbsoluteAddress AbsoluteAddress;
124 : typedef JSC::MacroAssembler::Jump Jump;
125 : typedef JSC::MacroAssembler::Imm32 Imm32;
126 : typedef JSC::MacroAssembler::ImmPtr ImmPtr;
127 :
128 : static const uint32_t InvalidIndex = 0xFFFFFFFF;
129 :
130 : struct Tracker {
131 134091 : Tracker()
132 134091 : : entries(NULL), nentries(0)
133 134091 : { }
134 :
135 2606451 : void add(FrameEntry *fe) {
136 2606451 : entries[nentries++] = fe;
137 2606451 : }
138 :
139 1018153 : void reset() {
140 1018153 : nentries = 0;
141 1018153 : }
142 :
143 507223394 : FrameEntry * operator [](uint32_t n) const {
144 507223394 : JS_ASSERT(n < nentries);
145 507223394 : return entries[n];
146 : }
147 :
148 : FrameEntry **entries;
149 : uint32_t nentries;
150 : };
151 :
152 : /*
153 : * Some RegisterState invariants.
154 : *
155 : * If |fe| is non-NULL, |save| is NULL.
156 : * If |save| is non-NULL, |fe| is NULL.
157 : * That is, both |fe| and |save| cannot be non-NULL.
158 : *
159 : * If either |fe| or |save| is non-NULL, the register is not in freeRegs.
160 : * If both |fe| and |save| are NULL, the register is either in freeRegs,
161 : * or owned by the compiler.
162 : */
163 : struct RegisterState {
164 2011365 : RegisterState() : fe_(NULL), save_(NULL)
165 2011365 : { }
166 :
167 : RegisterState(FrameEntry *fe, RematInfo::RematType type)
168 : : fe_(fe), save_(NULL), type_(type)
169 : {
170 : JS_ASSERT(!save_);
171 : }
172 :
173 279171784 : bool isPinned() const {
174 279171784 : assertConsistency();
175 279171784 : return !!save_;
176 : }
177 :
178 1025142387 : void assertConsistency() const {
179 1025142387 : JS_ASSERT_IF(fe_, !save_);
180 1025142387 : JS_ASSERT_IF(save_, !fe_);
181 1025142387 : }
182 :
183 715027854 : FrameEntry *fe() const {
184 715027854 : assertConsistency();
185 715027854 : return fe_;
186 : }
187 :
188 12899418 : RematInfo::RematType type() const {
189 12899418 : assertConsistency();
190 12899418 : return type_;
191 : }
192 :
193 70358595 : FrameEntry *usedBy() const {
194 70358595 : if (fe_)
195 15512400 : return fe_;
196 54846195 : return save_;
197 : }
198 :
199 6697117 : void associate(FrameEntry *fe, RematInfo::RematType type) {
200 6697117 : JS_ASSERT(!fe_);
201 6697117 : JS_ASSERT(!save_);
202 :
203 6697117 : fe_ = fe;
204 6697117 : type_ = type;
205 6697117 : }
206 :
207 : /* Change ownership. */
208 4760343 : void reassociate(FrameEntry *fe) {
209 4760343 : assertConsistency();
210 4760343 : JS_ASSERT(fe);
211 :
212 4760343 : fe_ = fe;
213 4760343 : }
214 :
215 : /* Unassociate this register from the FE. */
216 6221401 : void forget() {
217 6221401 : JS_ASSERT(fe_);
218 6221401 : fe_ = NULL;
219 6221401 : JS_ASSERT(!save_);
220 6221401 : }
221 :
222 6667079 : void pin() {
223 6667079 : JS_ASSERT(fe_ != NULL);
224 6667079 : assertConsistency();
225 6667079 : save_ = fe_;
226 6667079 : fe_ = NULL;
227 6667079 : }
228 :
229 6271619 : void unpin() {
230 6271619 : JS_ASSERT(save_ != NULL);
231 6271619 : assertConsistency();
232 6271619 : fe_ = save_;
233 6271619 : save_ = NULL;
234 6271619 : }
235 :
236 344290 : void unpinUnsafe() {
237 344290 : assertConsistency();
238 344290 : save_ = NULL;
239 344290 : }
240 :
241 : private:
242 : /* FrameEntry owning this register, or NULL if not owned by a frame. */
243 : FrameEntry *fe_;
244 :
245 : /* Hack - simplifies register allocation for pairs. */
246 : FrameEntry *save_;
247 :
248 : /* Part of the FrameEntry that owns the FE. */
249 : RematInfo::RematType type_;
250 : };
251 :
252 : struct ActiveFrame;
253 :
254 : FrameState *thisFromCtor() { return this; }
255 : public:
256 : FrameState(JSContext *cx, Compiler &cc, Assembler &masm, StubCompiler &stubcc);
257 : ~FrameState();
258 :
259 : /*
260 : * Pushes a synced slot that may have a known type.
261 : */
262 : inline void pushSynced(JSValueType knownType);
263 :
264 : /*
265 : * Pushes a slot that has a known, synced type and payload.
266 : */
267 : inline void pushSynced(JSValueType knownType, RegisterID reg);
268 :
269 : /*
270 : * Pushes a constant value.
271 : */
272 : inline void push(const Value &v);
273 :
274 : /*
275 : * Loads a value from memory and pushes it. If reuseBase is set, the
276 : * Compiler owns the register and it should be reused if possible.
277 : */
278 : inline void push(Address address, JSValueType knownType, bool reuseBase = false);
279 :
280 : /*
281 : * Loads a word from memory and pushes it. If reuseBase is set, the
282 : * Compiler owns the register and it should be reused if possible.
283 : * It takes an address and loads/pushes an unboxed word of a given non-double type.
284 : */
285 : inline void pushWord(Address address, JSValueType knownType, bool reuseBase = false);
286 :
287 : /* Loads a value from memory into a register pair, returning the register. */
288 : inline void loadIntoRegisters(Address address, bool reuseBase,
289 : RegisterID *ptypeReg, RegisterID *pdataReg);
290 :
291 : /*
292 : * Pushes a known type and allocated payload onto the operation stack.
293 : */
294 : inline void pushTypedPayload(JSValueType type, RegisterID payload);
295 :
296 : /*
297 : * Clobbers a stack entry with a type register and data register pair,
298 : * converting to the specified known type if necessary. If the type is
299 : * JSVAL_TYPE_DOUBLE, the registers are converted into a floating point
300 : * register, which is returned.
301 : */
302 : inline FPRegisterID storeRegs(int32_t depth, RegisterID type, RegisterID data,
303 : JSValueType knownType);
304 : inline FPRegisterID pushRegs(RegisterID type, RegisterID data, JSValueType knownType);
305 :
306 : /*
307 : * Load an address into a frame entry in registers. For handling call paths
308 : * where merge() would otherwise reload from the wrong address.
309 : */
310 : inline void reloadEntry(Assembler &masm, Address address, FrameEntry *fe);
311 :
312 : /* Push a value which is definitely a double. */
313 : void pushDouble(FPRegisterID fpreg);
314 : void pushDouble(Address address);
315 :
316 : /* Ensure that fe is definitely a double. It must already be either int or double. */
317 : void ensureDouble(FrameEntry *fe);
318 :
319 : /* Revert an entry just converted to double by ensureDouble. */
320 : void ensureInteger(FrameEntry *fe);
321 :
322 : /*
323 : * Emit code to masm ensuring that all in memory slots thought to be
324 : * doubles are in fact doubles.
325 : */
326 : void ensureInMemoryDoubles(Assembler &masm);
327 :
328 : /* Forget that fe is definitely a double. */
329 : void forgetKnownDouble(FrameEntry *fe);
330 :
331 : /*
332 : * Pushes a known type and allocated payload onto the operation stack.
333 : * This must be used when the type is known, but cannot be propagated
334 : * because it is not known to be correct at a slow-path merge point.
335 : *
336 : * The caller guarantees that the tag was a fast-path check; that is,
337 : * the value it replaces on the stack had the same tag if the fast-path
338 : * was taken.
339 : */
340 : inline void pushUntypedPayload(JSValueType type, RegisterID payload);
341 :
342 : /*
343 : * Pushes a value onto the operation stack. This must be used when the
344 : * value is known, but its type cannot be propagated because it is not
345 : * known to be correct at a slow-path merge point.
346 : */
347 : inline void pushUntypedValue(const Value &value);
348 :
349 : /*
350 : * Pushes a number onto the operation stack.
351 : *
352 : * If asInt32 is set to true, then the FS will attempt to optimize
353 : * syncing the type as int32. Only use this parameter when the fast-path
354 : * guaranteed that the stack slot was guarded to be an int32_t originally.
355 : *
356 : * For example, checking LHS and RHS as ints guarantees that if the LHS
357 : * was synced, then popping both and pushing a maybe-int32_t does not need
358 : * to be synced.
359 : */
360 : inline void pushNumber(RegisterID payload, bool asInt32 = false);
361 :
362 : /*
363 : * Pushes an int32_t onto the operation stack. This is a specialized version
364 : * of pushNumber. The caller must guarantee that (a) an int32_t is to be
365 : * pushed on the inline path, and (b) if any slow path pushes a double,
366 : * the slow path also stores the double to memory.
367 : */
368 : inline void pushInt32(RegisterID payload);
369 :
370 : /*
371 : * Pops a value off the operation stack, freeing any of its resources.
372 : */
373 : inline void pop();
374 :
375 : /*
376 : * Pops a number of values off the operation stack, freeing any of their
377 : * resources.
378 : */
379 : inline void popn(uint32_t n);
380 :
381 : /*
382 : * Returns true iff lhs and rhs are copies of the same FrameEntry.
383 : */
384 : inline bool haveSameBacking(FrameEntry *lhs, FrameEntry *rhs);
385 :
386 : /* If the rhs to a binary operation directly copies the lhs, uncopy the lhs. */
387 : void separateBinaryEntries(FrameEntry *lhs, FrameEntry *rhs);
388 :
389 : /*
390 : * Temporarily increase and decrease local variable depth.
391 : */
392 : inline void enterBlock(uint32_t n);
393 : inline void leaveBlock(uint32_t n);
394 :
395 : // Pushes a copy of a slot (formal argument, local variable, or stack slot)
396 : // onto the operation stack.
397 : void pushLocal(uint32_t n);
398 : void pushArg(uint32_t n);
399 : void pushCallee();
400 : void pushThis();
401 : void pushCopyOf(FrameEntry *fe);
402 : inline void setThis(RegisterID reg);
403 : inline void syncThis();
404 : inline void learnThisIsObject(bool unsync = true);
405 :
406 : inline FrameEntry *getStack(uint32_t slot);
407 : inline FrameEntry *getLocal(uint32_t slot);
408 : inline FrameEntry *getArg(uint32_t slot);
409 : inline FrameEntry *getSlotEntry(uint32_t slot);
410 :
411 : /*
412 : * Allocates a temporary register for a FrameEntry's type. The register
413 : * can be spilled or clobbered by the frame. The compiler may only operate
414 : * on it temporarily, and must take care not to clobber it.
415 : */
416 : inline RegisterID tempRegForType(FrameEntry *fe);
417 :
418 : /*
419 : * Try to use a register already allocated for fe's type, but if one
420 : * is not already available, use fallback.
421 : *
422 : * Note: this does NOT change fe's type-register remat info. It's supposed
423 : * to be a super lightweight/transparent operation.
424 : */
425 : inline RegisterID tempRegForType(FrameEntry *fe, RegisterID fallback);
426 :
427 : inline void loadTypeIntoReg(const FrameEntry *fe, RegisterID reg);
428 : inline void loadDataIntoReg(const FrameEntry *fe, RegisterID reg);
429 :
430 : /*
431 : * Returns a register that is guaranteed to contain the frame entry's
432 : * data payload. The compiler may not modify the contents of the register.
433 : * The compiler should NOT explicitly free it.
434 : */
435 : inline RegisterID tempRegForData(FrameEntry *fe);
436 : inline FPRegisterID tempFPRegForData(FrameEntry *fe);
437 :
438 : /*
439 : * Same as above, except register must match identically.
440 : */
441 : inline AnyRegisterID tempRegInMaskForData(FrameEntry *fe, uint32_t mask);
442 :
443 : /*
444 : * Same as above, except loads into reg (using masm) if the entry does not
445 : * already have a register, and does not change the frame state in doing so.
446 : */
447 : inline RegisterID tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const;
448 :
449 : /*
450 : * For opcodes which expect to operate on an object, forget the entry if it
451 : * is either a known constant or a non-object. This simplifies path
452 : * generation in the Compiler for such unusual cases.
453 : */
454 : inline void forgetMismatchedObject(FrameEntry *fe);
455 :
456 : /*
457 : * Convert an integer to a double without applying
458 : * additional Register pressure.
459 : */
460 : inline void convertInt32ToDouble(Assembler &masm, FrameEntry *fe,
461 : FPRegisterID fpreg) const;
462 :
463 : /*
464 : * Dive into a FrameEntry and check whether it's in a register.
465 : */
466 : inline bool peekTypeInRegister(FrameEntry *fe) const;
467 :
468 : /*
469 : * Allocates a register for a FrameEntry's data, such that the compiler
470 : * can modify it in-place.
471 : *
472 : * The caller guarantees the FrameEntry will not be observed again. This
473 : * allows the compiler to avoid spilling. Only call this if the FE is
474 : * going to be popped before stubcc joins/guards or the end of the current
475 : * opcode.
476 : */
477 : RegisterID ownRegForData(FrameEntry *fe);
478 :
479 : /*
480 : * Allocates a register for a FrameEntry's type, such that the compiler
481 : * can modify it in-place.
482 : *
483 : * The caller guarantees the FrameEntry will not be observed again. This
484 : * allows the compiler to avoid spilling. Only call this if the FE is
485 : * going to be popped before stubcc joins/guards or the end of the current
486 : * opcode.
487 : */
488 : RegisterID ownRegForType(FrameEntry *fe);
489 :
490 : /*
491 : * Allocates a register for a FrameEntry's data, such that the compiler
492 : * can modify it in-place. The actual FE is not modified.
493 : */
494 : RegisterID copyDataIntoReg(FrameEntry *fe);
495 : void copyDataIntoReg(FrameEntry *fe, RegisterID exact);
496 : RegisterID copyDataIntoReg(Assembler &masm, FrameEntry *fe);
497 :
498 : /*
499 : * Allocates a register for a FrameEntry's type, such that the compiler
500 : * can modify it in-place. The actual FE is not modified.
501 : */
502 : RegisterID copyTypeIntoReg(FrameEntry *fe);
503 :
504 : /*
505 : * Returns a register that contains the constant Int32 value of the
506 : * frame entry's data payload.
507 : * Since the register is not bound to a FrameEntry,
508 : * it MUST be explicitly freed with freeReg().
509 : */
510 : RegisterID copyInt32ConstantIntoReg(FrameEntry *fe);
511 : RegisterID copyInt32ConstantIntoReg(Assembler &masm, FrameEntry *fe);
512 :
513 : /*
514 : * Gets registers for the components of fe where needed, pins them and
515 : * stores into vr. If breakDouble is set, vr is guaranteed not to be a
516 : * floating point register.
517 : */
518 : void pinEntry(FrameEntry *fe, ValueRemat &vr, bool breakDouble = true);
519 :
520 : /* Unpins registers from a call to pinEntry. */
521 : void unpinEntry(const ValueRemat &vr);
522 :
523 : /* Syncs fe to memory, given its state as constructed by a call to pinEntry. */
524 : void ensureValueSynced(Assembler &masm, FrameEntry *fe, const ValueRemat &vr);
525 :
526 641906 : struct BinaryAlloc {
527 : MaybeRegisterID lhsType;
528 : MaybeRegisterID lhsData;
529 : MaybeRegisterID rhsType;
530 : MaybeRegisterID rhsData;
531 : MaybeRegisterID extraFree;
532 : RegisterID result; // mutable result reg
533 : FPRegisterID lhsFP; // mutable scratch floating point reg
534 : FPRegisterID rhsFP; // mutable scratch floating point reg
535 : bool resultHasRhs; // whether the result has the RHS instead of the LHS
536 : bool lhsNeedsRemat; // whether LHS needs memory remat
537 : bool rhsNeedsRemat; // whether RHS needs memory remat
538 : bool undoResult; // whether to remat LHS/RHS by undoing operation
539 : };
540 :
541 : /*
542 : * Ensures that the two given FrameEntries have registers for both their
543 : * type and data. The register allocations are returned in a struct.
544 : *
545 : * One mutable register is allocated as well, holding the LHS payload. If
546 : * this would cause a spill that could be avoided by using a mutable RHS,
547 : * and the operation is commutative, then the resultHasRhs is set to true.
548 : */
549 : void allocForBinary(FrameEntry *lhs, FrameEntry *rhs, JSOp op, BinaryAlloc &alloc,
550 : bool resultNeeded = true);
551 :
552 : /*
553 : * After the result register in a BinaryAlloc has been clobbered, rematerialize
554 : * the left or right side if necessary to restore the original values.
555 : */
556 : void rematBinary(FrameEntry *lhs, FrameEntry *rhs, const BinaryAlloc &alloc, Assembler &masm);
557 :
558 : /* Ensures that an FE has both type and data remat'd in registers. */
559 : void ensureFullRegs(FrameEntry *fe, MaybeRegisterID *typeReg, MaybeRegisterID *dataReg);
560 :
561 : /*
562 : * Similar to allocForBinary, except works when the LHS and RHS have the
563 : * same backing FE. Only a reduced subset of BinaryAlloc is used:
564 : * lhsType
565 : * lhsData
566 : * result
567 : * lhsNeedsRemat
568 : */
569 : void allocForSameBinary(FrameEntry *fe, JSOp op, BinaryAlloc &alloc);
570 :
571 : /* Loads an FE into an fp reg. */
572 : inline void loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const;
573 :
574 : /*
575 : * Slightly more specialized version when more precise register
576 : * information is known.
577 : */
578 : inline void loadDouble(RegisterID type, RegisterID data, FrameEntry *fe, FPRegisterID fpReg,
579 : Assembler &masm) const;
580 :
581 : /*
582 : * Types don't always have to be in registers, sometimes the compiler
583 : * can use addresses and avoid spilling. If this FrameEntry has a synced
584 : * address and no register, this returns true.
585 : */
586 : inline bool shouldAvoidTypeRemat(FrameEntry *fe);
587 :
588 : /*
589 : * Payloads don't always have to be in registers, sometimes the compiler
590 : * can use addresses and avoid spilling. If this FrameEntry has a synced
591 : * address and no register, this returns true.
592 : */
593 : inline bool shouldAvoidDataRemat(FrameEntry *fe);
594 :
595 : /*
596 : * Frees a temporary register. If this register is being tracked, then it
597 : * is not spilled; the backing data becomes invalidated!
598 : */
599 : inline void freeReg(AnyRegisterID reg);
600 :
601 : /*
602 : * Allocates a register. If none are free, one may be spilled from the
603 : * tracker. If there are none available for spilling in the tracker,
604 : * then this is considered a compiler bug and an assert will fire.
605 : */
606 : inline RegisterID allocReg();
607 : inline FPRegisterID allocFPReg();
608 :
609 : /*
610 : * Allocates a register, except using a mask.
611 : */
612 : inline AnyRegisterID allocReg(uint32_t mask);
613 :
614 : /*
615 : * Allocates a specific register, evicting it if it's not avaliable.
616 : */
617 : void takeReg(AnyRegisterID reg);
618 :
619 : /*
620 : * Returns a FrameEntry * for a slot on the operation stack.
621 : */
622 : inline FrameEntry *peek(int32_t depth);
623 :
624 : /*
625 : * Fully stores a FrameEntry at an arbitrary address. popHint specifies
626 : * how hard the register allocator should try to keep the FE in registers.
627 : */
628 : void storeTo(FrameEntry *fe, Address address, bool popHint = false);
629 :
630 : /*
631 : * Fully stores a FrameEntry into two arbitrary registers. tempReg may be
632 : * used as a temporary.
633 : */
634 : void loadForReturn(FrameEntry *fe, RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
635 : void loadThisForReturn(RegisterID typeReg, RegisterID dataReg, RegisterID tempReg);
636 :
637 : /* Stores the top stack slot back to a local or slot. */
638 : void storeLocal(uint32_t n, bool popGuaranteed = false);
639 : void storeArg(uint32_t n, bool popGuaranteed = false);
640 : void storeTop(FrameEntry *target);
641 :
642 : /*
643 : * Restores state from a slow path.
644 : */
645 : void merge(Assembler &masm, Changes changes) const;
646 :
647 : /*
648 : * Writes unsynced stores to an arbitrary buffer.
649 : */
650 : void sync(Assembler &masm, Uses uses) const;
651 :
652 : /*
653 : * Syncs all outstanding stores to memory and possibly kills regs in the
654 : * process. The top [ignored..uses-1] frame entries will be synced.
655 : */
656 : void syncAndKill(Registers kill, Uses uses, Uses ignored);
657 1527571 : void syncAndKill(Registers kill, Uses uses) { syncAndKill(kill, uses, Uses(0)); }
658 295711 : void syncAndKill(Uses uses) { syncAndKill(Registers(Registers::AvailAnyRegs), uses, Uses(0)); }
659 :
660 : /* Syncs and kills everything. */
661 466024 : void syncAndKillEverything() {
662 466024 : syncAndKill(Registers(Registers::AvailAnyRegs), Uses(frameSlots()));
663 466024 : }
664 :
665 : /*
666 : * Throw away the entire frame state, without syncing anything.
667 : * This can only be called after a syncAndKill() against all registers.
668 : */
669 : void forgetEverything();
670 :
671 405333 : void syncAndForgetEverything()
672 : {
673 405333 : syncAndKillEverything();
674 405333 : forgetEverything();
675 405333 : }
676 :
677 : /*
678 : * Discard the entire framestate forcefully.
679 : */
680 : void discardFrame();
681 :
682 : /*
683 : * Make a copy of the current frame state, and restore from that snapshot.
684 : * The stack depth must match between the snapshot and restore points.
685 : */
686 : FrameEntry *snapshotState();
687 : void restoreFromSnapshot(FrameEntry *snapshot);
688 :
689 : /*
690 : * Tries to sync and shuffle registers in accordance with the register state
691 : * at target, constructing that state if necessary. Forgets all constants and
692 : * copies, and nothing can be pinned. Keeps the top Uses in registers; if Uses
693 : * is non-zero the state may not actually be consistent with target.
694 : */
695 : bool syncForBranch(jsbytecode *target, Uses uses);
696 : void syncForAllocation(RegisterAllocation *alloc, bool inlineReturn, Uses uses);
697 :
698 : /* Discards the current frame state and updates to a new register allocation. */
699 : bool discardForJoin(RegisterAllocation *&alloc, uint32_t stackDepth);
700 :
701 : RegisterAllocation * computeAllocation(jsbytecode *target);
702 :
703 : /* Return whether the register state is consistent with that at target. */
704 : bool consistentRegisters(jsbytecode *target);
705 :
706 : /*
707 : * Load all registers to update from either the current register state (if synced
708 : * is unset) or a synced state (if synced is set) to target.
709 : */
710 : void prepareForJump(jsbytecode *target, Assembler &masm, bool synced);
711 :
712 : /*
713 : * Mark an existing slot with a type. unsync indicates whether type is already synced.
714 : * Do not call this on entries which might be copied.
715 : */
716 : inline void learnType(FrameEntry *fe, JSValueType type, bool unsync = true);
717 : inline void learnType(FrameEntry *fe, JSValueType type, RegisterID payload);
718 :
719 : /*
720 : * Forget a type, syncing in the process.
721 : */
722 : inline void forgetType(FrameEntry *fe);
723 :
724 : /*
725 : * Discards a FrameEntry, tricking the FS into thinking it's synced.
726 : */
727 : void discardFe(FrameEntry *fe);
728 :
729 : /* Compiler-owned metadata about stack entries, reset on push/pop/copy. */
730 : struct StackEntryExtra {
731 : bool initArray;
732 : JSObject *initObject;
733 : types::TypeSet *types;
734 : JSAtom *name;
735 22461062 : void reset() { PodZero(this); }
736 : };
737 3298122 : StackEntryExtra& extra(const FrameEntry *fe) {
738 3298122 : JS_ASSERT(fe >= a->args && fe < a->sp);
739 3298122 : return extraArray[fe - entries];
740 : }
741 : StackEntryExtra& extra(uint32_t slot) { return extra(entries + slot); }
742 :
743 : /*
744 : * Helper function. Tests if a slot's type is null. Condition must
745 : * be Equal or NotEqual.
746 : */
747 : inline Jump testNull(Assembler::Condition cond, FrameEntry *fe);
748 :
749 : /*
750 : * Helper function. Tests if a slot's type is undefined. Condition must
751 : * be Equal or NotEqual.
752 : */
753 : inline Jump testUndefined(Assembler::Condition cond, FrameEntry *fe);
754 :
755 : /*
756 : * Helper function. Tests if a slot's type is an integer. Condition must
757 : * be Equal or NotEqual.
758 : */
759 : inline Jump testInt32(Assembler::Condition cond, FrameEntry *fe);
760 :
761 : /*
762 : * Helper function. Tests if a slot's type is a double. Condition must
763 : * be Equal or Not Equal.
764 : */
765 : inline Jump testDouble(Assembler::Condition cond, FrameEntry *fe);
766 :
767 : /*
768 : * Helper function. Tests if a slot's type is a boolean. Condition must
769 : * be Equal or NotEqual.
770 : */
771 : inline Jump testBoolean(Assembler::Condition cond, FrameEntry *fe);
772 :
773 : /*
774 : * Helper function. Tests if a slot's type is a string. Condition must
775 : * be Equal or NotEqual.
776 : */
777 : inline Jump testString(Assembler::Condition cond, FrameEntry *fe);
778 :
779 : /*
780 : * Helper function. Tests if a slot's type is a non-funobj. Condition must
781 : * be Equal or NotEqual.
782 : */
783 : inline Jump testObject(Assembler::Condition cond, FrameEntry *fe);
784 :
785 : inline Jump testGCThing(FrameEntry *fe);
786 :
787 : /*
788 : * Helper function. Tests if a slot's type is primitive. Condition must
789 : * be Equal or NotEqual.
790 : */
791 : inline Jump testPrimitive(Assembler::Condition cond, FrameEntry *fe);
792 :
793 : /*
794 : * Marks a register such that it cannot be spilled by the register
795 : * allocator. Any pinned registers must be unpinned at the end of the op,
796 : * no matter what. In addition, pinReg() can only be used on registers
797 : * which are associated with FrameEntries.
798 : */
799 6667079 : inline void pinReg(AnyRegisterID reg) { regstate(reg).pin(); }
800 :
801 : /*
802 : * Unpins a previously pinned register.
803 : */
804 6271619 : inline void unpinReg(AnyRegisterID reg) { regstate(reg).unpin(); }
805 :
806 : /*
807 : * Same as unpinReg(), but does not restore the FrameEntry.
808 : */
809 : inline void unpinKilledReg(AnyRegisterID reg);
810 :
811 : /* Pins a data or type register if one exists. */
812 : MaybeRegisterID maybePinData(FrameEntry *fe);
813 : MaybeRegisterID maybePinType(FrameEntry *fe);
814 : void maybeUnpinReg(MaybeRegisterID reg);
815 :
816 : /*
817 : * Dups the top item on the stack.
818 : */
819 : inline void dup();
820 :
821 : /*
822 : * Dups the top 2 items on the stack.
823 : */
824 : inline void dup2();
825 :
826 : /*
827 : * Dups an item n-deep in the stack. n must be < 0
828 : */
829 : inline void dupAt(int32_t n);
830 :
831 : /*
832 : * Syncs an item n-deep in the stack.
833 : */
834 : inline void syncAt(int32_t n);
835 :
836 : /*
837 : * If the frameentry is a copy, give it its own registers.
838 : * This may only be called on the topmost fe.
839 : */
840 : inline void giveOwnRegs(FrameEntry *fe);
841 :
842 14096935 : uint32_t stackDepth() const { return a->sp - a->spBase; }
843 :
844 : /*
845 : * The stack depth of the current frame plus any locals and space
846 : * for inlined frames, i.e. the difference between the end of the
847 : * current fp and sp.
848 : */
849 5277622 : uint32_t totalDepth() const { return a->depth + a->script->nfixed + stackDepth(); }
850 :
851 : // Returns the number of entries in the frame, that is:
852 : // 2 for callee, this +
853 : // nargs +
854 : // nfixed +
855 : // currently pushed stack slots
856 741171 : uint32_t frameSlots() const { return uint32_t(a->sp - a->callee_); }
857 :
858 : #ifdef DEBUG
859 : void assertValidRegisterState() const;
860 : #else
861 : inline void assertValidRegisterState() const {};
862 : #endif
863 :
864 : // Return an address, relative to the StackFrame, that represents where
865 : // this FrameEntry is stored in memory. Note that this is its canonical
866 : // address, not its backing store. There is no guarantee that the memory
867 : // is coherent.
868 : Address addressOf(const FrameEntry *fe) const;
869 55679 : Address addressOf(uint32_t slot) const { return addressOf(a->callee_ + slot); }
870 :
871 38155 : Address addressOfTop() const { return addressOf(a->sp); }
872 :
873 : // Returns an address, relative to the StackFrame, that represents where
874 : // this FrameEntry is backed in memory. This is not necessarily its
875 : // canonical address, but the address for which the payload has been synced
876 : // to memory. The caller guarantees that the payload has been synced.
877 : Address addressForDataRemat(const FrameEntry *fe) const;
878 :
879 : // Inside an inline frame, the address for the return value in the caller.
880 : Address addressForInlineReturn();
881 :
882 : inline StateRemat dataRematInfo(const FrameEntry *fe) const;
883 :
884 : /*
885 : * This is similar to freeReg(ownRegForData(fe)) - except no movement takes place.
886 : * The fe is simply invalidated as if it were popped. This can be used to free
887 : * registers in the working area of the stack. Obviously, this can only be called
888 : * in infallible code that will pop these entries soon after.
889 : */
890 : inline void eviscerate(FrameEntry *fe);
891 :
892 : /*
893 : * Moves the top of the stack down N slots, popping each item above it.
894 : * Caller guarantees the slots below have been observed and eviscerated.
895 : */
896 : void shimmy(uint32_t n);
897 :
898 : /*
899 : * Stores the top item on the stack to a stack slot, count down from the
900 : * current stack depth. For example, to move the top (-1) to -3, you would
901 : * call shift(-2).
902 : */
903 : void shift(int32_t n);
904 :
905 : /* Swaps the top two items on the stack. Requires two temp slots. */
906 : void swap();
907 :
908 8820573 : inline void setInTryBlock(bool inTryBlock) {
909 8820573 : this->inTryBlock = inTryBlock;
910 8820573 : }
911 :
912 5692 : inline uint32_t regsInUse() const { return Registers::AvailRegs & ~freeRegs.freeMask; }
913 :
914 8820573 : void setPC(jsbytecode *PC) { a->PC = PC; }
915 67192 : void setLoop(LoopState *loop) { this->loop = loop; }
916 :
917 : void pruneDeadEntries();
918 :
919 : bool pushActiveFrame(JSScript *script, uint32_t argc);
920 : void popActiveFrame();
921 :
922 608277 : uint32_t entrySlot(const FrameEntry *fe) const {
923 608277 : return frameSlot(a, fe);
924 : }
925 :
926 18076 : uint32_t outerSlot(const FrameEntry *fe) const {
927 18076 : ActiveFrame *na = a;
928 18076 : while (na->parent) { na = na->parent; }
929 18076 : return frameSlot(na, fe);
930 : }
931 :
932 20637 : bool isOuterSlot(const FrameEntry *fe) const {
933 20637 : if (isTemporary(fe))
934 655 : return true;
935 19982 : ActiveFrame *na = a;
936 19982 : while (na->parent) { na = na->parent; }
937 19982 : return fe < na->spBase && fe != na->callee_;
938 : }
939 :
940 : #ifdef DEBUG
941 : const char * entryName(const FrameEntry *fe) const;
942 : void dumpAllocation(RegisterAllocation *alloc);
943 : #else
944 : const char * entryName(const FrameEntry *fe) const { return NULL; }
945 : #endif
946 28876 : const char * entryName(uint32_t slot) { return entryName(entries + slot); }
947 :
948 : /* Maximum number of analysis temporaries the FrameState can track. */
949 : static const uint32_t TEMPORARY_LIMIT = 10;
950 :
951 : uint32_t allocTemporary(); /* -1 if limit reached. */
952 : void clearTemporaries();
953 : inline FrameEntry *getTemporary(uint32_t which);
954 :
955 : /*
956 : * Return NULL or a new vector with all current copies of temporaries,
957 : * excluding those about to be popped per 'uses'.
958 : */
959 : Vector<TemporaryCopy> *getTemporaryCopies(Uses uses);
960 :
961 : inline void syncAndForgetFe(FrameEntry *fe, bool markSynced = false);
962 : inline void forgetLoopReg(FrameEntry *fe);
963 :
964 : /*
965 : * Get an address for the specified name access in another script.
966 : * The compiler owns the result's base register.
967 : */
968 : inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access);
969 : inline Address loadNameAddress(const analyze::ScriptAnalysis::NameAccess &access,
970 : RegisterID reg);
971 :
972 : private:
973 : inline AnyRegisterID allocAndLoadReg(FrameEntry *fe, bool fp, RematInfo::RematType type);
974 : inline void forgetReg(AnyRegisterID reg);
975 : AnyRegisterID evictSomeReg(uint32_t mask);
976 : void evictReg(AnyRegisterID reg);
977 : inline FrameEntry *rawPush();
978 : inline void addToTracker(FrameEntry *fe);
979 :
980 : /* Guarantee sync, but do not set any sync flag. */
981 : inline void ensureFeSynced(const FrameEntry *fe, Assembler &masm) const;
982 : inline void ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const;
983 : inline void ensureDataSynced(const FrameEntry *fe, Assembler &masm) const;
984 :
985 : /* Guarantee sync, even if register allocation is required, and set sync. */
986 : inline void syncFe(FrameEntry *fe);
987 : inline void syncType(FrameEntry *fe);
988 : inline void syncData(FrameEntry *fe);
989 :
990 : /* For a frame entry whose value is dead, mark as synced. */
991 : inline void fakeSync(FrameEntry *fe);
992 :
993 : inline FrameEntry *getCallee();
994 : inline FrameEntry *getThis();
995 : inline FrameEntry *getOrTrack(uint32_t index);
996 :
997 : inline void forgetAllRegs(FrameEntry *fe);
998 : inline void swapInTracker(FrameEntry *lhs, FrameEntry *rhs);
999 : #if defined JS_NUNBOX32
1000 : void syncFancy(Assembler &masm, Registers avail, int trackerIndex) const;
1001 : #endif
1002 : inline bool tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const;
1003 : void resetInternalState();
1004 :
1005 : /*
1006 : * "Uncopies" the backing store of a FrameEntry that has been copied. The
1007 : * original FrameEntry is not invalidated; this is the responsibility of
1008 : * the caller. The caller can check isCopied() to see if the registers
1009 : * were moved to a copy.
1010 : *
1011 : * Later addition: uncopy() returns the first copy found.
1012 : */
1013 : FrameEntry *uncopy(FrameEntry *original);
1014 : FrameEntry *walkTrackerForUncopy(FrameEntry *original);
1015 : FrameEntry *walkFrameForUncopy(FrameEntry *original);
1016 :
1017 : /* Whether fe is the only copy of backing. */
1018 : bool hasOnlyCopy(FrameEntry *backing, FrameEntry *fe);
1019 :
1020 : /*
1021 : * All registers in the FE are forgotten. If it is copied, it is uncopied
1022 : * beforehand.
1023 : */
1024 : void forgetEntry(FrameEntry *fe);
1025 :
1026 : /* Stack and temporary entries whose contents should be disregarded. */
1027 488474427 : bool deadEntry(const FrameEntry *fe, unsigned uses = 0) const {
1028 488474427 : return (fe >= (a->sp - uses) && fe < temporaries) || fe >= temporariesTop;
1029 : }
1030 :
1031 71423587 : RegisterState & regstate(AnyRegisterID reg) {
1032 71423587 : JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
1033 71423587 : return regstate_[reg.reg_];
1034 : }
1035 :
1036 1036995913 : const RegisterState & regstate(AnyRegisterID reg) const {
1037 1036995913 : JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
1038 1036995913 : return regstate_[reg.reg_];
1039 : }
1040 :
1041 : AnyRegisterID bestEvictReg(uint32_t mask, bool includePinned) const;
1042 : void evictDeadEntries(bool includePinned);
1043 :
1044 : inline analyze::Lifetime * variableLive(FrameEntry *fe, jsbytecode *pc) const;
1045 : inline bool binaryEntryLive(FrameEntry *fe) const;
1046 : void relocateReg(AnyRegisterID reg, RegisterAllocation *alloc, Uses uses);
1047 :
1048 370299 : bool isThis(const FrameEntry *fe) const {
1049 370299 : return fe == a->this_;
1050 : }
1051 :
1052 : inline bool isConstructorThis(const FrameEntry *fe) const;
1053 :
1054 206158 : bool isArg(const FrameEntry *fe) const {
1055 206158 : return a->script->function() && fe >= a->args && fe - a->args < a->script->function()->nargs;
1056 : }
1057 :
1058 480927 : bool isLocal(const FrameEntry *fe) const {
1059 480927 : return fe >= a->locals && fe - a->locals < a->script->nfixed;
1060 : }
1061 :
1062 32704268 : bool isTemporary(const FrameEntry *fe) const {
1063 32704268 : JS_ASSERT_IF(fe >= temporaries, fe < temporariesTop);
1064 32704268 : return fe >= temporaries;
1065 : }
1066 :
1067 : int32_t frameOffset(const FrameEntry *fe, ActiveFrame *a) const;
1068 : Address addressOf(const FrameEntry *fe, ActiveFrame *a) const;
1069 : uint32_t frameSlot(ActiveFrame *a, const FrameEntry *fe) const;
1070 :
1071 : void associateReg(FrameEntry *fe, RematInfo::RematType type, AnyRegisterID reg);
1072 :
1073 : inline void modifyReg(AnyRegisterID reg);
1074 :
1075 : MaybeJump guardArrayLengthBase(FrameEntry *obj, Int32Key key);
1076 :
1077 : private:
1078 : JSContext *cx;
1079 : Assembler &masm;
1080 : Compiler &cc;
1081 : StubCompiler &stubcc;
1082 :
1083 : /* State for the active stack frame. */
1084 :
1085 2995 : struct ActiveFrame {
1086 131876 : ActiveFrame() { PodZero(this); }
1087 :
1088 : ActiveFrame *parent;
1089 :
1090 : /* Number of values between the start of the outer frame and the start of this frame. */
1091 : uint32_t depth;
1092 :
1093 : JSScript *script;
1094 : jsbytecode *PC;
1095 : analyze::ScriptAnalysis *analysis;
1096 :
1097 : /* Indexes into the main FrameEntry buffer of entries for this frame. */
1098 : FrameEntry *callee_;
1099 : FrameEntry *this_;
1100 : FrameEntry *args;
1101 : FrameEntry *locals;
1102 : FrameEntry *spBase;
1103 : FrameEntry *sp;
1104 : };
1105 : ActiveFrame *a;
1106 :
1107 : /* Common buffer of frame entries. */
1108 : FrameEntry *entries;
1109 : uint32_t nentries;
1110 :
1111 : /* Compiler-owned metadata for stack contents. */
1112 : StackEntryExtra *extraArray;
1113 :
1114 : /* Vector of tracked slot indexes. */
1115 : Tracker tracker;
1116 :
1117 : #if defined JS_NUNBOX32
1118 : mutable ImmutableSync reifier;
1119 : #endif
1120 :
1121 : /*
1122 : * Register ownership state. This can't be used alone; to find whether an
1123 : * entry is active, you must check the allocated registers.
1124 : */
1125 : RegisterState regstate_[Registers::TotalAnyRegisters];
1126 :
1127 : /* All unallocated registers. */
1128 : Registers freeRegs;
1129 :
1130 : /* Stack of active loops. */
1131 : LoopState *loop;
1132 :
1133 : /*
1134 : * Track state for analysis temporaries. The meaning of these temporaries
1135 : * is opaque to the frame state, which just tracks where they are stored.
1136 : */
1137 : FrameEntry *temporaries;
1138 : FrameEntry *temporariesTop;
1139 :
1140 : bool inTryBlock;
1141 : };
1142 :
1143 : /*
1144 : * Register allocation overview. We want to allocate registers at the same time
1145 : * as we emit code, in a single forward pass over the script. This is good both
1146 : * for compilation speed and for design simplicity; we allocate registers for
1147 : * variables and temporaries as the compiler needs them. To get a good allocation,
1148 : * however, we need knowledge of which variables will be used in the future and
1149 : * in what order --- we must prioritize keeping variables in registers which
1150 : * will be used soon, and evict variables after they are no longer needed.
1151 : * We get this from the analyze::LifetimeScript analysis, an initial backwards
1152 : * pass over the script.
1153 : *
1154 : * Combining a backwards lifetime pass with a forward allocation pass in this
1155 : * way produces a Linear-scan register allocator. These can generate code at
1156 : * a speed close to that produced by a graph coloring register allocator,
1157 : * at a fraction of the compilation time.
1158 : */
1159 :
1160 : /* Register allocation to use at a join point. */
1161 : struct RegisterAllocation {
1162 : private:
1163 : typedef JSC::MacroAssembler::RegisterID RegisterID;
1164 : typedef JSC::MacroAssembler::FPRegisterID FPRegisterID;
1165 :
1166 : /* Entry for an unassigned register at the join point. */
1167 : static const uint32_t UNASSIGNED_REGISTER = UINT32_MAX;
1168 :
1169 : /*
1170 : * In the body of a loop, entry for an unassigned register that has not been
1171 : * used since the start of the loop. We do not finalize the register state
1172 : * at the start of a loop body until after generating code for the entire loop,
1173 : * so we can decide on which variables to carry around the loop after seeing
1174 : * them accessed early on in the body.
1175 : */
1176 : static const uint32_t LOOP_REGISTER = uint32_t(-2);
1177 :
1178 : /*
1179 : * Assignment of registers to payloads. Type tags are always in memory,
1180 : * except for known doubles in FP registers. These are indexes into the
1181 : * frame's entries[] buffer, not slots.
1182 : */
1183 : uint32_t regstate_[Registers::TotalAnyRegisters];
1184 :
1185 : /* Mask for regstate entries indicating if the slot is synced. */
1186 : static const uint32_t SYNCED = 0x80000000;
1187 :
1188 18978894 : uint32_t & regstate(AnyRegisterID reg) {
1189 18978894 : JS_ASSERT(reg.reg_ < Registers::TotalAnyRegisters);
1190 18978894 : return regstate_[reg.reg_];
1191 : }
1192 :
1193 : public:
1194 174438 : RegisterAllocation(bool forLoop)
1195 : {
1196 174438 : uint32_t entry = forLoop ? (uint32_t) LOOP_REGISTER : (uint32_t) UNASSIGNED_REGISTER;
1197 2791008 : for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
1198 2616570 : AnyRegisterID reg = AnyRegisterID::fromRaw(i);
1199 2616570 : bool avail = Registers::maskReg(reg) & Registers::AvailAnyRegs;
1200 2616570 : regstate_[i] = avail ? entry : UNASSIGNED_REGISTER;
1201 : }
1202 174438 : }
1203 :
1204 13495631 : bool assigned(AnyRegisterID reg) {
1205 13495631 : return regstate(reg) != UNASSIGNED_REGISTER && regstate(reg) != LOOP_REGISTER;
1206 : }
1207 :
1208 3195778 : bool loop(AnyRegisterID reg) {
1209 3195778 : return regstate(reg) == LOOP_REGISTER;
1210 : }
1211 :
1212 60240 : bool synced(AnyRegisterID reg) {
1213 60240 : JS_ASSERT(assigned(reg));
1214 60240 : return regstate(reg) & SYNCED;
1215 : }
1216 :
1217 378120 : uint32_t index(AnyRegisterID reg) {
1218 378120 : JS_ASSERT(assigned(reg));
1219 378120 : return regstate(reg) & ~SYNCED;
1220 : }
1221 :
1222 55669 : void set(AnyRegisterID reg, uint32_t index, bool synced) {
1223 55669 : JS_ASSERT(index != LOOP_REGISTER && index != UNASSIGNED_REGISTER);
1224 55669 : regstate(reg) = index | (synced ? SYNCED : 0);
1225 55669 : }
1226 :
1227 421076 : void setUnassigned(AnyRegisterID reg) {
1228 421076 : regstate(reg) = UNASSIGNED_REGISTER;
1229 421076 : }
1230 :
1231 77850 : bool synced() {
1232 1074727 : for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
1233 1011581 : if (assigned(AnyRegisterID::fromRaw(i)))
1234 14704 : return false;
1235 : }
1236 63146 : return true;
1237 : }
1238 :
1239 154271 : void clearLoops() {
1240 2468336 : for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
1241 2314065 : AnyRegisterID reg = AnyRegisterID::fromRaw(i);
1242 2314065 : if (loop(reg))
1243 284111 : setUnassigned(reg);
1244 : }
1245 154271 : }
1246 :
1247 287316 : bool hasAnyReg(uint32_t n) {
1248 4058692 : for (unsigned i = 0; i < Registers::TotalAnyRegisters; i++) {
1249 3823787 : AnyRegisterID reg = AnyRegisterID::fromRaw(i);
1250 3823787 : if (assigned(reg) && index(reg) == n)
1251 52411 : return true;
1252 : }
1253 234905 : return false;
1254 : }
1255 : };
1256 :
1257 : class AutoPreserveAcrossSyncAndKill;
1258 :
1259 : } /* namespace mjit */
1260 : } /* namespace js */
1261 :
1262 : #endif /* jsjaeger_framestate_h__ */
1263 :
|