/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=4 sw=4 et tw=99: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released * May 28, 2008. * * The Initial Developer of the Original Code is * Brendan Eich * * Contributor(s): * David Anderson * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #if defined JS_NUNBOX32 #include "FrameEntry.h" #include "FrameState.h" #include "FrameState-inl.h" #include "ImmutableSync.h" using namespace js; using namespace js::mjit; ImmutableSync::ImmutableSync(JSContext *cx, const FrameState &frame) : cx(cx), entries(NULL), frame(frame), generation(0) { } ImmutableSync::~ImmutableSync() { cx->free(entries); } bool ImmutableSync::init(uint32 nentries) { entries = (SyncEntry *)cx->calloc(sizeof(SyncEntry) * nentries); return !!entries; } void ImmutableSync::reset(Assembler *masm, Registers avail, FrameEntry *top, FrameEntry *bottom) { this->avail = avail; this->masm = masm; this->top = top; this->bottom = bottom; this->generation++; memset(regs, 0, sizeof(regs)); } JSC::MacroAssembler::RegisterID ImmutableSync::allocReg() { if (!avail.empty()) return avail.takeAnyReg(); uint32 lastResort = FrameState::InvalidIndex; uint32 evictFromFrame = FrameState::InvalidIndex; /* Find something to evict. */ for (uint32 i = 0; i < JSC::MacroAssembler::TotalRegisters; i++) { RegisterID reg = RegisterID(i); if (!(Registers::maskReg(reg) & Registers::AvailRegs)) continue; lastResort = 0; if (!regs[i]) { /* If the frame does not own this register, take it! */ FrameEntry *fe = frame.regstate[i].usedBy(); if (!fe) return reg; evictFromFrame = i; /* * If not copied, we can sync and not have to load again later. * That's about as good as it gets, so just break out now. */ if (!fe->isCopied()) break; } } if (evictFromFrame != FrameState::InvalidIndex) { FrameEntry *fe = frame.regstate[evictFromFrame].usedBy(); SyncEntry &e = entryFor(fe); if (frame.regstate[evictFromFrame].type() == RematInfo::TYPE) { JS_ASSERT(!e.typeClobbered); e.typeClobbered = true; } else { JS_ASSERT(!e.dataClobbered); e.dataClobbered = true; } return RegisterID(evictFromFrame); } JS_ASSERT(lastResort != FrameState::InvalidIndex); JS_ASSERT(regs[lastResort]); SyncEntry *e = regs[lastResort]; RegisterID reg = RegisterID(lastResort); if (e->hasDataReg && e->dataReg == reg) { e->hasDataReg = false; } else if (e->hasTypeReg && e->typeReg == reg) { e->hasTypeReg = false; } else { JS_NOT_REACHED("no way"); } return reg; } inline ImmutableSync::SyncEntry & ImmutableSync::entryFor(FrameEntry *fe) { JS_ASSERT(fe <= top); SyncEntry &e = entries[frame.indexOfFe(fe)]; if (e.generation != generation) e.reset(generation); return e; } void ImmutableSync::sync(FrameEntry *fe) { #ifdef DEBUG top = fe; #endif if (fe->isCopy()) syncCopy(fe); else syncNormal(fe); } bool ImmutableSync::shouldSyncType(FrameEntry *fe, SyncEntry &e) { /* Registers are synced up-front. */ return !fe->type.synced() && !fe->type.inRegister(); } bool ImmutableSync::shouldSyncData(FrameEntry *fe, SyncEntry &e) { /* Registers are synced up-front. */ return !fe->data.synced() && !fe->data.inRegister(); } JSC::MacroAssembler::RegisterID ImmutableSync::ensureTypeReg(FrameEntry *fe, SyncEntry &e) { if (fe->type.inRegister() && !e.typeClobbered) return fe->type.reg(); if (e.hasTypeReg) return e.typeReg; e.typeReg = allocReg(); e.hasTypeReg = true; regs[e.typeReg] = &e; masm->loadTypeTag(frame.addressOf(fe), e.typeReg); return e.typeReg; } JSC::MacroAssembler::RegisterID ImmutableSync::ensureDataReg(FrameEntry *fe, SyncEntry &e) { if (fe->data.inRegister() && !e.dataClobbered) return fe->data.reg(); if (e.hasDataReg) return e.dataReg; e.dataReg = allocReg(); e.hasDataReg = true; regs[e.dataReg] = &e; masm->loadPayload(frame.addressOf(fe), e.dataReg); return e.dataReg; } void ImmutableSync::syncCopy(FrameEntry *fe) { JS_ASSERT(fe >= bottom); FrameEntry *backing = fe->copyOf(); SyncEntry &e = entryFor(backing); JS_ASSERT(!backing->isConstant()); Address addr = frame.addressOf(fe); if (fe->isTypeKnown() && !e.learnedType) { e.learnedType = true; e.type = fe->getKnownType(); } if (!fe->data.synced()) masm->storePayload(ensureDataReg(backing, e), addr); if (!fe->type.synced()) { if (e.learnedType) masm->storeTypeTag(ImmType(e.type), addr); else masm->storeTypeTag(ensureTypeReg(backing, e), addr); } } void ImmutableSync::syncNormal(FrameEntry *fe) { SyncEntry &e = entryFor(fe); Address addr = frame.addressOf(fe); if (fe->isTypeKnown()) { e.learnedType = true; e.type = fe->getKnownType(); } if (shouldSyncData(fe, e)) { if (fe->isConstant()) { masm->storeValue(fe->getValue(), addr); return; } masm->storePayload(ensureDataReg(fe, e), addr); } if (shouldSyncType(fe, e)) { if (e.learnedType) masm->storeTypeTag(ImmType(e.type), addr); else masm->storeTypeTag(ensureTypeReg(fe, e), addr); } if (e.hasDataReg) { avail.putReg(e.dataReg); regs[e.dataReg] = NULL; } else if (!e.dataClobbered && fe->data.inRegister() && frame.regstate[fe->data.reg()].usedBy()) { avail.putReg(fe->data.reg()); } if (e.hasTypeReg) { avail.putReg(e.typeReg); regs[e.typeReg] = NULL; } else if (!e.typeClobbered && fe->type.inRegister() && frame.regstate[fe->type.reg()].usedBy()) { avail.putReg(fe->type.reg()); } } #endif /* JS_NUNBOX32 */