Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / methodjit / FrameState-inl.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_framestate_inl_h__ && defined JS_METHODJIT
41 #define jsjaeger_framestate_inl_h__
42
43 namespace js {
44 namespace mjit {
45
46 inline void
47 FrameState::addToTracker(FrameEntry *fe)
48 {
49     JS_ASSERT(!fe->isTracked());
50     fe->track(tracker.nentries);
51     tracker.add(fe);
52     JS_ASSERT(tracker.nentries <= feLimit());
53 }
54
55 inline FrameEntry *
56 FrameState::peek(int32 depth)
57 {
58     JS_ASSERT(depth < 0);
59     JS_ASSERT(sp + depth >= spBase);
60     FrameEntry *fe = &sp[depth];
61     if (!fe->isTracked()) {
62         addToTracker(fe);
63         fe->resetSynced();
64     }
65     return fe;
66 }
67
68 inline void
69 FrameState::popn(uint32 n)
70 {
71     for (uint32 i = 0; i < n; i++)
72         pop();
73 }
74
75 inline bool
76 FrameState::haveSameBacking(FrameEntry *lhs, FrameEntry *rhs)
77 {
78     if (lhs->isCopy())
79         lhs = lhs->copyOf();
80     if (rhs->isCopy())
81         rhs = rhs->copyOf();
82     return lhs == rhs;
83 }
84
85 inline JSC::MacroAssembler::RegisterID
86 FrameState::allocReg()
87 {
88     RegisterID reg;
89     if (!freeRegs.empty()) {
90         reg = freeRegs.takeAnyReg();
91     } else {
92         reg = evictSomeReg();
93         regstate[reg].forget();
94     }
95
96     return reg;
97 }
98
99 inline JSC::MacroAssembler::RegisterID
100 FrameState::allocReg(uint32 mask)
101 {
102     RegisterID reg;
103     if (freeRegs.hasRegInMask(mask)) {
104         reg = freeRegs.takeRegInMask(mask);
105     } else {
106         reg = evictSomeReg(mask);
107         regstate[reg].forget();
108     }
109
110     return reg;
111 }
112
113 inline JSC::MacroAssembler::RegisterID
114 FrameState::allocReg(FrameEntry *fe, RematInfo::RematType type)
115 {
116     RegisterID reg;
117     if (!freeRegs.empty()) {
118         reg = freeRegs.takeAnyReg();
119     } else {
120         reg = evictSomeReg();
121         regstate[reg].forget();
122     }
123
124     regstate[reg].associate(fe, type);
125
126     return reg;
127 }
128
129 inline void
130 FrameState::convertInt32ToDouble(Assembler &masm, FrameEntry *fe, FPRegisterID fpreg) const
131 {
132     JS_ASSERT(!fe->isConstant());
133
134     if (fe->isCopy())
135         fe = fe->copyOf();
136     
137     if (fe->data.inRegister())
138         masm.convertInt32ToDouble(fe->data.reg(), fpreg);
139     else
140         masm.convertInt32ToDouble(addressOf(fe), fpreg);
141 }
142
143 inline bool
144 FrameState::peekTypeInRegister(FrameEntry *fe) const
145 {
146     if (fe->isCopy())
147         fe = fe->copyOf();
148     return fe->type.inRegister();
149 }
150
151 inline void
152 FrameState::pop()
153 {
154     JS_ASSERT(sp > spBase);
155
156     FrameEntry *fe = --sp;
157     if (!fe->isTracked())
158         return;
159
160     forgetAllRegs(fe);
161 }
162
163 inline void
164 FrameState::freeReg(RegisterID reg)
165 {
166     JS_ASSERT(!regstate[reg].usedBy());
167
168     freeRegs.putReg(reg);
169 }
170
171 inline void
172 FrameState::forgetReg(RegisterID reg)
173 {
174     /*
175      * Important: Do not touch the fe here. We can peephole optimize away
176      * loads and stores by re-using the contents of old FEs.
177      */
178     JS_ASSERT_IF(regstate[reg].fe(), !regstate[reg].fe()->isCopy());
179
180     if (!regstate[reg].isPinned()) {
181         regstate[reg].forget();
182         freeRegs.putReg(reg);
183     }
184 }
185
186 inline void
187 FrameState::syncAndForgetEverything(uint32 newStackDepth)
188 {
189     syncAndForgetEverything();
190     sp = spBase + newStackDepth;
191 }
192
193 inline FrameEntry *
194 FrameState::rawPush()
195 {
196     JS_ASSERT(unsigned(sp - entries) < feLimit());
197
198     if (!sp->isTracked())
199         addToTracker(sp);
200
201     return sp++;
202 }
203
204 inline void
205 FrameState::push(const Value &v)
206 {
207     FrameEntry *fe = rawPush();
208     fe->setConstant(Jsvalify(v));
209 }
210
211 inline void
212 FrameState::pushSynced()
213 {
214     if (sp->isTracked())
215         sp->resetSynced();
216     sp++;
217 }
218
219 inline void
220 FrameState::pushSyncedType(JSValueType type)
221 {
222     FrameEntry *fe = rawPush();
223
224     fe->resetSynced();
225     fe->setType(type);
226 }
227
228 inline void
229 FrameState::pushSynced(JSValueType type, RegisterID reg)
230 {
231     FrameEntry *fe = rawPush();
232
233     fe->resetUnsynced();
234     fe->type.sync();
235     fe->data.sync();
236     fe->setType(type);
237     fe->data.setRegister(reg);
238     regstate[reg].associate(fe, RematInfo::DATA);
239 }
240
241 inline void
242 FrameState::push(Address address)
243 {
244 #ifdef JS_PUNBOX64
245     // It's okay if either of these clobbers address.base, since we guarantee
246     // eviction will not physically clobber. It's also safe, on x64, for
247     // loadValueAsComponents() to take either type or data regs as address.base.
248     RegisterID typeReg = allocReg();
249     RegisterID dataReg = allocReg();
250     masm.loadValueAsComponents(address, typeReg, dataReg);
251 #elif JS_NUNBOX32
252     // Prevent us from clobbering this reg.
253     bool free = freeRegs.hasReg(address.base);
254     if (free)
255         freeRegs.takeReg(address.base);
256
257     RegisterID typeReg = allocReg();
258
259     masm.loadTypeTag(address, typeReg);
260
261     // Allow re-use of the base register. This could avoid a spill, and
262     // is safe because the following allocReg() won't actually emit any
263     // writes to the register.
264     if (free)
265         freeRegs.putReg(address.base);
266
267     RegisterID dataReg = allocReg();
268     masm.loadPayload(address, dataReg);
269 #endif
270
271     pushRegs(typeReg, dataReg);
272 }
273
274 inline void
275 FrameState::pushRegs(RegisterID type, RegisterID data)
276 {
277     JS_ASSERT(!freeRegs.hasReg(type) && !freeRegs.hasReg(data));
278
279     FrameEntry *fe = rawPush();
280
281     fe->resetUnsynced();
282     fe->type.setRegister(type);
283     fe->data.setRegister(data);
284     regstate[type].associate(fe, RematInfo::TYPE);
285     regstate[data].associate(fe, RematInfo::DATA);
286 }
287
288 inline void
289 FrameState::pushTypedPayload(JSValueType type, RegisterID payload)
290 {
291     JS_ASSERT(!freeRegs.hasReg(payload));
292
293     FrameEntry *fe = rawPush();
294
295     fe->resetUnsynced();
296     fe->setType(type);
297     fe->data.setRegister(payload);
298     regstate[payload].associate(fe, RematInfo::DATA);
299 }
300
301 inline void
302 FrameState::pushNumber(MaybeRegisterID payload, bool asInt32)
303 {
304     JS_ASSERT_IF(payload.isSet(), !freeRegs.hasReg(payload.reg()));
305
306     FrameEntry *fe = rawPush();
307     fe->clear();
308
309     JS_ASSERT(!fe->isNumber);
310
311     if (asInt32) {
312         if (!fe->type.synced())
313             masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
314         fe->type.setMemory();
315     } else {
316         fe->type.setMemory();
317     }
318
319     fe->isNumber = true;
320     if (payload.isSet()) {
321         fe->data.unsync();
322         fe->data.setRegister(payload.reg());
323         regstate[payload.reg()].associate(fe, RematInfo::DATA);
324     } else {
325         fe->data.setMemory();
326     }
327 }
328
329 inline void
330 FrameState::pushInt32(RegisterID payload)
331 {
332     FrameEntry *fe = rawPush();
333     fe->clear();
334     JS_ASSERT(!fe->isNumber);
335
336     masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
337     fe->type.setMemory();
338
339     fe->isNumber = true;
340     fe->data.unsync();
341     fe->data.setRegister(payload);
342     regstate[payload].associate(fe, RematInfo::DATA);
343 }
344
345 inline void
346 FrameState::pushInitializerObject(RegisterID payload, bool array, JSObject *baseobj)
347 {
348     pushTypedPayload(JSVAL_TYPE_OBJECT, payload);
349
350     FrameEntry *fe = peek(-1);
351     fe->initArray = array;
352     fe->initObject = baseobj;
353 }
354
355 inline void
356 FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
357 {
358     JS_ASSERT(!freeRegs.hasReg(payload));
359
360     FrameEntry *fe = rawPush();
361
362     fe->clear();
363
364     masm.storeTypeTag(ImmType(type), addressOf(fe));
365
366     /* The forceful type sync will assert otherwise. */
367 #ifdef DEBUG
368     fe->type.unsync();
369 #endif
370     fe->type.setMemory();
371     fe->data.unsync();
372     fe->setNotCopied();
373     fe->setCopyOf(NULL);
374     fe->data.setRegister(payload);
375     regstate[payload].associate(fe, RematInfo::DATA);
376 }
377
378 inline void
379 FrameState::pushUntypedValue(const Value &v)
380 {
381     FrameEntry *fe = rawPush();
382
383     fe->clear();
384
385     masm.storeValue(v, addressOf(fe));
386
387     /* The forceful type sync will assert otherwise. */
388 #ifdef DEBUG
389     fe->type.unsync();
390 #endif
391     fe->type.setMemory();
392     fe->data.unsync();
393     fe->data.setMemory();
394     fe->setNotCopied();
395     fe->setCopyOf(NULL);
396 }
397
398 inline JSC::MacroAssembler::RegisterID
399 FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
400 {
401     JS_ASSERT(!regstate[fallback].fe());
402     if (fe->isCopy())
403         fe = fe->copyOf();
404
405     JS_ASSERT(!fe->type.isConstant());
406
407     if (fe->type.inRegister())
408         return fe->type.reg();
409
410     /* :XXX: X86 */
411
412     masm.loadTypeTag(addressOf(fe), fallback);
413     return fallback;
414 }
415
416
417 inline JSC::MacroAssembler::RegisterID
418 FrameState::tempRegForType(FrameEntry *fe)
419 {
420     if (fe->isCopy())
421         fe = fe->copyOf();
422
423     JS_ASSERT(!fe->type.isConstant());
424
425     if (fe->type.inRegister())
426         return fe->type.reg();
427
428     /* :XXX: X86 */
429
430     RegisterID reg = allocReg(fe, RematInfo::TYPE);
431     masm.loadTypeTag(addressOf(fe), reg);
432     fe->type.setRegister(reg);
433     return reg;
434 }
435
436 inline JSC::MacroAssembler::RegisterID
437 FrameState::tempRegForData(FrameEntry *fe)
438 {
439     JS_ASSERT(!fe->data.isConstant());
440
441     if (fe->isCopy())
442         fe = fe->copyOf();
443
444     if (fe->data.inRegister())
445         return fe->data.reg();
446
447     RegisterID reg = allocReg(fe, RematInfo::DATA);
448     masm.loadPayload(addressOf(fe), reg);
449     fe->data.setRegister(reg);
450     return reg;
451 }
452
453 inline JSC::MacroAssembler::RegisterID
454 FrameState::tempRegInMaskForData(FrameEntry *fe, uint32 mask)
455 {
456     JS_ASSERT(!fe->data.isConstant());
457
458     if (fe->isCopy())
459         fe = fe->copyOf();
460
461     RegisterID reg;
462     if (fe->data.inRegister()) {
463         RegisterID old = fe->data.reg();
464         if (Registers::maskReg(old) & mask)
465             return old;
466
467         /* Keep the old register pinned. */
468         regstate[old].forget();
469         reg = allocReg(mask);
470         masm.move(old, reg);
471         freeReg(old);
472     } else {
473         reg = allocReg(mask);
474         masm.loadPayload(addressOf(fe), reg);
475     }
476     regstate[reg].associate(fe, RematInfo::DATA);
477     fe->data.setRegister(reg);
478     return reg;
479 }
480
481 inline JSC::MacroAssembler::RegisterID
482 FrameState::tempRegForData(FrameEntry *fe, RegisterID reg, Assembler &masm) const
483 {
484     JS_ASSERT(!fe->data.isConstant());
485
486     if (fe->isCopy())
487         fe = fe->copyOf();
488
489     if (fe->data.inRegister()) {
490         JS_ASSERT(fe->data.reg() != reg);
491         return fe->data.reg();
492     } else {
493         masm.loadPayload(addressOf(fe), reg);
494         return reg;
495     }
496 }
497
498 inline bool
499 FrameState::shouldAvoidTypeRemat(FrameEntry *fe)
500 {
501     return fe->type.inMemory();
502 }
503
504 inline bool
505 FrameState::shouldAvoidDataRemat(FrameEntry *fe)
506 {
507     return fe->data.inMemory();
508 }
509
510 inline void
511 FrameState::ensureFeSynced(const FrameEntry *fe, Assembler &masm) const
512 {
513 #if defined JS_PUNBOX64
514     Address to = addressOf(fe);
515     const FrameEntry *backing = fe;
516     if (fe->isCopy())
517         backing = fe->copyOf();
518
519     /* If we can, sync the type and data in one go. */
520     if (!fe->data.synced() && !fe->type.synced()) {
521         if (backing->isConstant())
522             masm.storeValue(backing->getValue(), to);
523         else if (backing->isTypeKnown())
524             masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to);
525         else
526             masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to);
527         return;
528     }
529 #endif
530
531     /* 
532      * On x86_64, only one of the following two calls will have output,
533      * and a load will only occur if necessary.
534      */
535     ensureDataSynced(fe, masm);
536     ensureTypeSynced(fe, masm);
537 }
538
539 inline void
540 FrameState::ensureTypeSynced(const FrameEntry *fe, Assembler &masm) const
541 {
542     if (fe->type.synced())
543         return;
544
545     Address to = addressOf(fe);
546     const FrameEntry *backing = fe;
547     if (fe->isCopy())
548         backing = fe->copyOf();
549
550 #if defined JS_PUNBOX64
551     /* Attempt to store the entire Value, to prevent a load. */
552     if (backing->isConstant()) {
553         masm.storeValue(backing->getValue(), to);
554         return;
555     }
556
557     if (backing->data.inRegister()) {
558         RegisterID dreg = backing->data.reg();
559         if (backing->isTypeKnown())
560             masm.storeValueFromComponents(ImmType(backing->getKnownType()), dreg, to);
561         else
562             masm.storeValueFromComponents(backing->type.reg(), dreg, to);
563         return;
564     }
565 #endif
566
567     /* Store a double's type bits, even though !isTypeKnown(). */
568     if (backing->isConstant())
569         masm.storeTypeTag(ImmTag(backing->getKnownTag()), to);
570     else if (backing->isTypeKnown())
571         masm.storeTypeTag(ImmType(backing->getKnownType()), to); 
572     else
573         masm.storeTypeTag(backing->type.reg(), to);
574 }
575
576 inline void
577 FrameState::ensureDataSynced(const FrameEntry *fe, Assembler &masm) const
578 {
579     if (fe->data.synced())
580         return;
581
582     Address to = addressOf(fe);
583     const FrameEntry *backing = fe;
584     if (fe->isCopy())
585         backing = fe->copyOf();
586
587 #if defined JS_PUNBOX64
588     if (backing->isConstant())
589         masm.storeValue(backing->getValue(), to);
590     else if (backing->isTypeKnown())
591         masm.storeValueFromComponents(ImmType(backing->getKnownType()), backing->data.reg(), to);
592     else if (backing->type.inRegister())
593         masm.storeValueFromComponents(backing->type.reg(), backing->data.reg(), to);
594     else
595         masm.storePayload(backing->data.reg(), to);
596 #elif defined JS_NUNBOX32
597     if (backing->isConstant())
598         masm.storePayload(ImmPayload(backing->getPayload()), to);
599     else
600         masm.storePayload(backing->data.reg(), to);
601 #endif
602 }
603
604 inline void
605 FrameState::syncFe(FrameEntry *fe)
606 {
607     FrameEntry *backing = fe;
608     if (fe->isCopy())
609         backing = fe->copyOf();
610
611     bool needTypeReg = !fe->type.synced() && backing->type.inMemory();
612     bool needDataReg = !fe->data.synced() && backing->data.inMemory();
613
614 #if defined JS_NUNBOX32
615     /* Determine an ordering that won't spill known regs. */
616     if (needTypeReg && !needDataReg) {
617         syncData(fe);
618         syncType(fe);
619     } else {
620         syncType(fe);
621         syncData(fe);
622     }
623 #elif defined JS_PUNBOX64
624     if (JS_UNLIKELY(needTypeReg && needDataReg)) {
625         /* Memory-to-memory moves can only occur for copies backed by memory. */
626         JS_ASSERT(backing != fe);
627
628         /* Use ValueReg to do a whole-Value mem-to-mem move. */
629         masm.loadValue(addressOf(backing), Registers::ValueReg);
630         masm.storeValue(Registers::ValueReg, addressOf(fe));
631     } else {
632         /* Store in case unpinning is necessary. */
633         MaybeRegisterID pairReg;
634
635         /* Get a register if necessary, without clobbering its pair. */
636         if (needTypeReg) {
637             if (backing->data.inRegister() && !regstate[backing->data.reg()].isPinned()) {
638                 pairReg = backing->data.reg();
639                 pinReg(backing->data.reg());
640             }
641             tempRegForType(backing);
642         } else if (needDataReg) {
643             if (backing->type.inRegister() && !regstate[backing->type.reg()].isPinned()) {
644                 pairReg = backing->type.reg();
645                 pinReg(backing->type.reg());
646             }
647             tempRegForData(backing);
648         }
649
650         ensureFeSynced(fe, masm);
651
652         if (pairReg.isSet())
653             unpinReg(pairReg.reg());
654     }
655
656     if (!fe->type.synced())
657         fe->type.sync();
658     if (!fe->data.synced())
659         fe->data.sync();
660 #endif
661 }
662
663 inline void
664 FrameState::syncType(FrameEntry *fe)
665 {
666     FrameEntry *backing = fe;
667     if (fe->isCopy())
668         backing = fe->copyOf();
669
670     if (!fe->type.synced() && backing->type.inMemory())
671         tempRegForType(backing);
672
673     ensureTypeSynced(fe, masm);
674
675     if (!fe->type.synced())
676         fe->type.sync();
677 }
678
679 inline void
680 FrameState::syncData(FrameEntry *fe)
681 {
682     FrameEntry *backing = fe;
683     if (fe->isCopy())
684         backing = fe->copyOf();
685
686     if (!fe->data.synced() && backing->data.inMemory())
687         tempRegForData(backing);
688
689     ensureDataSynced(fe, masm);
690
691     if (!fe->data.synced())
692         fe->data.sync();
693 }
694
695 inline void
696 FrameState::forgetType(FrameEntry *fe)
697 {
698     /*
699      * The type may have been forgotten with an intervening storeLocal in the
700      * presence of eval or closed variables. For defense in depth and to make
701      * callers' lives simpler, bail out if the type is not known.
702      */
703     if (!fe->isTypeKnown())
704         return;
705
706     /*
707      * Likewise, storeLocal() may have set this FE, with a known type,
708      * to be a copy of another FE, which has an unknown type.
709      * Just forget the type, since the backing is used in all cases.
710      */
711     if (fe->isCopy()) {
712         fe->type.invalidate();
713         return;
714     }
715
716     ensureTypeSynced(fe, masm);
717     fe->type.setMemory();
718 }
719
720 inline void
721 FrameState::learnType(FrameEntry *fe, JSValueType type)
722 {
723     if (fe->type.inRegister())
724         forgetReg(fe->type.reg());
725 #ifdef DEBUG
726     fe->isNumber = false;
727 #endif
728     fe->setType(type);
729 }
730
731 inline JSC::MacroAssembler::Address
732 FrameState::addressOf(const FrameEntry *fe) const
733 {
734     int32 frameOffset = 0;
735     if (fe >= locals)
736         frameOffset = JSStackFrame::offsetOfFixed(uint32(fe - locals));
737     else if (fe >= args)
738         frameOffset = JSStackFrame::offsetOfFormalArg(fun, uint32(fe - args));
739     else if (fe == this_)
740         frameOffset = JSStackFrame::offsetOfThis(fun);
741     else if (fe == callee_)
742         frameOffset = JSStackFrame::offsetOfCallee(fun);
743     JS_ASSERT(frameOffset);
744     return Address(JSFrameReg, frameOffset);
745 }
746
747 inline JSC::MacroAssembler::Address
748 FrameState::addressForDataRemat(const FrameEntry *fe) const
749 {
750     if (fe->isCopy() && !fe->data.synced())
751         fe = fe->copyOf();
752     JS_ASSERT(fe->data.synced());
753     return addressOf(fe);
754 }
755
756 inline JSC::MacroAssembler::Jump
757 FrameState::testNull(Assembler::Condition cond, FrameEntry *fe)
758 {
759     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
760     if (shouldAvoidTypeRemat(fe))
761         return masm.testNull(cond, addressOf(fe));
762     return masm.testNull(cond, tempRegForType(fe));
763 }
764
765 inline JSC::MacroAssembler::Jump
766 FrameState::testUndefined(Assembler::Condition cond, FrameEntry *fe)
767 {
768     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
769     if (shouldAvoidTypeRemat(fe))
770         return masm.testUndefined(cond, addressOf(fe));
771     return masm.testUndefined(cond, tempRegForType(fe));
772 }
773
774 inline JSC::MacroAssembler::Jump
775 FrameState::testInt32(Assembler::Condition cond, FrameEntry *fe)
776 {
777     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
778     if (shouldAvoidTypeRemat(fe))
779         return masm.testInt32(cond, addressOf(fe));
780     return masm.testInt32(cond, tempRegForType(fe));
781 }
782
783 inline JSC::MacroAssembler::Jump
784 FrameState::testPrimitive(Assembler::Condition cond, FrameEntry *fe)
785 {
786     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
787     if (shouldAvoidTypeRemat(fe))
788         return masm.testPrimitive(cond, addressOf(fe));
789     return masm.testPrimitive(cond, tempRegForType(fe));
790 }
791
792 inline JSC::MacroAssembler::Jump
793 FrameState::testObject(Assembler::Condition cond, FrameEntry *fe)
794 {
795     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
796     if (shouldAvoidTypeRemat(fe))
797         return masm.testObject(cond, addressOf(fe));
798     return masm.testObject(cond, tempRegForType(fe));
799 }
800
801 inline JSC::MacroAssembler::Jump
802 FrameState::testDouble(Assembler::Condition cond, FrameEntry *fe)
803 {
804     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
805     if (shouldAvoidTypeRemat(fe))
806         return masm.testDouble(cond, addressOf(fe));
807     return masm.testDouble(cond, tempRegForType(fe));
808 }
809
810 inline JSC::MacroAssembler::Jump
811 FrameState::testBoolean(Assembler::Condition cond, FrameEntry *fe)
812 {
813     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
814     if (shouldAvoidTypeRemat(fe))
815         return masm.testBoolean(cond, addressOf(fe));
816     return masm.testBoolean(cond, tempRegForType(fe));
817 }
818
819 inline JSC::MacroAssembler::Jump
820 FrameState::testString(Assembler::Condition cond, FrameEntry *fe)
821 {
822     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
823     if (shouldAvoidTypeRemat(fe))
824         return masm.testString(cond, addressOf(fe));
825     return masm.testString(cond, tempRegForType(fe));
826 }
827
828 inline FrameEntry *
829 FrameState::getOrTrack(uint32 index)
830 {
831     FrameEntry *fe = &entries[index];
832     if (!fe->isTracked()) {
833         addToTracker(fe);
834         fe->resetSynced();
835     }
836     return fe;
837 }
838
839 inline FrameEntry *
840 FrameState::getLocal(uint32 slot)
841 {
842     JS_ASSERT(slot < script->nslots);
843     return getOrTrack(uint32(&locals[slot] - entries));
844 }
845
846 inline FrameEntry *
847 FrameState::getArg(uint32 slot)
848 {
849     JS_ASSERT(slot < nargs);
850     return getOrTrack(uint32(&args[slot] - entries));
851 }
852
853 inline FrameEntry *
854 FrameState::getThis()
855 {
856     return getOrTrack(uint32(this_ - entries));
857 }
858
859 inline FrameEntry *
860 FrameState::getCallee()
861 {
862     // Callee can only be used in function code, and it's always an object.
863     JS_ASSERT(fun);
864     if (!callee_->isTracked()) {
865         addToTracker(callee_);
866         callee_->resetSynced();
867         callee_->setType(JSVAL_TYPE_OBJECT);
868     }
869     return callee_;
870 }
871
872 inline void
873 FrameState::pinReg(RegisterID reg)
874 {
875     regstate[reg].pin();
876 }
877
878 inline void
879 FrameState::unpinReg(RegisterID reg)
880 {
881     regstate[reg].unpin();
882 }
883
884 inline void
885 FrameState::unpinKilledReg(RegisterID reg)
886 {
887     regstate[reg].unpinUnsafe();
888     freeRegs.putReg(reg);
889 }
890
891 inline void
892 FrameState::forgetAllRegs(FrameEntry *fe)
893 {
894     if (fe->type.inRegister())
895         forgetReg(fe->type.reg());
896     if (fe->data.inRegister())
897         forgetReg(fe->data.reg());
898 }
899
900 inline void
901 FrameState::swapInTracker(FrameEntry *lhs, FrameEntry *rhs)
902 {
903     uint32 li = lhs->trackerIndex();
904     uint32 ri = rhs->trackerIndex();
905     JS_ASSERT(tracker[li] == lhs);
906     JS_ASSERT(tracker[ri] == rhs);
907     tracker.entries[ri] = lhs;
908     tracker.entries[li] = rhs;
909     lhs->index_ = ri;
910     rhs->index_ = li;
911 }
912
913 inline void
914 FrameState::dup()
915 {
916     dupAt(-1);
917 }
918
919 inline void
920 FrameState::dup2()
921 {
922     FrameEntry *lhs = peek(-2);
923     FrameEntry *rhs = peek(-1);
924     pushCopyOf(indexOfFe(lhs));
925     pushCopyOf(indexOfFe(rhs));
926 }
927
928 inline void
929 FrameState::dupAt(int32 n)
930 {
931     JS_ASSERT(n < 0);
932     FrameEntry *fe = peek(n);
933     pushCopyOf(indexOfFe(fe));
934 }
935
936 inline void
937 FrameState::pushLocal(uint32 n)
938 {
939     FrameEntry *fe = getLocal(n);
940     if (!isClosedVar(n)) {
941         pushCopyOf(indexOfFe(fe));
942     } else {
943 #ifdef DEBUG
944         /*
945          * We really want to assert on local variables, but in the presence of
946          * SETLOCAL equivocation of stack slots, and let expressions, just
947          * weakly assert on the fixed local vars.
948          */
949         FrameEntry *fe = &locals[n];
950         if (fe->isTracked() && n < script->nfixed) {
951             JS_ASSERT(fe->type.inMemory());
952             JS_ASSERT(fe->data.inMemory());
953         }
954 #endif
955         push(addressOf(fe));
956     }
957 }
958
959 inline void
960 FrameState::pushArg(uint32 n)
961 {
962     FrameEntry *fe = getArg(n);
963     if (!isClosedArg(n)) {
964         pushCopyOf(indexOfFe(fe));
965     } else {
966 #ifdef DEBUG
967         FrameEntry *fe = &args[n];
968         if (fe->isTracked()) {
969             JS_ASSERT(fe->type.inMemory());
970             JS_ASSERT(fe->data.inMemory());
971         }
972 #endif
973         push(addressOf(fe));
974     }
975 }
976
977 inline void
978 FrameState::pushCallee()
979 {
980     FrameEntry *fe = getCallee();
981     pushCopyOf(indexOfFe(fe));
982 }
983
984 inline void
985 FrameState::pushThis()
986 {
987     FrameEntry *fe = getThis();
988     pushCopyOf(indexOfFe(fe));
989 }
990
991 void
992 FrameState::learnThisIsObject()
993 {
994     // This is safe, albeit hacky. This is only called from the compiler,
995     // and only on the first use of |this| inside a basic block. Thus,
996     // there are no copies of |this| anywhere.
997     learnType(this_, JSVAL_TYPE_OBJECT);
998 }
999
1000 inline void
1001 FrameState::leaveBlock(uint32 n)
1002 {
1003     popn(n);
1004 }
1005
1006 inline void
1007 FrameState::enterBlock(uint32 n)
1008 {
1009     /* expect that tracker has 0 entries, for now. */
1010     JS_ASSERT(!tracker.nentries);
1011     JS_ASSERT(uint32(sp + n - locals) <= script->nslots);
1012
1013     if (!eval)
1014         memset(&closedVars[uint32(sp - locals)], 0, n * sizeof(*closedVars));
1015     sp += n;
1016 }
1017
1018 inline void
1019 FrameState::eviscerate(FrameEntry *fe)
1020 {
1021     forgetAllRegs(fe);
1022     fe->type.invalidate();
1023     fe->data.invalidate();
1024     fe->setNotCopied();
1025     fe->setCopyOf(NULL);
1026 }
1027
1028 inline void
1029 FrameState::setClosedVar(uint32 slot)
1030 {
1031     if (!eval)
1032         closedVars[slot] = true;
1033 }
1034
1035 inline void
1036 FrameState::setClosedArg(uint32 slot)
1037 {
1038     if (!eval && !usesArguments)
1039         closedArgs[slot] = true;
1040 }
1041
1042 inline StateRemat
1043 FrameState::dataRematInfo(const FrameEntry *fe) const
1044 {
1045     if (fe->isCopy())
1046         fe = fe->copyOf();
1047
1048     if (fe->data.inRegister())
1049         return StateRemat::FromRegister(fe->data.reg());
1050
1051     JS_ASSERT(fe->data.synced());
1052     return StateRemat::FromAddress(addressOf(fe));
1053 }
1054
1055 inline void
1056 FrameState::giveOwnRegs(FrameEntry *fe)
1057 {
1058     JS_ASSERT(!fe->isConstant());
1059     JS_ASSERT(fe == peek(-1));
1060
1061     if (!fe->isCopy())
1062         return;
1063
1064     RegisterID data = copyDataIntoReg(fe);
1065     if (fe->isTypeKnown()) {
1066         JSValueType type = fe->getKnownType();
1067         pop();
1068         pushTypedPayload(type, data);
1069     } else {
1070         RegisterID type = copyTypeIntoReg(fe);
1071         pop();
1072         pushRegs(type, data);
1073     }
1074 }
1075
1076 inline void
1077 FrameState::loadDouble(RegisterID t, RegisterID d, FrameEntry *fe, FPRegisterID fpReg,
1078                        Assembler &masm) const
1079 {
1080 #ifdef JS_CPU_X86
1081     masm.fastLoadDouble(d, t, fpReg);
1082 #else
1083     loadDouble(fe, fpReg, masm);
1084 #endif
1085 }
1086
1087 inline bool
1088 FrameState::tryFastDoubleLoad(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1089 {
1090 #ifdef JS_CPU_X86
1091     if (fe->type.inRegister() && fe->data.inRegister()) {
1092         masm.fastLoadDouble(fe->data.reg(), fe->type.reg(), fpReg);
1093         return true;
1094     }
1095 #endif
1096     return false;
1097 }
1098
1099 inline void
1100 FrameState::loadDouble(FrameEntry *fe, FPRegisterID fpReg, Assembler &masm) const
1101 {
1102     if (fe->isCopy()) {
1103         FrameEntry *backing = fe->copyOf();
1104         if (tryFastDoubleLoad(fe, fpReg, masm))
1105             return;
1106         if (backing->isCachedNumber() || (backing->type.synced() && backing->data.synced())) {
1107             masm.loadDouble(addressOf(backing), fpReg);
1108             return;
1109         }
1110         fe = backing;
1111     }
1112
1113     if (tryFastDoubleLoad(fe, fpReg, masm))
1114         return;
1115
1116     if ((fe->type.synced() && fe->data.synced()) || fe->isCachedNumber()) {
1117         masm.loadDouble(addressOf(fe), fpReg);
1118         return;
1119     }
1120
1121     ensureFeSynced(fe, masm);
1122     masm.loadDouble(addressOf(fe), fpReg);
1123 }
1124
1125 inline bool
1126 FrameState::isClosedVar(uint32 slot)
1127 {
1128     return eval || closedVars[slot];
1129 }
1130
1131 inline bool
1132 FrameState::isClosedArg(uint32 slot)
1133 {
1134     return eval || usesArguments || closedArgs[slot];
1135 }
1136
1137 class PinRegAcrossSyncAndKill
1138 {
1139     typedef JSC::MacroAssembler::RegisterID RegisterID;
1140     FrameState &frame;
1141     MaybeRegisterID maybeReg;
1142   public:
1143     PinRegAcrossSyncAndKill(FrameState &frame, RegisterID reg)
1144       : frame(frame), maybeReg(reg)
1145     {
1146         frame.pinReg(reg);
1147     }
1148     PinRegAcrossSyncAndKill(FrameState &frame, MaybeRegisterID maybeReg)
1149       : frame(frame), maybeReg(maybeReg)
1150     {
1151         if (maybeReg.isSet())
1152             frame.pinReg(maybeReg.reg());
1153     }
1154     ~PinRegAcrossSyncAndKill() {
1155         if (maybeReg.isSet())
1156             frame.unpinKilledReg(maybeReg.reg());
1157     }
1158 };
1159
1160 } /* namespace mjit */
1161 } /* namespace js */
1162
1163 #endif /* include */
1164