mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
281 lines
7.5 KiB
C++
281 lines
7.5 KiB
C++
/* -*- 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 */
|
|
|