diff options
Diffstat (limited to 'js/src/methodjit/ImmutableSync.cpp')
-rw-r--r-- | js/src/methodjit/ImmutableSync.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/js/src/methodjit/ImmutableSync.cpp b/js/src/methodjit/ImmutableSync.cpp new file mode 100644 index 0000000..05d2da0 --- /dev/null +++ b/js/src/methodjit/ImmutableSync.cpp @@ -0,0 +1,281 @@ +/* -*- 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 <brendan@mozilla.org> + * + * Contributor(s): + * David Anderson <danderson@mozilla.com> + * + * 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 */ + |