1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
24 * David Anderson <danderson@mozilla.com>
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.
38 * ***** END LICENSE BLOCK ***** */
40 #if !defined jsjaeger_framestate_inl_h__ && defined JS_METHODJIT
41 #define jsjaeger_framestate_inl_h__
47 FrameState::addToTracker(FrameEntry
*fe
)
49 JS_ASSERT(!fe
->isTracked());
50 fe
->track(tracker
.nentries
);
52 JS_ASSERT(tracker
.nentries
<= script
->nslots
);
56 FrameState::peek(int32 depth
)
59 JS_ASSERT(sp
+ depth
>= spBase
);
60 FrameEntry
*fe
= &sp
[depth
];
61 if (!fe
->isTracked()) {
69 FrameState::popn(uint32 n
)
71 for (uint32 i
= 0; i
< n
; i
++)
76 FrameState::haveSameBacking(FrameEntry
*lhs
, FrameEntry
*rhs
)
85 inline JSC::MacroAssembler::RegisterID
86 FrameState::allocReg()
89 if (!freeRegs
.empty()) {
90 reg
= freeRegs
.takeAnyReg();
93 regstate
[reg
].forget();
99 inline JSC::MacroAssembler::RegisterID
100 FrameState::allocReg(uint32 mask
)
103 if (freeRegs
.hasRegInMask(mask
)) {
104 reg
= freeRegs
.takeRegInMask(mask
);
106 reg
= evictSomeReg(mask
);
107 regstate
[reg
].forget();
113 inline JSC::MacroAssembler::RegisterID
114 FrameState::allocReg(FrameEntry
*fe
, RematInfo::RematType type
)
117 if (!freeRegs
.empty()) {
118 reg
= freeRegs
.takeAnyReg();
120 reg
= evictSomeReg();
121 regstate
[reg
].forget();
124 regstate
[reg
].associate(fe
, type
);
130 FrameState::emitLoadTypeTag(FrameEntry
*fe
, RegisterID reg
) const
132 emitLoadTypeTag(this->masm
, fe
, reg
);
136 FrameState::emitLoadTypeTag(Assembler
&masm
, FrameEntry
*fe
, RegisterID reg
) const
140 masm
.loadTypeTag(addressOf(fe
), reg
);
144 FrameState::convertInt32ToDouble(Assembler
&masm
, FrameEntry
*fe
, FPRegisterID fpreg
) const
146 JS_ASSERT(!fe
->isConstant());
151 if (fe
->data
.inRegister())
152 masm
.convertInt32ToDouble(fe
->data
.reg(), fpreg
);
154 masm
.convertInt32ToDouble(addressOf(fe
), fpreg
);
158 FrameState::peekTypeInRegister(FrameEntry
*fe
) const
162 return fe
->type
.inRegister();
168 JS_ASSERT(sp
> spBase
);
170 FrameEntry
*fe
= --sp
;
171 if (!fe
->isTracked())
178 FrameState::freeReg(RegisterID reg
)
180 JS_ASSERT(!regstate
[reg
].usedBy());
182 freeRegs
.putReg(reg
);
186 FrameState::forgetReg(RegisterID reg
)
189 * Important: Do not touch the fe here. We can peephole optimize away
190 * loads and stores by re-using the contents of old FEs.
192 JS_ASSERT_IF(regstate
[reg
].fe(), !regstate
[reg
].fe()->isCopy());
194 if (!regstate
[reg
].isPinned()) {
195 regstate
[reg
].forget();
196 freeRegs
.putReg(reg
);
201 FrameState::syncAndForgetEverything(uint32 newStackDepth
)
203 syncAndForgetEverything();
204 sp
= spBase
+ newStackDepth
;
208 FrameState::rawPush()
210 JS_ASSERT(unsigned(sp
- entries
) < nargs
+ script
->nslots
);
212 if (!sp
->isTracked())
219 FrameState::push(const Value
&v
)
221 FrameEntry
*fe
= rawPush();
222 fe
->setConstant(Jsvalify(v
));
226 FrameState::pushSynced()
234 FrameState::pushSyncedType(JSValueType type
)
236 FrameEntry
*fe
= rawPush();
243 FrameState::pushSynced(JSValueType type
, RegisterID reg
)
245 FrameEntry
*fe
= rawPush();
251 fe
->data
.setRegister(reg
);
252 regstate
[reg
].associate(fe
, RematInfo::DATA
);
256 FrameState::push(Address address
)
258 FrameEntry
*fe
= rawPush();
263 /* Prevent us from clobbering this reg. */
264 bool free
= freeRegs
.hasReg(address
.base
);
266 freeRegs
.takeReg(address
.base
);
268 RegisterID dreg
= allocReg(fe
, RematInfo::DATA
);
269 masm
.loadPayload(address
, dreg
);
270 fe
->data
.setRegister(dreg
);
272 /* Now it's safe to grab this register again. */
274 freeRegs
.putReg(address
.base
);
276 RegisterID treg
= allocReg(fe
, RematInfo::TYPE
);
277 masm
.loadTypeTag(address
, treg
);
278 fe
->type
.setRegister(treg
);
282 FrameState::pushRegs(RegisterID type
, RegisterID data
)
284 JS_ASSERT(!freeRegs
.hasReg(type
) && !freeRegs
.hasReg(data
));
286 FrameEntry
*fe
= rawPush();
289 fe
->type
.setRegister(type
);
290 fe
->data
.setRegister(data
);
291 regstate
[type
].associate(fe
, RematInfo::TYPE
);
292 regstate
[data
].associate(fe
, RematInfo::DATA
);
296 FrameState::pushTypedPayload(JSValueType type
, RegisterID payload
)
298 JS_ASSERT(!freeRegs
.hasReg(payload
));
300 FrameEntry
*fe
= rawPush();
304 fe
->data
.setRegister(payload
);
305 regstate
[payload
].associate(fe
, RematInfo::DATA
);
309 FrameState::pushNumber(MaybeRegisterID payload
, bool asInt32
)
311 JS_ASSERT_IF(payload
.isSet(), !freeRegs
.hasReg(payload
.reg()));
313 FrameEntry
*fe
= rawPush();
316 JS_ASSERT(!fe
->isNumber
);
319 if (!fe
->type
.synced())
320 masm
.storeTypeTag(ImmType(JSVAL_TYPE_INT32
), addressOf(fe
));
321 fe
->type
.setMemory();
323 fe
->type
.setMemory();
327 if (payload
.isSet()) {
329 fe
->data
.setRegister(payload
.reg());
330 regstate
[payload
.reg()].associate(fe
, RematInfo::DATA
);
332 fe
->data
.setMemory();
337 FrameState::pushInt32(RegisterID payload
)
339 FrameEntry
*fe
= rawPush();
341 JS_ASSERT(!fe
->isNumber
);
343 masm
.storeTypeTag(ImmType(JSVAL_TYPE_INT32
), addressOf(fe
));
344 fe
->type
.setMemory();
348 fe
->data
.setRegister(payload
);
349 regstate
[payload
].associate(fe
, RematInfo::DATA
);
353 FrameState::pushUntypedPayload(JSValueType type
, RegisterID payload
)
355 JS_ASSERT(!freeRegs
.hasReg(payload
));
357 FrameEntry
*fe
= rawPush();
361 masm
.storeTypeTag(ImmType(type
), addressOf(fe
));
363 /* The forceful type sync will assert otherwise. */
367 fe
->type
.setMemory();
371 fe
->data
.setRegister(payload
);
372 regstate
[payload
].associate(fe
, RematInfo::DATA
);
375 inline JSC::MacroAssembler::RegisterID
376 FrameState::tempRegForType(FrameEntry
*fe
, RegisterID fallback
)
378 JS_ASSERT(!regstate
[fallback
].fe());
382 JS_ASSERT(!fe
->type
.isConstant());
384 if (fe
->type
.inRegister())
385 return fe
->type
.reg();
389 masm
.loadTypeTag(addressOf(fe
), fallback
);
394 inline JSC::MacroAssembler::RegisterID
395 FrameState::tempRegForType(FrameEntry
*fe
)
400 JS_ASSERT(!fe
->type
.isConstant());
402 if (fe
->type
.inRegister())
403 return fe
->type
.reg();
407 RegisterID reg
= allocReg(fe
, RematInfo::TYPE
);
408 masm
.loadTypeTag(addressOf(fe
), reg
);
409 fe
->type
.setRegister(reg
);
413 inline JSC::MacroAssembler::RegisterID
414 FrameState::tempRegForData(FrameEntry
*fe
)
416 JS_ASSERT(!fe
->data
.isConstant());
421 if (fe
->data
.inRegister())
422 return fe
->data
.reg();
424 RegisterID reg
= allocReg(fe
, RematInfo::DATA
);
425 masm
.loadPayload(addressOf(fe
), reg
);
426 fe
->data
.setRegister(reg
);
430 inline JSC::MacroAssembler::RegisterID
431 FrameState::tempRegInMaskForData(FrameEntry
*fe
, uint32 mask
)
433 JS_ASSERT(!fe
->data
.isConstant());
439 if (fe
->data
.inRegister()) {
440 RegisterID old
= fe
->data
.reg();
441 if (Registers::maskReg(old
) & mask
)
444 /* Keep the old register pinned. */
445 regstate
[old
].forget();
446 reg
= allocReg(mask
);
450 reg
= allocReg(mask
);
451 masm
.loadPayload(addressOf(fe
), reg
);
453 regstate
[reg
].associate(fe
, RematInfo::DATA
);
454 fe
->data
.setRegister(reg
);
458 inline JSC::MacroAssembler::RegisterID
459 FrameState::tempRegForData(FrameEntry
*fe
, RegisterID reg
, Assembler
&masm
) const
461 JS_ASSERT(!fe
->data
.isConstant());
466 if (fe
->data
.inRegister()) {
467 JS_ASSERT(fe
->data
.reg() != reg
);
468 return fe
->data
.reg();
470 masm
.loadPayload(addressOf(fe
), reg
);
476 FrameState::shouldAvoidTypeRemat(FrameEntry
*fe
)
478 return fe
->type
.inMemory();
482 FrameState::shouldAvoidDataRemat(FrameEntry
*fe
)
484 return fe
->data
.inMemory();
488 FrameState::syncType(const FrameEntry
*fe
, Address to
, Assembler
&masm
) const
490 JS_ASSERT_IF(fe
->type
.synced(),
491 fe
->isCopied() && addressOf(fe
).offset
!= to
.offset
);
492 JS_ASSERT(fe
->type
.inRegister() || fe
->type
.isConstant());
494 if (fe
->type
.isConstant()) {
495 JS_ASSERT(fe
->isTypeKnown());
496 masm
.storeTypeTag(ImmType(fe
->getKnownType()), to
);
498 masm
.storeTypeTag(fe
->type
.reg(), to
);
503 FrameState::syncData(const FrameEntry
*fe
, Address to
, Assembler
&masm
) const
505 JS_ASSERT_IF(addressOf(fe
).base
== to
.base
&&
506 addressOf(fe
).offset
== to
.offset
,
508 JS_ASSERT(fe
->data
.inRegister() || fe
->data
.isConstant());
510 if (fe
->data
.isConstant()) {
511 if (!fe
->type
.synced())
512 masm
.storeValue(fe
->getValue(), to
);
514 #if defined JS_NUNBOX32
515 masm
.storePayload(Imm32(fe
->getPayload32()), to
);
516 #elif defined JS_PUNBOX64
517 masm
.storePayload(Imm64(fe
->getPayload64()), to
);
520 masm
.storePayload(fe
->data
.reg(), to
);
525 FrameState::forgetType(FrameEntry
*fe
)
527 JS_ASSERT(fe
->isTypeKnown() && !fe
->type
.synced());
528 syncType(fe
, addressOf(fe
), masm
);
529 fe
->type
.setMemory();
533 FrameState::learnType(FrameEntry
*fe
, JSValueType type
)
535 if (fe
->type
.inRegister())
536 forgetReg(fe
->type
.reg());
538 fe
->isNumber
= false;
543 inline JSC::MacroAssembler::Address
544 FrameState::addressOf(const FrameEntry
*fe
) const
546 uint32 index
= (fe
- entries
);
547 JS_ASSERT(index
>= nargs
);
549 return Address(JSFrameReg
, sizeof(JSStackFrame
) + sizeof(Value
) * index
);
552 inline JSC::MacroAssembler::Address
553 FrameState::addressForDataRemat(const FrameEntry
*fe
) const
555 if (fe
->isCopy() && !fe
->data
.synced())
557 JS_ASSERT(fe
->data
.synced());
558 return addressOf(fe
);
561 inline JSC::MacroAssembler::Jump
562 FrameState::testNull(Assembler::Condition cond
, FrameEntry
*fe
)
564 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
565 if (shouldAvoidTypeRemat(fe
))
566 return masm
.testNull(cond
, addressOf(fe
));
567 return masm
.testNull(cond
, tempRegForType(fe
));
570 inline JSC::MacroAssembler::Jump
571 FrameState::testInt32(Assembler::Condition cond
, FrameEntry
*fe
)
573 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
574 if (shouldAvoidTypeRemat(fe
))
575 return masm
.testInt32(cond
, addressOf(fe
));
576 return masm
.testInt32(cond
, tempRegForType(fe
));
579 inline JSC::MacroAssembler::Jump
580 FrameState::testPrimitive(Assembler::Condition cond
, FrameEntry
*fe
)
582 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
583 if (shouldAvoidTypeRemat(fe
))
584 return masm
.testPrimitive(cond
, addressOf(fe
));
585 return masm
.testPrimitive(cond
, tempRegForType(fe
));
588 inline JSC::MacroAssembler::Jump
589 FrameState::testObject(Assembler::Condition cond
, FrameEntry
*fe
)
591 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
592 if (shouldAvoidTypeRemat(fe
))
593 return masm
.testObject(cond
, addressOf(fe
));
594 return masm
.testObject(cond
, tempRegForType(fe
));
597 inline JSC::MacroAssembler::Jump
598 FrameState::testDouble(Assembler::Condition cond
, FrameEntry
*fe
)
600 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
601 if (shouldAvoidTypeRemat(fe
))
602 return masm
.testDouble(cond
, addressOf(fe
));
603 return masm
.testDouble(cond
, tempRegForType(fe
));
606 inline JSC::MacroAssembler::Jump
607 FrameState::testBoolean(Assembler::Condition cond
, FrameEntry
*fe
)
609 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
610 if (shouldAvoidTypeRemat(fe
))
611 return masm
.testBoolean(cond
, addressOf(fe
));
612 return masm
.testBoolean(cond
, tempRegForType(fe
));
615 inline JSC::MacroAssembler::Jump
616 FrameState::testString(Assembler::Condition cond
, FrameEntry
*fe
)
618 JS_ASSERT(cond
== Assembler::Equal
|| cond
== Assembler::NotEqual
);
619 if (shouldAvoidTypeRemat(fe
))
620 return masm
.testString(cond
, addressOf(fe
));
621 return masm
.testString(cond
, tempRegForType(fe
));
625 FrameState::getLocal(uint32 slot
)
627 uint32 index
= nargs
+ slot
;
628 FrameEntry
*fe
= &entries
[index
];
629 if (!fe
->isTracked()) {
637 FrameState::pinReg(RegisterID reg
)
643 FrameState::unpinReg(RegisterID reg
)
645 regstate
[reg
].unpin();
649 FrameState::unpinKilledReg(RegisterID reg
)
651 regstate
[reg
].unpinUnsafe();
652 freeRegs
.putReg(reg
);
656 FrameState::forgetAllRegs(FrameEntry
*fe
)
658 if (fe
->type
.inRegister())
659 forgetReg(fe
->type
.reg());
660 if (fe
->data
.inRegister())
661 forgetReg(fe
->data
.reg());
665 FrameState::swapInTracker(FrameEntry
*lhs
, FrameEntry
*rhs
)
667 uint32 li
= lhs
->trackerIndex();
668 uint32 ri
= rhs
->trackerIndex();
669 JS_ASSERT(tracker
[li
] == lhs
);
670 JS_ASSERT(tracker
[ri
] == rhs
);
671 tracker
.entries
[ri
] = lhs
;
672 tracker
.entries
[li
] = rhs
;
678 FrameState::localIndex(uint32 n
)
692 FrameEntry
*lhs
= peek(-2);
693 FrameEntry
*rhs
= peek(-1);
694 pushCopyOf(indexOfFe(lhs
));
695 pushCopyOf(indexOfFe(rhs
));
699 FrameState::dupAt(int32 n
)
702 FrameEntry
*fe
= peek(n
);
703 pushCopyOf(indexOfFe(fe
));
707 FrameState::pushLocal(uint32 n
)
709 if (!eval
&& !escaping
[n
]) {
710 pushCopyOf(indexOfFe(getLocal(n
)));
714 * We really want to assert on local variables, but in the presence of
715 * SETLOCAL equivocation of stack slots, and let expressions, just
716 * weakly assert on the fixed local vars.
718 FrameEntry
*fe
= &locals
[n
];
719 if (fe
->isTracked() && n
< script
->nfixed
) {
720 JS_ASSERT(fe
->type
.inMemory());
721 JS_ASSERT(fe
->data
.inMemory());
724 push(Address(JSFrameReg
, sizeof(JSStackFrame
) + n
* sizeof(Value
)));
729 FrameState::leaveBlock(uint32 n
)
735 FrameState::enterBlock(uint32 n
)
737 /* expect that tracker has 0 entries, for now. */
738 JS_ASSERT(!tracker
.nentries
);
739 JS_ASSERT(uint32(sp
+ n
- locals
) <= script
->nslots
);
745 FrameState::eviscerate(FrameEntry
*fe
)
748 fe
->type
.invalidate();
749 fe
->data
.invalidate();
755 FrameState::addEscaping(uint32 local
)
758 uint32 already
= escaping
[local
];
766 FrameState::dataRematInfo(const FrameEntry
*fe
) const
771 if (fe
->data
.inRegister()) {
772 remat
.reg
= fe
->data
.reg();
775 JS_ASSERT(fe
->data
.synced());
776 remat
.offset
= addressOf(fe
).offset
;
783 FrameState::giveOwnRegs(FrameEntry
*fe
)
785 JS_ASSERT(!fe
->isConstant());
786 JS_ASSERT(fe
== peek(-1));
791 RegisterID data
= copyDataIntoReg(fe
);
792 if (fe
->isTypeKnown()) {
793 JSValueType type
= fe
->getKnownType();
795 pushTypedPayload(type
, data
);
797 RegisterID type
= copyTypeIntoReg(fe
);
799 pushRegs(type
, data
);
804 FrameState::loadDouble(RegisterID t
, RegisterID d
, FrameEntry
*fe
, FPRegisterID fpReg
,
805 Assembler
&masm
) const
808 masm
.fastLoadDouble(d
, t
, fpReg
);
810 loadDouble(fe
, fpReg
, masm
);
815 FrameState::tryFastDoubleLoad(FrameEntry
*fe
, FPRegisterID fpReg
, Assembler
&masm
) const
818 if (fe
->type
.inRegister() && fe
->data
.inRegister()) {
819 masm
.fastLoadDouble(fe
->data
.reg(), fe
->type
.reg(), fpReg
);
827 FrameState::loadDouble(FrameEntry
*fe
, FPRegisterID fpReg
, Assembler
&masm
) const
830 FrameEntry
*backing
= fe
->copyOf();
831 if (tryFastDoubleLoad(fe
, fpReg
, masm
))
833 if (backing
->isCachedNumber() || (backing
->type
.synced() && backing
->data
.synced())) {
834 masm
.loadDouble(addressOf(backing
), fpReg
);
840 if (tryFastDoubleLoad(fe
, fpReg
, masm
))
843 if ((fe
->type
.synced() && fe
->data
.synced()) || fe
->isCachedNumber()) {
844 masm
.loadDouble(addressOf(fe
), fpReg
);
848 Address address
= addressOf(fe
);
850 if (!fe
->data
.synced()) {
851 syncData(fe
, address
, masm
);
852 if (fe
->isConstant())
855 if (!fe
->type
.synced())
856 syncType(fe
, address
, masm
);
859 masm
.loadDouble(address
, fpReg
);
862 } /* namspace mjit */