Compare commits

..

2 Commits

Author SHA1 Message Date
fur%netscape.com
1c43d4984f This is a copy of regalloc_code2_BRANCH from Netscape's private repository,
as it existed in January of 1998.


git-svn-id: svn://10.0.0.236/branches/regalloc_code2_BRANCH@22571 18797224-902f-48f8-a5cc-f745e15eee43
1999-03-02 16:12:08 +00:00
(no author)
cfe021ff88 This commit was manufactured by cvs2svn to create branch
'regalloc_code2_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/regalloc_code2_BRANCH@22567 18797224-902f-48f8-a5cc-f745e15eee43
1999-03-02 15:57:58 +00:00
167 changed files with 5324 additions and 56052 deletions

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "BitSet.h"
// Return the next bit after index set to true or -1 if none.
//
Int32 BitSet::nextOne(Int32 pos) const
{
++pos;
if (pos < 0 || Uint32(pos) >= universeSize)
return -1;
Uint32 offset = getWordOffset(pos);
Uint8 index = getBitOffset(pos);
Word* ptr = &word[offset];
Word currentWord = *ptr++ >> index;
if (currentWord != Word(0)) {
while ((currentWord & Word(1)) == 0) {
++index;
currentWord >>= 1;
}
return (offset << nBitsInWordLog2) + index;
}
Word* limit = &word[getSizeInWords(universeSize)];
while (ptr < limit) {
++offset;
currentWord = *ptr++;
if (currentWord != Word(0)) {
index = 0;
while ((currentWord & Word(1)) == 0) {
++index;
currentWord >>= 1;
}
return (offset << nBitsInWordLog2) + index;
}
}
return -1;
}
// Return the next bit after index set to false or -1 if none.
//
Int32 BitSet::nextZero(Int32 pos) const
{
++pos;
if (pos < 0 || Uint32(pos) >= universeSize)
return -1;
Uint32 offset = getWordOffset(pos);
Uint8 index = getBitOffset(pos);
Word* ptr = &word[offset];
Word currentWord = *ptr++ >> index;
if (currentWord != Word(~0)) {
for (; index < nBitsInWord; ++index) {
if ((currentWord & Word(1)) == 0) {
Int32 ret = (offset << nBitsInWordLog2) + index;
return (Uint32(ret) < universeSize) ? ret : -1;
}
currentWord >>= 1;
}
}
Word* limit = &word[getSizeInWords(universeSize)];
while (ptr < limit) {
++offset;
currentWord = *ptr++;
if (currentWord != Word(~0)) {
for (index = 0; index < nBitsInWord; ++index) {
if ((currentWord & Word(1)) == 0) {
Int32 ret = (offset << nBitsInWordLog2) + index;
return (Uint32(ret) < universeSize) ? ret : -1;
}
currentWord >>= 1;
}
}
}
return -1;
}
#ifdef DEBUG_LOG
// Print the set.
//
void BitSet::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("[ "));
for (Int32 i = firstOne(); i != -1; i = nextOne(i)) {
Int32 currentBit = i;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", currentBit));
Int32 nextBit = nextOne(currentBit);
if (nextBit != currentBit + 1) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" "));
continue;
}
while ((nextBit != -1) && (nextBit == (currentBit + 1))) {
currentBit = nextBit;
nextBit = nextOne(nextBit);
}
if (currentBit > (i+1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("-%d ", currentBit));
else
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" %d ", currentBit));
i = currentBit;
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("]\n"));
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,195 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _BITSET_H_
#define _BITSET_H_
#include "Fundamentals.h"
#include "LogModule.h"
#include "Pool.h"
#include <string.h>
//------------------------------------------------------------------------------
// BitSet -
class BitSet
{
private:
#if (PR_BITS_PER_WORD == 64)
typedef Uint64 Word;
#elif (PR_BITS_PER_WORD == 32)
typedef Uint32 Word;
#endif
static const nBitsInWord = PR_BITS_PER_WORD;
static const nBytesInWord = PR_BYTES_PER_WORD;
static const nBitsInWordLog2 = PR_BITS_PER_WORD_LOG2;
static const nBytesInWordLog2 = PR_BYTES_PER_WORD_LOG2;
// Return the number of Word need to store the universe.
static Uint32 getSizeInWords(Uint32 sizeOfUniverse) {return (sizeOfUniverse + (nBitsInWord - 1)) >> nBitsInWordLog2;}
// Return the given element offset in its containing Word.
static Uint32 getBitOffset(Uint32 element) {return element & (nBitsInWord - 1);}
// Return the Word offset for the given element int the universe.
static Uint32 getWordOffset(Uint32 element) {return element >> nBitsInWordLog2;}
// Return the mask for the given bit index.
static Word getMask(Uint8 index) {return Word(1) << index;}
private:
Uint32 universeSize; // Size of the universe
Word* word; // universe memory.
private:
// No copy constructor.
BitSet(const BitSet&);
// Check if the given set's universe is of the same size than this universe.
void checkUniverseCompatibility(const BitSet& set) const {assert(set.universeSize == universeSize);}
// Check if pos is valid for this set's universe.
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
public:
// Create a bitset of universeSize bits.
BitSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {word = new(pool) Word[getSizeInWords(universeSize)]; clear();}
// Return the size of this bitset.
Uint32 getSize() const {return universeSize;}
// Clear the bitset.
void clear() {memset(word, 0x00, getSizeInWords(universeSize) << nBytesInWordLog2);}
// Clear the bit at index.
void clear(Uint32 index) {checkMember(index); word[getWordOffset(index)] &= ~getMask(index);}
// Set the bitset.
void set() {memset(word, 0xFF, getSizeInWords(universeSize) << nBytesInWordLog2);}
// Set the bit at index.
void set(Uint32 index) {checkMember(index); word[getWordOffset(index)] |= getMask(index);}
// Return true if the bit at index is set.
bool test(Uint32 index) const {checkMember(index); return (word[getWordOffset(index)] & getMask(index)) != 0;}
// Union with the given bitset.
inline void or(const BitSet& set);
// Intersection with the given bitset.
inline void and(const BitSet& set);
// Difference with the given bitset.
inline void difference(const BitSet& set);
// Copy set.
inline BitSet& operator = (const BitSet& set);
// Return true if the bitset are identical.
friend bool operator == (const BitSet& set1, const BitSet& set2);
// Return true if the bitset are different.
friend bool operator != (const BitSet& set1, const BitSet& set2);
// Logical operators.
BitSet& operator |= (const BitSet& set) {or(set); return *this;}
BitSet& operator &= (const BitSet& set) {and(set); return *this;}
BitSet& operator -= (const BitSet& set) {difference(set); return *this;}
// Return the first bit at set to true or -1 if none.
Int32 firstOne() const {return nextOne(-1);}
// Return the next bit after index set to true or -1 if none.
Int32 nextOne(Int32 pos) const;
// Return the first bit at set to false or -1 if none.
Int32 firstZero() const {return nextZero(-1);}
// Return the next bit after index set to false or -1 if none.
Int32 nextZero(Int32 pos) const;
// Iterator to conform with the set API.
typedef Int32 iterator;
// Return true if the walk is ordered.
static bool isOrdered() {return true;}
// Return the iterator for the first element of this set.
iterator begin() const {return firstOne();}
// Return the next iterator.
iterator advance(iterator pos) const {return nextOne(pos);}
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos == -1;}
// Return the element corresponding to the given iterator.
Uint32 get(iterator pos) const {return pos;}
#ifdef DEBUG_LOG
// Print the set.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
// Union with the given bitset.
//
inline void BitSet::or(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ |= *src++;
}
// Intersection with the given bitset.
//
inline void BitSet::and(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ &= *src++;
}
// Difference with the given bitset.
//
inline void BitSet::difference(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ &= ~*src++;
}
// Copy the given set into this set.
//
inline BitSet& BitSet::operator = (const BitSet& set)
{
checkUniverseCompatibility(set);
if (this != &set)
memcpy(word, set.word, getSizeInWords(universeSize) << nBytesInWordLog2);
return *this;
}
// Return true if the given set is identical to this set.
inline bool operator == (const BitSet& set1, const BitSet& set2)
{
set1.checkUniverseCompatibility(set2);
if (&set1 == &set2)
return true;
return memcmp(set1.word, set2.word, BitSet::getSizeInWords(set1.universeSize) << BitSet::nBytesInWordLog2) == 0;
}
inline bool operator != (const BitSet& set1, const BitSet& set2) {return !(set1 == set2);}
#endif // _BITSET_H

View File

@@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _COALESCING_H_
#define _COALESCING_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "RegisterPressure.h"
#include "InterferenceGraph.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "SparseSet.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
#if 1
// Performing an ultra conservative coalescing meens that when we look at
// candidates (source,destination) for coalescing we need to make sure
// that the combined interference of the source and destination register
// will not exceed the total number of register available for the register
// class.
#define ULTRA_CONSERVATIVE_COALESCING
#else
// If we are not doing an ultra conservative coalescing we have to make sure
// that the total number of neighbor whose degree is greater than the total
// number of register is not greater than the total number of register.
#undef ULTRA_CONSERVATIVE_COALESCING
#endif
template <class RegisterPressure>
struct Coalescing
{
static bool coalesce(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
bool Coalescing<RegisterPressure>::coalesce(RegisterAllocator& registerAllocator)
{
Pool& pool = registerAllocator.pool;
// Initialize the lookup table
//
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* newRange = new RegisterName[2 * rangeCount];
RegisterName* coalescedRange = &newRange[rangeCount];
RegisterName* name2range = registerAllocator.name2range;
init(coalescedRange, rangeCount);
SparseSet interferences(pool, rangeCount);
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
bool removedInstructions = false;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.lndList;
Uint32 nNodes = controlGraph.nNodes;
// Walk the nodes in the loop nesting depth list.
for (Int32 n = nNodes - 1; n >= 0; n--) {
InstructionList& instructions = nodes[n]->getInstructions();
InstructionList::iterator it = instructions.begin();
while (!instructions.done(it)) {
Instruction& instruction = instructions.get(it);
it = instructions.advance(it);
if ((instruction.getFlags() & ifCopy) != 0) {
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
RegisterName source = findRoot(name2range[instruction.getInstructionUseBegin()[0].getRegisterName()], coalescedRange);
RegisterName destination = findRoot(name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()], coalescedRange);
if (source == destination) {
instruction.remove();
} else if (!iGraph.interfere(source, destination)) {
InterferenceVector* sourceVector = iGraph.getInterferenceVector(source);
InterferenceVector* destinationVector = iGraph.getInterferenceVector(destination);
#ifdef ULTRA_CONSERVATIVE_COALESCING
interferences.clear();
InterferenceVector* vector;
for (vector = sourceVector; vector != NULL; vector = vector->next) {
RegisterName* neighbors = vector->neighbors;
for (Uint32 i = 0; i < vector->count; i++)
interferences.set(findRoot(neighbors[i], coalescedRange));
}
for (vector = destinationVector; vector != NULL; vector = vector->next) {
RegisterName* neighbors = vector->neighbors;
for (Uint32 i = 0; i < vector->count; i++)
interferences.set(findRoot(neighbors[i], coalescedRange));
}
Uint32 count = interferences.getSize();
#else // ULTRA_CONSERVATIVE_COALESCING
trespass("not implemented");
Uint32 count = 0;
#endif // ULTRA_CONSERVATIVE_COALESCING
if (count < 6 /* FIX: should get the number from the class */) {
// Update the interferences vector.
if (sourceVector == NULL) {
iGraph.setInterferenceVector(source, destinationVector);
sourceVector = destinationVector;
} else if (destinationVector == NULL)
iGraph.setInterferenceVector(destination, sourceVector);
else {
InterferenceVector* last = NULL;
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next)
last = v;
assert(last);
last->next = destinationVector;
iGraph.setInterferenceVector(destination, sourceVector);
}
// Update the interference matrix.
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next) {
RegisterName* neighbors = v->neighbors;
for (Uint32 i = 0; i < v->count; i++) {
RegisterName neighbor = findRoot(neighbors[i], coalescedRange);
iGraph.setInterference(neighbor, source);
iGraph.setInterference(neighbor, destination);
}
}
instruction.remove();
coalescedRange[source] = destination;
removedInstructions = true;
}
}
}
}
}
registerAllocator.rangeCount = compress(registerAllocator.name2range, coalescedRange, registerAllocator.nameCount, rangeCount);
delete newRange;
return removedInstructions;
}
#endif // _COALESCING_H_

View File

@@ -0,0 +1,283 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef NEW_LAURENTM_CODE
#include "Coloring.h"
#include "VirtualRegister.h"
#include "FastBitSet.h"
#include "FastBitMatrix.h"
#include "CpuInfo.h"
bool Coloring::
assignRegisters(FastBitMatrix& interferenceMatrix)
{
PRUint32 *stackPtr = new(pool) PRUint32[vRegManager.count()];
return select(interferenceMatrix, stackPtr, simplify(interferenceMatrix, stackPtr));
}
PRInt32 Coloring::
getLowestSpillCostRegister(FastBitSet& bitset)
{
PRInt32 lowest = bitset.firstOne();
if (lowest != -1)
{
Flt32 cost = vRegManager.getVirtualRegister(lowest).spillInfo.spillCost;
for (PRInt32 r = bitset.nextOne(lowest); r != -1; r = bitset.nextOne(r))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
if (!vReg.spillInfo.infiniteSpillCost && (vReg.spillInfo.spillCost < cost))
{
cost = vReg.spillInfo.spillCost;
lowest = r;
}
}
}
return lowest;
}
PRUint32* Coloring::
simplify(FastBitMatrix interferenceMatrix, PRUint32* stackPtr)
{
// first we construct the sets low and high. low contains all nodes of degree
// inferior to the number of register available on the processor. All the
// nodes with an high degree and a finite spill cost are placed in high.
// Nodes of high degree and infinite spill cost are not included in either sets.
PRUint32 nRegisters = vRegManager.count();
FastBitSet low(pool, nRegisters);
FastBitSet high(pool, nRegisters);
FastBitSet stack(pool, nRegisters);
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
if (vReg.getClass() == vrcStackSlot)
{
stack.set(i);
vReg.colorRegister(nRegisters);
}
else
{
if (vReg.colorInfo.interferenceDegree < NUMBER_OF_REGISTERS)
low.set(i);
else // if (!vReg.spillInfo.infiniteSpillCost)
high.set(i);
// Set coloring info.
vReg.spillInfo.willSpill = false;
switch(vReg.getClass())
{
case vrcInteger:
vReg.colorRegister(LAST_GREGISTER + 1);
break;
case vrcFloatingPoint:
case vrcFixedPoint:
vReg.colorRegister(LAST_FPREGISTER + 1);
break;
default:
PR_ASSERT(false); // Cannot happen.
}
}
}
// push the stack registers
PRInt32 j;
for (j = stack.firstOne(); j != -1; j = stack.nextOne(j))
*stackPtr++ = j;
// simplify
while (true)
{
PRInt32 r;
while ((r = getLowestSpillCostRegister(low)) != -1)
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
/* update low and high */
FastBitSet inter(interferenceMatrix.getRow(r), nRegisters);
for (j = inter.firstOne(); j != -1; j = inter.nextOne(j))
{
VirtualRegister& neighbor = vRegManager.getVirtualRegister(j);
// if the new interference degree of one of his neighbor becomes
// NUMBER_OF_REGISTERS - 1 then it is added to the set 'low'.
PRUint32 maxInterference = 0;
switch (neighbor.getClass())
{
case vrcInteger:
maxInterference = NUMBER_OF_GREGISTERS;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
maxInterference = NUMBER_OF_FPREGISTERS;
break;
default:
PR_ASSERT(false);
}
if ((vRegManager.getVirtualRegister(j).colorInfo.interferenceDegree-- == maxInterference))
{
high.clear(j);
low.set(j);
}
vReg.colorInfo.interferenceDegree--;
interferenceMatrix.clear(r, j);
interferenceMatrix.clear(j, r);
}
low.clear(r);
// Push this register.
*stackPtr++ = r;
}
if ((r = getLowestSpillCostRegister(high)) != -1)
{
high.clear(r);
low.set(r);
}
else
break;
}
return stackPtr;
}
bool Coloring::
select(FastBitMatrix& interferenceMatrix, PRUint32* stackBase, PRUint32* stackPtr)
{
PRUint32 nRegisters = vRegManager.count();
FastBitSet usedRegisters(NUMBER_OF_REGISTERS + 1); // usedRegisters if used for both GR & FPR.
FastBitSet preColoredRegisters(NUMBER_OF_REGISTERS + 1);
FastBitSet usedStack(nRegisters + 1);
bool success = true;
Int32 lastUsedSSR = -1;
// select
while (stackPtr != stackBase)
{
// Pop one register.
PRUint32 r = *--stackPtr;
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
FastBitSet neighbors(interferenceMatrix.getRow(r), nRegisters);
if (vReg.getClass() == vrcStackSlot)
// Stack slots coloring.
{
usedStack.clear();
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
usedStack.set(vRegManager.getVirtualRegister(i).getColor());
Int32 color = usedStack.firstZero();
vReg.colorRegister(color);
if (color > lastUsedSSR)
lastUsedSSR = color;
}
else
// Integer & Floating point register coloring.
{
usedRegisters.clear();
preColoredRegisters.clear();
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
{
VirtualRegister& nvReg = vRegManager.getVirtualRegister(i);
usedRegisters.set(nvReg.getColor());
if (nvReg.isPreColored())
preColoredRegisters.set(nvReg.getPreColor());
}
if (vReg.hasSpecialInterference)
usedRegisters |= vReg.specialInterference;
PRInt8 c = -1;
PRInt8 maxColor = 0;
PRInt8 firstColor = 0;
switch (vReg.getClass())
{
case vrcInteger:
firstColor = FIRST_GREGISTER;
maxColor = LAST_GREGISTER;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
firstColor = FIRST_FPREGISTER;
maxColor = LAST_FPREGISTER;
break;
default:
PR_ASSERT(false);
}
if (vReg.isPreColored())
{
c = vReg.getPreColor();
if (usedRegisters.test(c))
c = -1;
}
else
{
for (c = usedRegisters.nextZero(firstColor - 1); (c >= 0) && (c <= maxColor) && (preColoredRegisters.test(c));
c = usedRegisters.nextZero(c)) {}
}
if ((c >= 0) && (c <= maxColor))
{
vReg.colorRegister(c);
}
else
{
VirtualRegister& stackRegister = vRegManager.newVirtualRegister(vrcStackSlot);
vReg.equivalentRegister[vrcStackSlot] = &stackRegister;
vReg.spillInfo.willSpill = true;
success = false;
}
}
}
#ifdef DEBUG
if (success)
{
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
switch (vReg.getClass())
{
case vrcInteger:
if (vReg.getColor() > LAST_GREGISTER)
PR_ASSERT(false);
break;
case vrcFloatingPoint:
case vrcFixedPoint:
#if NUMBER_OF_FPREGISTERS != 0
if (vReg.getColor() > LAST_FPREGISTER)
PR_ASSERT(false);
#endif
break;
default:
break;
}
}
}
#endif
vRegManager.nUsedStackSlots = lastUsedSSR + 1;
return success;
}
#endif // NEW_LAURENTM_CODE

View File

@@ -0,0 +1,284 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "VirtualRegister.h"
#include "InterferenceGraph.h"
#include "SparseSet.h"
#include "Spilling.h"
#include "Splits.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
template <class RegisterPressure>
class Coloring
{
private:
static RegisterName* simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack);
static bool select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr);
public:
static bool color(RegisterAllocator& registerAllocator);
static void finalColoring(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
void Coloring<RegisterPressure>::finalColoring(RegisterAllocator& registerAllocator)
{
RegisterName* color = registerAllocator.color;
RegisterName* name2range = registerAllocator.name2range;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
usePtr->setRegisterName(color[name2range[usePtr->getRegisterName()]]);
#ifdef DEBUG
RegisterID rid = usePtr->getRegisterID();
setColoredRegister(rid);
usePtr->setRegisterID(rid);
#endif // DEBUG
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
definePtr->setRegisterName(color[name2range[definePtr->getRegisterName()]]);
#ifdef DEBUG
RegisterID rid = definePtr->getRegisterID();
setColoredRegister(rid);
definePtr->setRegisterID(rid);
#endif // DEBUG
}
}
}
}
template <class RegisterPressure>
bool Coloring<RegisterPressure>::select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* color = new RegisterName[rangeCount];
registerAllocator.color = color;
for (Uint32 r = 1; r < rangeCount; r++)
color[r] = RegisterName(6); // FIX;
// Color the preColored registers.
//
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
RegisterName* name2range = registerAllocator.name2range;
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
if (machinePtr->id != invalidID) {
color[name2range[getName(machinePtr->id)]] = machinePtr->color;
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill preColor range %d as %d\n", name2range[getName(machinePtr->id)], machinePtr->color));
}
SpillCost* cost = registerAllocator.spillCost;
Pool& pool = registerAllocator.pool;
SparseSet& spill = *new(pool) SparseSet(pool, rangeCount);
registerAllocator.willSpill = &spill;
SparseSet neighborColors(pool, 6); // FIX
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
bool coloringFailed = false;
while (coloringStackPtr > coloringStack) {
RegisterName range = *--coloringStackPtr;
if (!cost[range].infinite && cost[range].cost < 0) {
coloringFailed = true;
spill.set(range);
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, will spill.\n", range));
} else {
neighborColors.clear();
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = vector->count - 1; i >= 0; --i) {
RegisterName neighborColor = color[vector->neighbors[i]];
if (neighborColor < 6) // FIX
neighborColors.set(neighborColor);
}
if (neighborColors.getSize() == 6) { // FIX
coloringFailed = true;
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, ", range));
if (!Splits<RegisterPressure>::findSplit(registerAllocator, color, range)) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will spill.\n"));
spill.set(range);
} else
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will split.\n"));
} else {
for (Uint32 i = 0; i < 6; i++) // FIX
if (!neighborColors.test(i)) {
fprintf(stdout, "\twill color %d as %d\n", range, i);
color[range] = RegisterName(i);
break;
}
}
}
}
#ifdef DEBUG_LOG
if (coloringFailed) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring failed:\n"));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill spill: "));
spill.printPretty(UT_LOG_MODULE(RegAlloc));
} else {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring succeeded:\n"));
for (Uint32 i = 1; i < rangeCount; i++)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\trange %d colored as %d\n", i, color[i]));
}
#endif
return !coloringFailed;
}
template <class RegisterPressure>
RegisterName* Coloring<RegisterPressure>::simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack)
{
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
SpillCost* spillCost = registerAllocator.spillCost;
Uint32 rangeCount = registerAllocator.rangeCount;
Uint32* degree = new Uint32[rangeCount];
for (RegisterName i = RegisterName(1); i < rangeCount; i = RegisterName(i + 1)) {
InterferenceVector* vector = iGraph.getInterferenceVector(i);
degree[i] = (vector != NULL) ? vector->count : 0;
}
Pool& pool = registerAllocator.pool;
SparseSet low(pool, rangeCount);
SparseSet high(pool, rangeCount);
SparseSet highInfinite(pool, rangeCount);
SparseSet preColored(pool, rangeCount);
// Get the precolored registers.
//
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
RegisterName* name2range = registerAllocator.name2range;
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
if (machinePtr->id != invalidID)
preColored.set(name2range[getName(machinePtr->id)]);
// Insert the live ranges in the sets.
//
for (Uint32 range = 1; range < rangeCount; range++)
if (!preColored.test(range))
if (degree[range] < 6) // FIX
low.set(range);
else if (!spillCost[range].infinite)
high.set(range);
else
highInfinite.set(range);
#ifdef DEBUG_LOG
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring sets:\n\tlow = "));
low.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thigh = "));
high.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thighInfinite = "));
highInfinite.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tpreColored = "));
preColored.printPretty(UT_LOG_MODULE(RegAlloc));
#endif // DEBUG_LOG
RegisterName* coloringStackPtr = coloringStack;
while (low.getSize() != 0 || high.getSize() != 0) {
while (low.getSize() != 0) {
RegisterName range = RegisterName(low.getOne());
low.clear(range);
*coloringStackPtr++ = range;
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = (vector->count - 1); i >= 0; --i) {
RegisterName neighbor = vector->neighbors[i];
degree[neighbor]--;
if (degree[neighbor] < 6) // FIX
if (high.test(neighbor)) {
high.clear(neighbor);
low.set(neighbor);
} else if (highInfinite.test(neighbor)) {
highInfinite.clear(neighbor);
low.set(neighbor);
}
}
}
if (high.getSize() != 0) {
RegisterName best = RegisterName(high.getOne());
double bestCost = spillCost[best].cost;
double bestDegree = degree[best];
// Choose the next best candidate.
//
for (SparseSet::iterator i = high.begin(); !high.done(i); i = high.advance(i)) {
RegisterName range = RegisterName(high.get(i));
double thisCost = spillCost[range].cost;
double thisDegree = degree[range];
if (thisCost * bestDegree < bestCost * thisDegree) {
best = range;
bestCost = thisCost;
bestDegree = thisDegree;
}
}
high.clear(best);
low.set(best);
}
}
assert(highInfinite.getSize() == 0);
delete degree;
#ifdef DEBUG_LOG
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring stack:\n\t"));
for (RegisterName* sp = coloringStack; sp < coloringStackPtr; ++sp)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("%d ", *sp));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\n"));
#endif // DEBUG_LOG
return coloringStackPtr;
}
template <class RegisterPressure>
bool Coloring<RegisterPressure>::color(RegisterAllocator& registerAllocator)
{
RegisterName* coloringStack = new RegisterName[registerAllocator.rangeCount];
return select(registerAllocator, coloringStack, simplify(registerAllocator, coloringStack));
}

View File

@@ -0,0 +1,212 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include <string.h>
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "DominatorGraph.h"
DominatorGraph::DominatorGraph(ControlGraph& controlGraph) : controlGraph(controlGraph)
{
Uint32 nNodes = controlGraph.nNodes;
GtoV = new Uint32[nNodes + 1];
VtoG = new Uint32[nNodes + 1];
Uint32 v = 1;
for (Uint32 n = 0; n < nNodes; n++) {
VtoG[v] = n;
GtoV[n] = v++;
}
// Initialize all the 1-based arrays.
//
parent = new Uint32[v];
semi = new Uint32[v];
vertex = new Uint32[v];
label = new Uint32[v];
size = new Uint32[v];
ancestor = new Uint32[v];
child = new Uint32[v];
dom = new Uint32[v];
bucket = new DGLinkedList*[v];
memset(semi, '\0', v * sizeof(Uint32));
memset(bucket, '\0', v * sizeof(DGLinkedList*));
vCount = v;
build();
delete parent;
delete semi;
delete vertex;
delete label;
delete size;
delete ancestor;
delete child;
delete dom;
delete bucket;
}
Uint32 DominatorGraph::DFS(Uint32 vx, Uint32 n)
{
semi[vx] = ++n;
vertex[n] = label[vx] = vx;
ancestor[vx] = child[vx] = 0;
size[vx] = 1;
ControlNode& node = *controlGraph.dfsList[VtoG[vx]];
ControlEdge* successorEnd = node.getSuccessorsEnd();
for (ControlEdge* successorPtr = node.getSuccessorsBegin(); successorPtr < successorEnd; successorPtr++) {
Uint32 w = GtoV[successorPtr->getTarget().dfsNum];
if (semi[w] == 0) {
parent[w] = vx;
n = DFS(w, n);
}
}
return n;
}
void DominatorGraph::LINK(Uint32 vx, Uint32 w)
{
Uint32 s = w;
while (semi[label[w]] < semi[label[child[s]]]) {
if (size[s] + size[child[child[s]]] >= (size[child[s]] << 1)) {
ancestor[child[s]] = s;
child[s] = child[child[s]];
} else {
size[child[s]] = size[s];
s = ancestor[s] = child[s];
}
}
label[s] = label[w];
size[vx] += size[w];
if(size[vx] < (size[w] << 1)) {
Uint32 t = s;
s = child[vx];
child[vx] = t;
}
while( s != 0 ) {
ancestor[s] = vx;
s = child[s];
}
}
void DominatorGraph::COMPRESS(Uint32 vx)
{
if(ancestor[ancestor[vx]] != 0) {
COMPRESS(ancestor[vx]);
if(semi[label[ancestor[vx]]] < semi[label[vx]])
label[vx] = label[ancestor[vx]];
ancestor[vx] = ancestor[ancestor[vx]];
}
}
Uint32 DominatorGraph::EVAL(Uint32 vx)
{
if(ancestor[vx] == 0)
return label[vx];
COMPRESS(vx);
return (semi[label[ancestor[vx]]] >= semi[label[vx]]) ? label[vx] : label[ancestor[vx]];
}
void DominatorGraph::build()
{
Uint32 n = DFS(GtoV[0], 0);
size[0] = label[0] = semi[0];
for (Uint32 i = n; i >= 2; i--) {
Uint32 w = vertex[i];
ControlNode& node = *controlGraph.dfsList[VtoG[w]];
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
Uint32 vx = GtoV[predecessors.get(p).getSource().dfsNum];
Uint32 u = EVAL(vx);
if(semi[u] < semi[w])
semi[w] = semi[u];
}
DGLinkedList* elem = new DGLinkedList();
elem->next = bucket[vertex[semi[w]]];
elem->index = w;
bucket[vertex[semi[w]]] = elem;
LINK(parent[w], w);
elem = bucket[parent[w]];
while(elem != NULL) {
Uint32 vx = elem->index;
Uint32 u = EVAL(vx);
dom[vx] = (semi[u] < semi[vx]) ? u : parent[w];
elem = elem->next;
}
}
memset(size, '\0', n * sizeof(Uint32));
Pool& pool = controlGraph.pool;
nodes = new(pool) DGNode[n];
for(Uint32 j = 2; j <= n; j++) {
Uint32 w = vertex[j];
Uint32 d = dom[w];
if(d != vertex[semi[w]]) {
d = dom[d];
dom[w] = d;
}
size[d]++;
}
dom[GtoV[0]] = 0;
for (Uint32 k = 1; k <= n; k++) {
DGNode& node = nodes[VtoG[k]];
Uint32 count = size[k];
node.successorsEnd = node.successorsBegin = (count) ? new(pool) Uint32[count] : (Uint32*) 0;
}
for (Uint32 l = 2; l <= n; l++)
*(nodes[VtoG[dom[l]]].successorsEnd)++ = VtoG[l];
}
#ifdef DEBUG_LOG
void DominatorGraph::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Dominator Graph:\n"));
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 i = 0; i < nNodes; i++) {
DGNode& node = nodes[i];
if (node.successorsBegin != node.successorsEnd) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tN%d dominates ", i));
for (Uint32* successorsPtr = node.successorsBegin; successorsPtr < node.successorsEnd; successorsPtr++)
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d ", *successorsPtr));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _DOMINATOR_GRAPH_H_
#define _DOMINATOR_GRAPH_H_
#include "LogModule.h"
class ControlGraph;
struct DGNode
{
Uint32* successorsBegin;
Uint32* successorsEnd;
};
struct DGLinkedList
{
DGLinkedList* next;
Uint32 index;
};
class DominatorGraph
{
private:
ControlGraph& controlGraph;
Uint32 vCount;
Uint32* VtoG;
Uint32* GtoV;
Uint32* parent;
Uint32* semi;
Uint32* vertex;
Uint32* label;
Uint32* size;
Uint32* ancestor;
Uint32* child;
Uint32* dom;
DGLinkedList** bucket;
DGNode* nodes;
private:
void build();
Uint32 DFS(Uint32 vx, Uint32 n);
void LINK(Uint32 vx, Uint32 w);
void COMPRESS(Uint32 vx);
Uint32 EVAL(Uint32 vx);
public:
DominatorGraph(ControlGraph& controlGraph);
Uint32* getSuccessorsBegin(Uint32 n) const {return nodes[n].successorsBegin;}
Uint32* getSuccessorsEnd(Uint32 n) const {return nodes[n].successorsEnd;}
#ifdef DEBUG_LOG
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
#endif // _DOMINATOR_GRAPH_H_

View File

@@ -0,0 +1,20 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HashSet.h"

View File

@@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HASH_SET_H_
#define _HASH_SET_H_
#include "Fundamentals.h"
#include "Pool.h"
#include <string.h>
struct HashSetElement
{
Uint32 index;
HashSetElement* next;
};
class HashSet
{
private:
static const hashSize = 64;
// Return the hash code for the given element index.
static Uint32 getHashCode(Uint32 index) {return index & (hashSize - 1);} // Could be better !
private:
Pool& allocationPool;
HashSetElement** bucket;
HashSetElement* free;
private:
// No copy constructor.
HashSet(const HashSet&);
// No copy operator.
void operator = (const HashSet&);
public:
// Create a new HashSet.
inline HashSet(Pool& pool, Uint32 universeSize);
// Clear the hashset.
void clear();
// Clear the element for the given index.
void clear(Uint32 index);
// Set the element for the given index.
void set(Uint32 index);
// Return true if the element at index is a member.
bool test(Uint32 index) const;
// Union with the given hashset.
inline void or(const HashSet& set);
// Intersection with the given hashset.
inline void and(const HashSet& set);
// Difference with the given hashset.
inline void difference(const HashSet& set);
// Logical operators.
HashSet& operator |= (const HashSet& set) {or(set); return *this;}
HashSet& operator &= (const HashSet& set) {and(set); return *this;}
HashSet& operator -= (const HashSet& set) {difference(set); return *this;}
// Iterator to conform with the set API.
typedef HashSetElement* iterator;
// Return the iterator for the first element of this set.
iterator begin() const;
// Return the next iterator.
iterator advance(iterator pos) const;
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos == NULL;}
};
inline HashSet::HashSet(Pool& pool, Uint32 /*universeSize*/)
: allocationPool(pool), free(NULL)
{
bucket = new(pool) HashSetElement*[hashSize];
memset(bucket, '\0', sizeof(HashSetElement*));
}
#endif // _HASH_SET_H_

View File

@@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _INDEXED_POOL_H_
#define _INDEXED_POOL_H_
#include "Fundamentals.h"
#include <string.h>
#include <stdlib.h>
//------------------------------------------------------------------------------
// IndexedPool<IndexedObjectSubclass> is an indexed pool of objects. The
// template parameter 'IndexedObjectSubclass' must be a subclass of the struct
// IndexedObject.
//
// When the indexed pool is ask to allocate and initialize a new object (using
// the operator new(anIndexedPool) it will zero the memory used to store the
// object and initialize the field 'index' of this object to its position in
// the pool.
//
// An object allocated by the indexed pool can be freed by calling the method
// IndexedPool::release(IndexedElement& objectIndex).
//
// example:
//
// IndexedPool<IndexedElement> elementPool;
//
// IndexedElement& element1 = *new(elementPool) IndexedElement();
// IndexedElement& element2 = *new(elementPool) IndexedElement();
//
// indexedPool.release(element1);
// IndexedElement& element3 = *new(elementPool) IndexedElement();
//
// At this point element1 is no longer a valid object, element2 is at
// index 2 and element3 is at index 1.
//
//------------------------------------------------------------------------------
// IndexedObject -
//
template<class Object>
struct IndexedObject
{
Uint32 index; // Index in the pool.
Object* next; // Used to link IndexedObject together.
Uint32 getIndex() {return index;}
};
//------------------------------------------------------------------------------
// IndexedPool<IndexedObject> -
//
template <class IndexedObject>
class IndexedPool
{
private:
static const blockSize = 4; // Size of one block.
Uint32 nBlocks; // Number of blocks in the pool.
IndexedObject** block; // Array of block pointers.
IndexedObject* freeObjects; // Chained list of free IndexedObjects.
Uint32 nextIndex; // Index of the next free object in the last block.
private:
void allocateAnotherBlock();
IndexedObject& newObject();
public:
IndexedPool() : nBlocks(0), block(NULL), freeObjects(NULL), nextIndex(1) {}
~IndexedPool();
IndexedObject& get(Uint32 index) const;
void release(IndexedObject& object);
void setSize(Uint32 size) {assert(size < nextIndex); nextIndex = size;}
// Return the universe size.
Uint32 getSize() {return nextIndex;}
friend void* operator new(size_t, IndexedPool<IndexedObject>& pool); // Needs to call newObject().
};
// Free all the memory allocated for this object.
//
template <class IndexedObject>
IndexedPool<IndexedObject>::~IndexedPool()
{
for (Uint32 n = 0; n < nBlocks; n++)
free(&((IndexedObject **) &block[n][n*blockSize])[-(n + 1)]);
}
// Release the given. This object will be iserted in the chained
// list of free IndexedObjects. To minimize the fragmentation the chained list
// is ordered by ascending indexes.
//
template <class IndexedObject>
void IndexedPool<IndexedObject>::release(IndexedObject& object)
{
Uint32 index = object.index;
IndexedObject* list = freeObjects;
assert(&object == &get(index)); // Make sure that object is owned by this pool.
if (list == NULL) { // The list is empty.
freeObjects = &object;
object.next = NULL;
} else { // The list contains at least 1 element.
if (index < list->index) { // insert as first element.
freeObjects = &object;
object.next = list;
} else { // Find this object's place.
while ((list->next) != NULL && (list->next->index < index))
list = list->next;
object.next = list->next;
list->next = &object;
}
}
#ifdef DEBUG
// Sanity check to be sure that the list is correctly ordered.
for (IndexedObject* obj = freeObjects; obj != NULL; obj = obj->next)
if (obj->next != NULL)
assert(obj->index < obj->next->index);
#endif
}
// Create a new block of IndexedObjects. We will allocate the memory to
// store IndexedPool::blockSize IndexedObject and the new Array of block
// pointers.
// The newly created IndexedObjects will not be initialized.
//
template <class IndexedObject>
void IndexedPool<IndexedObject>::allocateAnotherBlock()
{
void* memory = (void *) malloc((nBlocks + 1) * sizeof(Uint32) + blockSize * sizeof(IndexedObject));
memcpy(memory, block, nBlocks * sizeof(Uint32));
block = (IndexedObject **) memory;
IndexedObject* objects = (IndexedObject *) &block[nBlocks + 1];
block[nBlocks] = &objects[-(nBlocks * blockSize)];
nBlocks++;
}
// Return the IndexedObject at the position 'index' in the pool.
//
template <class IndexedObject>
IndexedObject& IndexedPool<IndexedObject>::get(Uint32 index) const
{
Uint32 blockIndex = index / blockSize;
assert(blockIndex < nBlocks);
return block[blockIndex][index];
}
// Return the reference of an unused object in the pool.
//
template <class IndexedObject>
IndexedObject& IndexedPool<IndexedObject>::newObject()
{
if (freeObjects != NULL) {
IndexedObject& newObject = *freeObjects;
freeObjects = newObject.next;
return newObject;
}
Uint32 nextIndex = this->nextIndex++;
Uint32 blockIndex = nextIndex / blockSize;
while (blockIndex >= nBlocks)
allocateAnotherBlock();
IndexedObject& newObject = block[blockIndex][nextIndex];
newObject.index = nextIndex;
return newObject;
}
// Return the address of the next unsused object in the given
// indexed pool. The field index of the newly allocated object
// will be initialized to the corresponding index of this object
// in the pool.
//
template <class IndexedObject>
void* operator new(size_t size, IndexedPool<IndexedObject>& pool)
{
assert(size == sizeof(IndexedObject));
return (void *) &pool.newObject();
}
#endif // _INDEXED_POOL_H_

View File

@@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _INTERFERENCE_GRAPH_H_
#define _INTERFERENCE_GRAPH_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "Primitives.h"
#include "Instruction.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h"
#include "SparseSet.h"
#include <string.h>
struct InterferenceVector
{
Uint32 count;
InterferenceVector* next;
RegisterName* neighbors;
InterferenceVector() : count(0), next(NULL) {}
};
class RegisterAllocator;
template <class RegisterPressure>
class InterferenceGraph
{
private:
RegisterAllocator& registerAllocator;
RegisterPressure::Set* interferences;
InterferenceVector** vector;
Uint32* offset;
Uint32 rangeCount;
private:
// No copy constructor.
InterferenceGraph(const InterferenceGraph&);
// No copy operator.
void operator = (const InterferenceGraph&);
// Check if reg is a member of the universe.
void checkMember(RegisterName name) {assert(name < rangeCount);}
// Return the edge index for the interference between name1 and name2.
Uint32 getEdgeIndex(RegisterName name1, RegisterName name2);
public:
InterferenceGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
// Calculate the interferences.
void build();
// Return true if reg1 and reg2 interfere.
bool interfere(RegisterName name1, RegisterName name2);
// Return the interference vector for the given register or NULL if there is none.
InterferenceVector* getInterferenceVector(RegisterName name) {return vector[name];}
// Set the interference between name1 and name2.
void setInterference(RegisterName name1, RegisterName name2);
// Set the interference vector for the given register.
void setInterferenceVector(RegisterName name, InterferenceVector* v) {vector[name] = v;}
#ifdef DEBUG_LOG
// Print the interferences.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::build()
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
this->rangeCount = rangeCount;
// Initialize the structures.
//
offset = new(pool) Uint32[rangeCount + 1];
vector = new(pool) InterferenceVector*[rangeCount];
memset(vector, '\0', sizeof(InterferenceVector*) * rangeCount);
Uint32 o = 0;
offset[0] = 0;
for (Uint32 i = 1; i <= rangeCount; ++i) {
offset[i] = o;
o += i;
}
interferences = new(pool) RegisterPressure::Set(pool, (rangeCount * rangeCount) / 2);
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
LivenessInfo<RegisterPressure> liveness = Liveness<RegisterPressure>::analysis(controlGraph, rangeCount, name2range);
registerAllocator.liveness = liveness;
SparseSet currentLive(pool, rangeCount);
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
currentLive = liveness.liveOut[n];
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
// Handle the copy instruction to avoid unnecessary interference between the 2 registers.
if ((instruction.getFlags() & ifCopy) != 0) {
assert(useBegin != useEnd && useBegin[0].isRegister());
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
}
// Create the interferences.
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName define = name2range[definePtr->getRegisterName()];
for (SparseSet::iterator e = currentLive.begin(); !currentLive.done(e); e = currentLive.advance(e)) {
RegisterName live = RegisterName(currentLive.get(e));
if ((live != define) && !interfere(live, define) && registerAllocator.canInterfere(live, define)) {
if (vector[define] == NULL)
vector[define] = new(pool) InterferenceVector();
vector[define]->count++;
if (vector[live] == NULL)
vector[live] = new(pool) InterferenceVector();
vector[live]->count++;
setInterference(live, define);
}
}
}
// Now update the liveness.
//
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
currentLive.set(name2range[usePtr->getRegisterName()]);
}
}
// Allocate the memory to store the interferences.
//
for (Uint32 e = 0; e < rangeCount; e++)
if (vector[e] != NULL) {
InterferenceVector& v = *vector[e];
v.neighbors = new(pool) RegisterName[v.count];
v.count = 0;
}
// Initialize the edges.
//
if (RegisterPressure::Set::isOrdered()) {
RegisterName name1 = RegisterName(0);
for (RegisterPressure::Set::iterator i = interferences->begin(); !interferences->done(i); i = interferences->advance(i)) {
Uint32 interferenceIndex = interferences->get(i);
while(interferenceIndex >= offset[name1 + 1])
name1 = RegisterName(name1 + 1);
assert((interferenceIndex >= offset[name1]) && (interferenceIndex < offset[name1 + 1]));
RegisterName name2 = RegisterName(interferenceIndex - offset[name1]);
assert(interfere(name1, name2));
InterferenceVector& vector1 = *vector[name1];
vector1.neighbors[vector1.count++] = name2;
InterferenceVector& vector2 = *vector[name2];
vector2.neighbors[vector2.count++] = name1;
}
} else {
trespass("not Implemented"); // FIX: need one more pass to initialize the vectors.
}
}
template <class RegisterPressure>
Uint32 InterferenceGraph<RegisterPressure>::getEdgeIndex(RegisterName name1, RegisterName name2)
{
checkMember(name1); checkMember(name2);
assert(name1 != name2); // This is not possible.
return (name1 < name2) ? offset[name2] + name1 : offset[name1] + name2;
}
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::setInterference(RegisterName name1, RegisterName name2)
{
interferences->set(getEdgeIndex(name1, name2));
}
template <class RegisterPressure>
bool InterferenceGraph<RegisterPressure>::interfere(RegisterName name1, RegisterName name2)
{
return interferences->test(getEdgeIndex(name1, name2));
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Vectors:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
if (vector[i] != NULL) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tvr%d: (", i));
for (InterferenceVector* v = vector[i]; v != NULL; v = v->next)
for (Uint32 j = 0; j < v->count; j++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", v->neighbors[j]));
if (v->next != NULL || j != (v->count - 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (","));
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (")\n"));
}
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Matrix:\n"));
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && interfere(name1, name2)) ? '1' : '0'));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _INTERFERENCE_GRAPH_H_

View File

@@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVE_RANGE_H_
#define _LIVE_RANGE_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
template <class RegisterPressure>
struct LiveRange
{
static void build(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
void LiveRange<RegisterPressure>::build(RegisterAllocator& registerAllocator)
{
// Intialize the lookup table.
//
Uint32 nameCount = registerAllocator.nameCount;
RegisterName* nameTable = new(registerAllocator.pool) RegisterName[2*nameCount];
RegisterName* rangeName = &nameTable[nameCount];
init(rangeName, nameCount);
// Walk the graph.
//
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
SparseSet destination(registerAllocator.pool, nameCount);
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
destination.clear();
for (InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
Instruction& phiNode = phiNodes.get(i);
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
destination.set(findRoot(phiNode.getInstructionDefineBegin()[0].getRegisterName(), rangeName));
}
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
RegisterName destinationName = phiNode.getInstructionDefineBegin()[0].getRegisterName();
RegisterName destinationRoot = findRoot(destinationName, rangeName);
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
assert(usePtr->isRegister());
RegisterName sourceName = usePtr->getRegisterName();
RegisterName sourceRoot = findRoot(sourceName, rangeName);
if (sourceRoot != destinationRoot && !destination.test(sourceRoot))
rangeName[sourceRoot] = destinationRoot;
}
}
}
registerAllocator.rangeCount = compress(registerAllocator.name2range, rangeName, nameCount, nameCount);
}
#endif // _LIVE_RANGE_H_

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVE_RANGE_GRAPH_
#define _LIVE_RANGE_GRAPH_
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterTypes.h"
class RegisterAllocator;
template <class RegisterPressure>
class LiveRangeGraph
{
private:
RegisterAllocator& registerAllocator;
RegisterPressure::Set* edges;
Uint32 rangeCount;
public:
//
//
LiveRangeGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
//
//
void build();
//
//
void addEdge(RegisterName name1, RegisterName name2);
//
//
bool haveEdge(RegisterName name1, RegisterName name2);
#ifdef DEBUG_LOG
//
//
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::build()
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
this->rangeCount = rangeCount;
edges = new(pool) RegisterPressure::Set(pool, rangeCount * rangeCount);
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
LivenessInfo<RegisterPressure>& liveness = registerAllocator.liveness;
SparseSet currentLive(pool, rangeCount);
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
currentLive = liveness.liveOut[n];
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
if ((instruction.getFlags() & ifCopy) != 0) {
assert(useBegin != useEnd && useBegin[0].isRegister());
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName define = name2range[definePtr->getRegisterName()];
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
RegisterName live = RegisterName(currentLive.get(l));
if (define != live && registerAllocator.canInterfere(define, live))
addEdge(define, live);
}
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
currentLive.set(name2range[usePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName use = name2range[usePtr->getRegisterName()];
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
RegisterName live = RegisterName(currentLive.get(l));
if (use != live && registerAllocator.canInterfere(use, live))
addEdge(use, live);
}
}
}
}
}
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::addEdge(RegisterName name1, RegisterName name2)
{
assert(name1 != name2);
edges->set(name1 * rangeCount + name2);
}
template <class RegisterPressure>
bool LiveRangeGraph<RegisterPressure>::haveEdge(RegisterName name1, RegisterName name2)
{
assert(name1 != name2);
return edges->test(name1 * rangeCount + name2);
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Live ranges graph:\n"));
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && haveEdge(name1, name2)) ? '1' : '0'));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _LIVE_RANGE_GRAPH_

View File

@@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "Liveness.h"

View File

@@ -0,0 +1,301 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVENESS_H_
#define _LIVENESS_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterTypes.h"
// ----------------------------------------------------------------------------
// LivenessInfo -
template <class RegisterPressure>
struct LivenessInfo
{
RegisterPressure::Set* liveIn;
RegisterPressure::Set* liveOut;
DEBUG_LOG_ONLY(Uint32 size);
#ifdef DEBUG_LOG
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
// ----------------------------------------------------------------------------
// Liveness
//
// The liveness is defined by the following data-flow equations:
//
// LiveIn(n) = LocalLive(n) U (LiveOut(n) - Killed(n)).
// LiveOut(n) = U LiveIn(s) (s a successor of n).
//
// where LocalLive(n) is the set of used registers in the block n, Killed(n)
// is the set of defined registers in the block n, LiveIn(n) is the set of
// live registers at the begining of the block n and LiveOut(n) is the set
// of live registers at the end of the block n.
//
//
// We will compute the liveness analysis in two stages:
//
// 1- Build LocalLive(n) (wich is an approximation of LiveIn(n)) and Killed(n)
// for each block n.
// 2- Perform a backward data-flow analysis to propagate the liveness information
// through the entire control-flow graph.
//
template <class RegisterPressure>
struct Liveness
{
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range);
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 nameCount);
};
template <class RegisterPressure>
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Allocate the temporary sets.
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
// Allocate the globals sets.
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
//
for (Uint32 n = 0; n < (nNodes - 1); n++) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLocalLive = liveIn[n];
RegisterPressure::Set& currentKilled = killed[n];
// Find the instructions contributions to the sets LocalLive and Killed.
//
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
Uint32 index = name2range[usePtr->getRegisterName()];
if (!currentKilled.test(index))
currentLocalLive.set(index);
}
// If a Virtualregister is 'defined' then we add it to the set Killed.
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentKilled.set(name2range[definePtr->getRegisterName()]);
}
}
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
// control-flow graph.
//
RegisterPressure::Set temp(pool, rangeCount);
bool changed;
do {
changed = false;
// For all nodes is this graph except the endNode.
for (Int32 n = (nNodes - 2); n >= 0; n--) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLiveIn = liveIn[n];
RegisterPressure::Set& currentLiveOut = liveOut[n];
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
// temp will be the new LiveOut(n).
Uint32 nSuccessors = node.nSuccessors();
if (nSuccessors != 0) {
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
for (Uint32 s = 1; s < nSuccessors; s++)
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
} else
temp.clear();
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
// new LiveIn(n).
if (currentLiveOut != temp) {
currentLiveOut = temp;
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
temp |= currentLiveIn;
if (currentLiveIn != temp) {
currentLiveIn = temp;
changed = true;
}
}
}
} while(changed);
LivenessInfo<RegisterPressure> liveness;
liveness.liveIn = liveIn;
liveness.liveOut = liveOut;
DEBUG_LOG_ONLY(liveness.size = nNodes);
return liveness;
}
template <class RegisterPressure>
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 nameCount)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Allocate the temporary sets.
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
RegisterPressure::Set* usedByPhiNodes = NULL;
// Allocate the globals sets.
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
//
for (Uint32 n = 0; n < (nNodes - 1); n++) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLocalLive = liveIn[n];
RegisterPressure::Set& currentKilled = killed[n];
InstructionList& phiNodes = node.getPhiNodeInstructions();
if ((usedByPhiNodes == NULL) && !phiNodes.empty())
usedByPhiNodes = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
InstructionDefine& define = phiNode.getInstructionDefineBegin()[0];
currentKilled.set(define.getRegisterName());
typedef DoublyLinkedList<ControlEdge> ControlEdgeList;
const ControlEdgeList& predecessors = node.getPredecessors();
ControlEdgeList::iterator p = predecessors.begin();
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++, p = predecessors.advance(p))
if (usePtr->isRegister())
usedByPhiNodes[predecessors.get(p).getSource().dfsNum].set(usePtr->getRegisterName());
}
// Find the instructions contributions to the sets LocalLive and Killed.
//
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
Uint32 index = usePtr->getRegisterName();
if (!currentKilled.test(index))
currentLocalLive.set(index);
}
// If a Virtualregister is 'defined' then we add it to the set Killed.
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentKilled.set(definePtr->getRegisterName());
}
}
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
// control-flow graph.
//
RegisterPressure::Set temp(pool, nameCount);
bool changed;
do {
changed = false;
// For all nodes is this graph except the endNode.
for (Int32 n = (nNodes - 2); n >= 0; n--) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLiveIn = liveIn[n];
RegisterPressure::Set& currentLiveOut = liveOut[n];
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
// temp will be the new LiveOut(n).
Uint32 nSuccessors = node.nSuccessors();
if (nSuccessors != 0) {
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
for (Uint32 s = 1; s < nSuccessors; s++)
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
} else
temp.clear();
// Insert the phiNodes contribution.
if (usedByPhiNodes != NULL)
temp |= usedByPhiNodes[n];
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
// new LiveIn(n).
if (currentLiveOut != temp) {
currentLiveOut = temp;
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
temp |= currentLiveIn;
if (currentLiveIn != temp) {
currentLiveIn = temp;
changed = true;
}
}
}
} while(changed);
LivenessInfo<RegisterPressure> liveness;
liveness.liveIn = liveIn;
liveness.liveOut = liveOut;
DEBUG_LOG_ONLY(liveness.size = nNodes);
return liveness;
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void LivenessInfo<RegisterPressure>::printPretty(LogModuleObject log)
{
for (Uint32 n = 0; n < size; n++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Node N%d:\n\tliveIn = ", n));
liveIn[n].printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tliveOut = "));
liveOut[n].printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _LIVENESS_H_

View File

@@ -0,0 +1,40 @@
#! gmake
DEPTH = ../..
MODULE_NAME = RegisterAllocator
include $(DEPTH)/config/config.mk
INCLUDES += \
-I$(DEPTH)/Utilities/General \
-I$(DEPTH)/Utilities/zlib \
-I$(DEPTH)/Runtime/ClassReader \
-I$(DEPTH)/Runtime/NativeMethods \
-I$(DEPTH)/Runtime/System \
-I$(DEPTH)/Runtime/ClassInfo \
-I$(DEPTH)/Runtime/FileReader \
-I$(DEPTH)/Compiler/PrimitiveGraph \
-I$(DEPTH)/Compiler/FrontEnd \
-I$(DEPTH)/Compiler/Optimizer \
-I$(DEPTH)/Compiler/CodeGenerator \
-I$(DEPTH)/Compiler/CodeGenerator/md \
-I$(DEPTH)/Compiler/CodeGenerator/md/$(CPU_ARCH) \
-I$(DEPTH)/Compiler/RegisterAllocator \
-I$(DEPTH)/Driver/StandAloneJava \
-I$(DEPTH)/Debugger \
$(NULL)
CXXSRCS = \
RegisterAllocator.cpp \
RegisterAllocatorTools.cpp \
DominatorGraph.cpp \
VirtualRegister.cpp \
BitSet.cpp \
SparseSet.cpp \
$(NULL)
include $(DEPTH)/config/rules.mk
libs:: $(MODULE)

View File

@@ -0,0 +1,392 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _PHI_NODE_REMOVER_H_
#define _PHI_NODE_REMOVER_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "DominatorGraph.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h"
#include "Liveness.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "SparseSet.h"
#include <string.h>
//------------------------------------------------------------------------------
// RegisterNameNode -
struct RegisterNameNode
{
RegisterNameNode* next;
RegisterName newName;
Uint32 nextPushed;
};
//------------------------------------------------------------------------------
// CopyData -
struct CopyData
{
RegisterName source;
RegisterClassKind classKind;
Uint32 useCount;
bool isLiveOut;
RegisterName sourceNameToUse;
RegisterName temporaryName;
RegisterNameNode* newName;
};
//------------------------------------------------------------------------------
// PhiNodeRemover<RegisterPressure> -
template <class RegisterPressure>
struct PhiNodeRemover
{
// Replace the phi nodes by copy instructions.
static void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
};
// Split some of the critical edges and return true if there are still some
// in the graph after that.
//
static bool splitCriticalEdges(ControlGraph& /*cg*/)
{
// FIX: not implemented.
return true;
}
inline void pushName(Pool& pool, RegisterNameNode** stack, SparseSet& pushed, Uint32* nodeListPointer, RegisterName oldName, RegisterName newName)
{
RegisterNameNode& newNode = *new(pool) RegisterNameNode();
if (pushed.test(oldName))
(*stack)->newName = newName;
else {
newNode.newName = newName;
newNode.nextPushed = *nodeListPointer;
*nodeListPointer = oldName;
newNode.next = *stack;
*stack = &newNode;
pushed.set(oldName);
}
}
template <class RegisterPressure>
void PhiNodeRemover<RegisterPressure>::replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Initialize the local variables.
//
// When we insert the copies we will also need to create new VirtualRegisters for
// the insertion of temporaries. The maximum number of temporary register will not
// exceed the number of phiNodes in the primitive graph.
Uint32 nameCount = vrManager.getSize();
Uint32 maxNameCount = nameCount;
for (Uint32 n = 0; n < nNodes; n++)
maxNameCount += nodes[n]->getPhiNodes().length();
// If the CFG contains some critical edges (backward edge which source has more than one
// outgoing edge and destination has more than one incomimg edge) then we need the liveness
// information to be able to insert temporary copies.
RegisterPressure::Set* liveOut = NULL;
if (splitCriticalEdges(controlGraph))
liveOut = Liveness<LowRegisterPressure>::analysis(controlGraph, nameCount).liveOut;
DominatorGraph dGraph(controlGraph);
SparseSet pushed(pool, maxNameCount);
SparseSet destinationList(pool, maxNameCount);
SparseSet workList(pool, maxNameCount);
CopyData* copyStats = new(pool) CopyData[maxNameCount];
memset(copyStats, '\0', maxNameCount*sizeof(CopyData));
struct NodeStack {
Uint32* next;
Uint32* limit;
Uint32 pushedList;
};
// Allocate the node stack and initialize the node stack pointer.
NodeStack* nodeStack = new(pool) NodeStack[nNodes + 1];
NodeStack* nodeStackPtr = nodeStack;
// We start by the begin node.
Uint32 startNode = 0;
Uint32* next = &startNode;
Uint32* limit = &startNode + 1;
while (true) {
if (next == limit) {
// If there are no more node in the sibling, we have to pop the current
// frame from the stack and update the copyStats of the pushed nodes.
//
if (nodeStackPtr == nodeStack)
// We are at the bottom of the stack and there are no more nodes
// to look at. We are done !
break;
--nodeStackPtr;
// We are done with all the children of this node in the dominator tree.
// We need to update the copy information of all the new names pushed
// during the walk over this node.
Uint32 pushedList = nodeStackPtr->pushedList;
while (pushedList != 0) {
Uint32 nextName = copyStats[pushedList].newName->nextPushed;
copyStats[pushedList].newName = copyStats[pushedList].newName->next;
pushedList = nextName;
}
// restore the previous frame.
next = nodeStackPtr->next;
limit = nodeStackPtr->limit;
} else {
Uint32 currentNode = *next++;
Uint32 pushedList = 0;
// Initialize the sets.
pushed.clear();
destinationList.clear();
// STEP1:
// Walk the instruction list and to replace all the instruction uses with their new name.
// If the instruction is a phi node and its defined register is alive at the end of this
// block then we push the defined register into the stack.
//
ControlNode& node = *nodes[currentNode];
RegisterPressure::Set* currentLiveOut = (liveOut != NULL) ? &liveOut[currentNode] : (RegisterPressure::Set*) 0;
InstructionList& phiNodes = node.getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
assert(usePtr->isRegister());
RegisterName name = usePtr->getRegisterName();
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
usePtr->setRegisterName(copyStats[name].newName->newName);
}
if (currentLiveOut != NULL) {
// This is a phi node and we have to push its defined name if it is live
// at the end of the node. We only need to do this if the CFG has critical edges.
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
RegisterName name = phiNode.getInstructionDefineBegin()[0].getRegisterName();
if (currentLiveOut->test(name))
pushName(pool, &(copyStats[name].newName), pushed, &pushedList, name, name);
}
}
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
usePtr->setRegisterName(copyStats[name].newName->newName);
}
}
// STEP2:
// Look at this node's successors' phiNodes. We keep track of the number of time
// a VR will be used by another copy instruction and insert each definition into the
// destinationList. This is the only pass over this node's successors as we will
// get all the information we need in the CopyData structures.
//
ControlEdge* successorEdgeEnd = node.getSuccessorsEnd();
for (ControlEdge* successorEdgePtr = node.getSuccessorsBegin(); successorEdgePtr < successorEdgeEnd; successorEdgePtr++) {
Uint32 useIndex = successorEdgePtr->getIndex();
ControlNode& successor = successorEdgePtr->getTarget();
// Look at its phi nodes. The phi nodes are at the top of the instruction list. We exit
// as soon as we find an instruction which is not a phi node
InstructionList& phiNodes = successor.getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
assert((phiNode.getInstructionUseBegin() + useIndex) < phiNode.getInstructionUseEnd());
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd());
InstructionUse& source = phiNode.getInstructionUseBegin()[useIndex];
InstructionDefine& destination = phiNode.getInstructionDefineBegin()[0];
assert(source.isRegister() && destination.isRegister());
RegisterName sourceName = source.getRegisterName();
RegisterName destinationName = destination.getRegisterName();
// Get the correct name for the source.
if (copyStats[sourceName].newName != NULL)
sourceName = copyStats[sourceName].newName->newName;
// Update the CopyData structures.
if ((sourceName != rnInvalid) && (sourceName != destinationName)) {
copyStats[destinationName].source = sourceName;
copyStats[destinationName].classKind = destination.getRegisterClass();
copyStats[destinationName].isLiveOut = (currentLiveOut != NULL) ? currentLiveOut->test(destinationName) : false;
copyStats[destinationName].sourceNameToUse = destinationName;
copyStats[sourceName].sourceNameToUse = sourceName;
copyStats[sourceName].useCount++;
destinationList.set(destinationName);
}
}
}
// STEP3:
// Insert into the worklist only the destination registers that will be not used in
// another copy instruction in this block.
//
assert(workList.getSize() == 0);
for (SparseSet::iterator d = destinationList.begin(); !destinationList.done(d); d = destinationList.advance(d)) {
Uint32 dest = destinationList.get(d);
if (copyStats[dest].useCount == 0)
workList.set(dest);
}
// STEP4:
// Insert the copy instructions.
//
Uint32 destinationListSize = destinationList.getSize();
InstructionList::iterator endOfTheNode = instructions.end();
// Find the right place to insert the copy instructions.
if (destinationListSize != 0)
while (instructions.get(endOfTheNode).getFlags() & ifControl)
endOfTheNode = instructions.retreat(endOfTheNode);
while (destinationListSize != 0) {
while(workList.getSize()) {
RegisterName destinationName = RegisterName(workList.getOne());
RegisterName sourceName = copyStats[destinationName].source;
workList.clear(destinationName);
if (copyStats[destinationName].isLiveOut && !copyStats[destinationName].temporaryName) {
// Lost copy problem.
copyStats[destinationName].isLiveOut = false;
RegisterName sourceName = destinationName;
RegisterClassKind classKind = copyStats[sourceName].classKind;
RegisterName destinationName = getName(vrManager.newVirtualRegister(classKind));
assert(destinationName < maxNameCount);
copyStats[destinationName].classKind = classKind;
copyStats[sourceName].useCount = 0;
// We need to insert a copy to a temporary register to keep the
// source register valid at the end of the node defining it.
// This copy will be inserted right after the phi node defining it.
RegisterName from = copyStats[sourceName].sourceNameToUse;
Instruction* definingPhiNode = vrManager.getVirtualRegister(from).getDefiningInstruction();
assert(definingPhiNode && (definingPhiNode->getFlags() & ifPhiNode) != 0);
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*definingPhiNode->getPrimitive(), fromID, toID);
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
definingPhiNode->getPrimitive()->getContainer()->getInstructions().addFirst(copy);
copyStats[sourceName].temporaryName = destinationName;
copyStats[sourceName].sourceNameToUse = destinationName;
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
}
// Insert the copy instruction at the end of the current node.
RegisterName from = copyStats[sourceName].sourceNameToUse;
RegisterClassKind classKind = copyStats[destinationName].classKind;
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
instructions.insertAfter(copy, endOfTheNode);
endOfTheNode = instructions.advance(endOfTheNode);
copyStats[sourceName].useCount = 0;
if (destinationList.test(sourceName) && copyStats[sourceName].isLiveOut)
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
copyStats[sourceName].isLiveOut = false;
copyStats[sourceName].sourceNameToUse = destinationName;
if (destinationList.test(sourceName))
workList.set(sourceName);
destinationList.clear(destinationName);
}
destinationListSize = destinationList.getSize();
if (destinationListSize != 0) {
RegisterName sourceName = RegisterName(destinationList.getOne());
RegisterName destinationName;
if (!copyStats[sourceName].temporaryName) {
// Cycle problem.
RegisterClassKind classKind = copyStats[sourceName].classKind;
destinationName = getName(vrManager.newVirtualRegister(classKind));
assert(destinationName < maxNameCount);
copyStats[destinationName].classKind = classKind;
copyStats[sourceName].temporaryName = destinationName;
// Insert the copy instruction at the end of the current node.
RegisterName from = copyStats[sourceName].sourceNameToUse;
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
instructions.insertAfter(copy, endOfTheNode);
endOfTheNode = instructions.advance(endOfTheNode);
} else
destinationName = copyStats[sourceName].temporaryName;
copyStats[sourceName].useCount = 0;
copyStats[sourceName].isLiveOut = false;
copyStats[sourceName].sourceNameToUse = destinationName;
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
workList.set(sourceName);
}
}
nodeStackPtr->pushedList = pushedList;
nodeStackPtr->next = next;
nodeStackPtr->limit = limit;
++nodeStackPtr;
next = dGraph.getSuccessorsBegin(currentNode);
limit = dGraph.getSuccessorsEnd(currentNode);
}
}
}
#endif // _PHI_NODE_REMOVER_H_

View File

@@ -0,0 +1,155 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "LogModule.h"
#include "RegisterAllocator.h"
#include "RegisterPressure.h"
#include "RegisterAllocatorTools.h"
#include "PhiNodeRemover.h"
#include "LiveRange.h"
#include "Liveness.h"
#include "InterferenceGraph.h"
#include "LiveRangeGraph.h"
#include "Coalescing.h"
#include "Spilling.h"
#include "Coloring.h"
#include "Splits.h"
class Pool;
class ControlGraph;
class VirtualRegisterManager;
class InstructionEmitter;
UT_DEFINE_LOG_MODULE(RegAlloc);
void RegisterAllocator::allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
{
// Insert the phi node instructions. We want to do this to have a single defined register per instruction.
// If we keep the PhiNode (as a DataNode) and a PhiNode is of DoubleWordKind then we have to execute
// some special code for the high word annotation.
//
RegisterAllocatorTools::insertPhiNodeInstructions(controlGraph, emitter);
// Perform some tests on the instruction graph.
//
DEBUG_ONLY(RegisterAllocatorTools::testTheInstructionGraph(controlGraph, vrManager));
// Replace the phi node instructions by their equivalent copy instructions.
//
PhiNodeRemover<LowRegisterPressure>::replacePhiNodes(controlGraph, vrManager, emitter);
// Do the register allocation.
//
RegisterAllocator registerAllocator(pool, controlGraph, vrManager, emitter);
registerAllocator.doGraphColoring();
}
void RegisterAllocator::doGraphColoring()
{
// Initialize the liverange map.
//
initLiveRanges();
// Build the live ranges. We do this to compress the number of RegisterNames
// used in the insterference graph.
//
LiveRange<LowRegisterPressure>::build(*this);
// Remove unnecessary copies.
//
RegisterAllocatorTools::removeUnnecessaryCopies(*this);
for (Uint8 loop = 0; loop < 10; loop++) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********* RegisterAllocator loop %d *********\n", loop));
while(true) {
// Build the interference graph.
//
iGraph.build();
// Coalesce the copy instructions.
//
if (!Coalescing<LowRegisterPressure>::coalesce(*this))
break;
}
// Print the interference graph.
//
DEBUG_LOG_ONLY(iGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
// Calculate the spill costs.
//
Spilling<LowRegisterPressure>::calculateSpillCosts(*this);
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSpillCosts(*this));
// Calculate the split costs.
//
Splits<LowRegisterPressure>::calculateSplitCosts(*this);
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSplitCosts(*this));
// Build the live range graph.
//
lGraph.build();
DEBUG_LOG_ONLY(lGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
// Color the graph. If it succeeds then we're done with the
// register allocation.
//
if (Coloring<LowRegisterPressure>::color(*this)) {
// Write the final colors in the instruction graph.
//
Coloring<LowRegisterPressure>::finalColoring(*this);
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********** RegisterAllocator done **********\n"));
DEBUG_LOG_ONLY(RegisterAllocatorTools::printInstructions(*this));
return;
}
// We need to spill some registers.
//
Spilling<LowRegisterPressure>::insertSpillCode(*this);
// Insert the split instructions.
//
Splits<LowRegisterPressure>::insertSplitCode(*this);
// Update the live ranges.
//
// FIX
}
#ifdef DEBUG_LOG
RegisterAllocatorTools::updateInstructionGraph(*this);
RegisterAllocatorTools::printInstructions(*this);
#endif
fprintf(stderr, "!!! Coloring failed after 10 loops !!!\n");
abort();
}
void RegisterAllocator::initLiveRanges()
{
Uint32 count = this->nameCount;
RegisterName* name2range = new(pool) RegisterName[nameCount];
for (RegisterName r = RegisterName(1); r < count; r = RegisterName(r + 1))
name2range[r] = r;
this->name2range = name2range;
rangeCount = count;
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_ALLOCATOR_H_
#define _REGISTER_ALLOCATOR_H_
class Pool;
class ControlGraph;
class InstructionEmitter;
struct SpillCost;
struct SplitCost;
#include "Liveness.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h" // This should included by Backend.cpp
#include "InterferenceGraph.h"
#include "LiveRangeGraph.h"
//template <class RegisterPressure>
class RegisterAllocator
{
public:
Pool& pool; //
ControlGraph& controlGraph; //
VirtualRegisterManager& vrManager; //
InstructionEmitter& emitter; //
RegisterName* name2range; //
RegisterName* color; //
SpillCost* spillCost; //
SparseSet* willSpill; //
SplitCost* splitCost; //
NameLinkedList** splitAround; //
InterferenceGraph<LowRegisterPressure> iGraph; //
LiveRangeGraph<LowRegisterPressure> lGraph; //
LivenessInfo<LowRegisterPressure> liveness; //
Uint32 nameCount; //
Uint32 rangeCount; //
bool splitFound; //
private:
//
//
void doGraphColoring();
public:
//
//
inline RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
//
//
bool canInterfere(RegisterName /*name1*/, RegisterName /*name2*/) const {return true;}
//
//
void initLiveRanges();
//
//
static void allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
};
//
//
inline RegisterAllocator::RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
: pool(pool), controlGraph(controlGraph), vrManager(vrManager), emitter(emitter), iGraph(*this), lGraph(*this), nameCount(vrManager.getSize()) {}
#endif // _REGISTER_ALLOCATOR_H_

View File

@@ -0,0 +1,355 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "LogModule.h"
#include "RegisterAllocatorTools.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "InstructionEmitter.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "Spilling.h"
#include "Splits.h"
#include "BitSet.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
#ifdef DEBUG
void RegisterAllocatorTools::testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
{
// Test the declared VirtualRegisters. The register allocator tries to condense the register universe.
// Any gap in the VirtualRegister names will be a loss of efficiency !!!!
Uint32 nameCount = vrManager.getSize();
BitSet registerSeen(controlGraph.pool, nameCount);
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
registerSeen.set(usePtr->getRegisterName());
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
registerSeen.set(definePtr->getRegisterName());
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
registerSeen.set(usePtr->getRegisterName());
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
registerSeen.set(definePtr->getRegisterName());
}
}
bool renameRegisters = false;
for (BitSet::iterator i = registerSeen.nextZero(0); !registerSeen.done(i); i = registerSeen.nextZero(i)) {
renameRegisters = true;
fprintf(stderr,
"WARNING: The VirtualRegister vr%d has been allocated during CodeGeneration but\n"
" is never used nor defined by any instruction in the instruction graph\n"
" PLEASE FIX \n",
i);
}
if (renameRegisters) {
Instruction** definingInstruction = new Instruction*[nameCount];
memset(definingInstruction, '\0', nameCount * sizeof(Instruction*));
RegisterName* newName = new RegisterName[nameCount];
memset(newName, '\0', nameCount * sizeof(RegisterName));
RegisterName nextName = RegisterName(1);
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
usePtr->setRegisterName(newName[name]);
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName name = definePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
definePtr->setRegisterName(newName[name]);
}
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
usePtr->setRegisterName(newName[name]);
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName name = definePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
definePtr->setRegisterName(newName[name]);
}
}
}
vrManager.setSize(nextName);
for (RegisterName r = RegisterName(1); r < nextName; r = RegisterName(r + 1))
vrManager.getVirtualRegister(r).definingInstruction = definingInstruction[r];
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("RegisterMap:\n"));
for (Uint32 i = 1; i < nameCount; i++)
if (newName[i] != 0)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d becomes vr%d.\n", i, newName[i]));
else
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d is dead.\n", i));
delete newName;
delete definingInstruction;
}
}
#endif // DEBUG
void RegisterAllocatorTools::removeUnnecessaryCopies(RegisterAllocator& registerAllocator)
{
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i);) {
Instruction& instruction = instructions.get(i);
i = instructions.advance(i);
if (instruction.getFlags() & ifCopy) {
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
RegisterName source = name2range[instruction.getInstructionUseBegin()[0].getRegisterName()];
RegisterName destination = name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()];
if (source == destination)
instruction.remove();
}
}
}
}
void RegisterAllocatorTools::updateInstructionGraph(RegisterAllocator& registerAllocator)
{
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
}
}
}
void RegisterAllocatorTools::insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
if (!phiNodes.empty()) {
// Set the index of the incoming edges.
Uint32 index = 0;
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p))
predecessors.get(p).setIndex(index++);
// Insert the phi node instruction in the instruction list.
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
PhiNode& phiNode = phiNodes.get(i);
ValueKind kind = phiNode.getKind();
if (!isStorableKind(kind))
continue;
RegisterClassKind classKind = rckGeneral; // FIX: get class kind from phi node kind.
Uint32 nInputs = phiNode.nInputs();
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drLow);
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drLow);
node.addPhiNodeInstruction(phiNodeInstruction);
if (isDoublewordKind(kind)) {
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drHigh);
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drHigh);
node.addPhiNodeInstruction(phiNodeInstruction);
}
}
}
}
}
#ifdef DEBUG_LOG
void RegisterAllocatorTools::printSpillCosts(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
Uint32 rangeCount = registerAllocator.rangeCount;
SpillCost* cost = registerAllocator.spillCost;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Spill costs:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : ", i));
if (cost[i].infinite)
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("infinite\n"));
else
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%f\n", cost[i].cost));
}
}
void RegisterAllocatorTools::printSplitCosts(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
Uint32 rangeCount = registerAllocator.rangeCount;
SplitCost* cost = registerAllocator.splitCost;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Split costs:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : loads = %f stores = %f\n", i, cost[i].loads, cost[i].stores));
}
}
void RegisterAllocatorTools::printInstructions(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
ControlNode** nodes = registerAllocator.controlGraph.dfsList;
Uint32 nNodes = registerAllocator.controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d:\n", n));
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
InstructionList& instructions = nodes[n]->getInstructions();
if (!phiNodes.empty()) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" PhiNodes:\n", n));
for(InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
phiNodes.get(i).printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
if (!instructions.empty())
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" Instructions:\n", n));
}
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
instructions.get(i).printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,117 @@
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
//
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
// NETSCAPE COMMUNICATIONS CORPORATION
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
// Reserved. Use of this Source Code is subject to the terms of the
// applicable license agreement from Netscape Communications Corporation.
// The copyright notice(s) in this Source Code does not indicate actual or
// intended publication of this Source Code.
//
// $Id: RegisterAllocatorTools.h,v 1.1.2.1 1999-03-02 16:12:05 fur%netscape.com Exp $
//
#ifndef _REGISTER_ALLOCATOR_TOOLS_H_
#define _REGISTER_ALLOCATOR_TOOLS_H_
#include "LogModule.h"
#include "RegisterTypes.h"
#include <string.h>
class RegisterAllocator;
class ControlGraph;
class InstructionEmitter;
class VirtualRegisterManager;
struct RegisterAllocatorTools
{
//
//
static void insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter);
//
//
static void updateInstructionGraph(RegisterAllocator& registerAllocator);
//
//
static void removeUnnecessaryCopies(RegisterAllocator& registerAllocator);
#ifdef DEBUG
//
//
static void testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
#endif // DEBUG
#ifdef DEBUG_LOG
//
//
static void printInstructions(RegisterAllocator& registerAllocator);
//
//
static void printSpillCosts(RegisterAllocator& registerAllocator);
//
//
static void printSplitCosts(RegisterAllocator& registerAllocator);
#endif // DEBUG_LOG
};
//
// FIX: this should go in a class (LookupTable ?)
//
inline RegisterName findRoot(RegisterName name, RegisterName* table)
{
RegisterName* stack = table;
RegisterName* stackPtr = stack;
RegisterName newName;
while((newName = table[name]) != name) {
*--stackPtr = name;
name = newName;
}
while (stackPtr != stack)
table[*stackPtr++] = name;
return name;
}
inline void init(RegisterName* table, Uint32 nameCount)
{
for (RegisterName r = RegisterName(0); r < nameCount; r = RegisterName(r + 1))
table[r] = r;
}
inline Uint32 compress(RegisterName* name2range, RegisterName* table, Uint32 nameCount, Uint32 tableSize)
{
RegisterName* liveRange = new RegisterName[tableSize];
memset(liveRange, '\0', tableSize * sizeof(RegisterName));
// Update the lookup table.
for (RegisterName r = RegisterName(1); r < tableSize; r = RegisterName(r + 1))
findRoot(r, table);
// Count the liveranges.
Uint32 liveRangeCount = 1;
for (RegisterName s = RegisterName(1); s < tableSize; s = RegisterName(s + 1))
if (table[s] == s)
liveRange[s] = RegisterName(liveRangeCount++);
for (RegisterName t = RegisterName(1); t < nameCount; t = RegisterName(t + 1))
name2range[t] = liveRange[table[name2range[t]]];
return liveRangeCount;
}
inline double doLog10(Uint32 power)
{
double log = 1.0;
while (power--)
log *= 10.0;
return log;
}
#endif // _REGISTER_ALLOCATOR_TOOLS_H_

View File

@@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_ASSIGNER_H_
#define _REGISTER_ASSIGNER_H_
#include "Fundamentals.h"
#include "VirtualRegister.h"
class FastBitMatrix;
class RegisterAssigner
{
protected:
VirtualRegisterManager& vRegManager;
public:
RegisterAssigner(VirtualRegisterManager& vrMan) : vRegManager(vrMan) {}
virtual bool assignRegisters(FastBitMatrix& interferenceMatrix) = 0;
};
#endif /* _REGISTER_ASSIGNER_H_ */

View File

@@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_CLASS_H_
#define _REGISTER_CLASS_H_
#include "Fundamentals.h"
#include "RegisterTypes.h"
#endif // _REGISTER_CLASS_H_

View File

@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_PRESSURE_H_
#define _REGISTER_PRESSURE_H_
#include "BitSet.h"
#include "HashSet.h"
struct LowRegisterPressure
{
typedef BitSet Set;
static const bool setIsOrdered = true;
};
struct HighRegisterPressure
{
typedef HashSet Set;
static const bool setIsOrdered = false;
};
#endif // _REGISTER_PRESSURE_H_

View File

@@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_TYPES_H_
#define _REGISTER_TYPES_H_
#include "Fundamentals.h"
//------------------------------------------------------------------------------
// RegisterName -
//
enum RegisterName {
rnInvalid = 0,
};
//------------------------------------------------------------------------------
// RegisterClassKind -
//
enum RegisterClassKind {
rckInvalid = 0,
rckGeneral,
rckStackSlot,
nRegisterClassKind
};
//------------------------------------------------------------------------------
// RegisterID -
//
enum RegisterID {
invalidID = 0
};
//------------------------------------------------------------------------------
// RegisterKind -
//
enum RegisterKind {
rkCallerSave = 0,
rkCalleeSave,
};
struct NameLinkedList {
RegisterName name;
NameLinkedList* next;
};
#ifdef DEBUG
const registerNameMask = 0x03ffffff;
const coloredRegisterMask = 0x04000000;
const machineRegisterMask = 0x08000000;
const registerClassMask = 0xf0000000;
const registerNameShift = 0;
const coloredRegisterShift = 26;
const machineRegisterShift = 27;
const registerClassShift = 28;
#else // DEBUG
const registerNameMask = 0x0fffffff;
const registerClassMask = 0xf0000000;
const registerNameShift = 0;
const registerClassShift = 28;
#endif // DEBUG
inline RegisterClassKind getClass(RegisterID registerID) {return RegisterClassKind((registerID & registerClassMask) >> registerClassShift);}
inline RegisterName getName(RegisterID registerID) {return RegisterName((registerID & registerNameMask) >> registerNameShift);}
inline void setClass(RegisterID& registerID, RegisterClassKind classKind) {registerID = RegisterID((registerID & ~registerClassMask) | ((classKind << registerClassShift) & registerClassMask));}
inline void setName(RegisterID& registerID, RegisterName name) {assert((name & ~registerNameMask) == 0); registerID = RegisterID((registerID & ~registerNameMask) | ((name << registerNameShift) & registerNameMask));}
inline RegisterID buildRegisterID(RegisterName name, RegisterClassKind classKind) {return RegisterID(((classKind << registerClassShift) & registerClassMask) | ((name << registerNameShift) & registerNameMask));}
#ifdef DEBUG
inline bool isMachineRegister(RegisterID rid) {return (rid & machineRegisterMask) != 0;}
inline void setMachineRegister(RegisterID& rid) {rid = RegisterID(rid | machineRegisterMask);}
inline bool isColoredRegister(RegisterID rid) {return (rid & coloredRegisterMask) != 0;}
inline void setColoredRegister(RegisterID& rid) {rid = RegisterID(rid | coloredRegisterMask);}
#endif // DEBUG
#endif // _REGISTER_TYPES_H_

View File

@@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SSATools.h"
#include "ControlGraph.h"
#include "VirtualRegister.h"
#include "Liveness.h"
void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
{
if (!controlGraph.hasBackEdges)
return;
Liveness liveness(controlGraph.pool);
liveness.buildLivenessAnalysis(controlGraph, vrManager);
}

View File

@@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SSA_TOOLS_H_
#define _SSA_TOOLS_H_
#include "Fundamentals.h"
class ControlGraph;
class VirtualRegisterManager;
extern void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
#endif // _SSA_TOOLS_H_

View File

@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SparseSet.h"
#include "BitSet.h"
#include "Pool.h"
#ifdef DEBUG_LOG
// Print the set.
//
void SparseSet::printPretty(LogModuleObject log)
{
Pool pool;
BitSet set(pool, universeSize);
for (Uint32 i = 0; i < count; i++)
set.set(node[i].element);
set.printPretty(log);
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,168 @@
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
//
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
// NETSCAPE COMMUNICATIONS CORPORATION
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
// Reserved. Use of this Source Code is subject to the terms of the
// applicable license agreement from Netscape Communications Corporation.
// The copyright notice(s) in this Source Code does not indicate actual or
// intended publication of this Source Code.
//
// $Id: SparseSet.h,v 1.1.2.1 1999-03-02 16:12:07 fur%netscape.com Exp $
//
#ifndef _SPARSE_SET_H_
#define _SPARSE_SET_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "LogModule.h"
#include "BitSet.h"
class SparseSet
{
private:
struct Node {
Uint32 element;
Uint32 stackIndex;
};
Node* node;
Uint32 count;
Uint32 universeSize;
private:
// No copy constructor.
SparseSet(const SparseSet&);
// Check if the given set's universe is of the same size than this universe.
void checkUniverseCompatibility(const SparseSet& set) const {assert(set.universeSize == universeSize);}
// Check if pos is valid for this set's universe.
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
public:
SparseSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {node = new(pool) Node[universeSize]; clear();}
// Clear the sparse set.
void clear() {count = 0;}
// Clear the element at index.
inline void clear(Uint32 index);
// Set the element at index.
inline void set(Uint32 index);
// Return true if the element at index is set.
inline bool test(Uint32 index) const;
// Union with the given sparse set.
inline void or(const SparseSet& set);
// Intersection with the given sparse set.
inline void and(const SparseSet& set);
// Difference with the given sparse set.
inline void difference(const SparseSet& set);
// Copy set.
inline SparseSet& operator = (const SparseSet& set);
inline SparseSet& operator = (const BitSet& set);
// Return true if the sparse sets are identical.
friend bool operator == (const SparseSet& set1, const SparseSet& set2);
// Return true if the sparse sets are different.
friend bool operator != (const SparseSet& set1, const SparseSet& set2);
// Logical operators.
SparseSet& operator |= (const SparseSet& set) {or(set); return *this;}
SparseSet& operator &= (const SparseSet& set) {and(set); return *this;}
SparseSet& operator -= (const SparseSet& set) {difference(set); return *this;}
// Iterator to conform with the set API.
typedef Int32 iterator;
// Return the iterator for the first element of this set.
iterator begin() const {return count - 1;}
// Return the next iterator.
iterator advance(iterator pos) const {return --pos;}
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos < 0;}
// Return the element for the given iterator;
Uint32 get(iterator pos) const {return node[pos].element;}
// Return one element of this set.
Uint32 getOne() const {assert(count > 0); return node[0].element;}
// Return the size of this set.
Uint32 getSize() const {return count;}
#ifdef DEBUG_LOG
// Print the set.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
inline void SparseSet::clear(Uint32 element)
{
checkMember(element);
Uint32 count = this->count;
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
if ((stackIndex < count) && (node[stackIndex].element == element)) {
Uint32 stackTop = node[count - 1].element;
node[stackIndex].element = stackTop;
node[stackTop].stackIndex = stackIndex;
this->count = count - 1;
}
}
inline void SparseSet::set(Uint32 element)
{
checkMember(element);
Uint32 count = this->count;
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
if ((stackIndex >= count) || (node[stackIndex].element != element)) {
node[count].element = element;
node[element].stackIndex = count;
this->count = count + 1;
}
}
inline bool SparseSet::test(Uint32 element) const
{
checkMember(element);
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
return ((stackIndex < count) && (node[stackIndex].element == element));
}
inline SparseSet& SparseSet::operator = (const SparseSet& set)
{
checkUniverseCompatibility(set);
Uint32 sourceCount = set.getSize();
Node* node = this->node;
memcpy(node, set.node, sourceCount * sizeof(Node));
for (Uint32 i = 0; i < sourceCount; i++) {
Uint32 element = node[i].element;
node[element].stackIndex = i;
}
count = sourceCount;
return *this;
}
inline SparseSet& SparseSet::operator = (const BitSet& set)
{
// FIX: there's room for optimization here.
assert(universeSize == set.getSize());
clear();
for (Int32 i = set.firstOne(); i != -1; i = set.nextOne(i))
this->set(i);
return *this;
}
#endif // _SPARSE_SET_H_

View File

@@ -0,0 +1,270 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef NEW_LAURENTM_CODE
#define INCLUDE_EMITTER
#include "CpuInfo.h"
#include "Fundamentals.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "Spilling.h"
void Spilling::
insertSpillCode(ControlNode** dfsList, Uint32 nNodes)
{
PRUint32 nVirtualRegisters = vRegManager.count();
FastBitSet currentLive(vRegManager.pool, nVirtualRegisters);
FastBitSet usedInThisInstruction(vRegManager.pool, nVirtualRegisters);
RegisterFifo grNeedLoad(nVirtualRegisters);
RegisterFifo fpNeedLoad(nVirtualRegisters);
for (PRInt32 n = nNodes - 1; n >= 0; n--)
{
PR_ASSERT(grNeedLoad.empty() & fpNeedLoad.empty());
ControlNode& node = *dfsList[n];
currentLive = node.liveAtEnd;
PRUint32 nGeneralAlive = 0;
PRUint32 nFloatingPointAlive = 0;
// Get the number of registers alive at the end of this node.
for (PRInt32 j = currentLive.firstOne(); j != -1; j = currentLive.nextOne(j))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(j);
if (vReg.spillInfo.willSpill)
{
currentLive.clear(j);
}
else
{
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive++;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive++;
break;
default:
break;
}
}
}
// if(node.dfsNum == 8) printf("\n________Begin Node %d________\n", node.dfsNum);
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i))
{
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
InstructionDefine* defPtr;
// if(node.dfsNum == 8) { printf("\n");
// instruction.printPretty(stdout);
// printf("\n"); }
// Handle definitions
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
if (defPtr->isVirtualRegister())
{
VirtualRegister& vReg = defPtr->getVirtualRegister();
currentLive.clear(vReg.getRegisterIndex());
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive--;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive--;
break;
default:
break;
}
}
// Check for deaths
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isVirtualRegister())
{
VirtualRegister& vReg = usePtr->getVirtualRegister();
if (!currentLive.test(vReg.getRegisterIndex()))
// This is the last use of this register.
{
currentLive.set(vReg.getRegisterIndex());
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive++;
while (/*(nGeneralAlive > NUMBER_OF_GREGISTERS) &&*/ !grNeedLoad.empty())
{
PRUint32 toLoad = grNeedLoad.get();
currentLive.clear(toLoad);
nGeneralAlive--;
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
nReg.releaseSelf();
}
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive++;
while (/*(nFloatingPointAlive > NUMBER_OF_FPREGISTERS) &&*/ !fpNeedLoad.empty())
{
PRUint32 toLoad = fpNeedLoad.get();
currentLive.clear(toLoad);
nFloatingPointAlive--;
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
nReg.releaseSelf();
}
break;
default:
break;
}
}
}
// Handle uses
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isVirtualRegister())
{
VirtualRegister& vReg = usePtr->getVirtualRegister();
PRUint32 registerIndex = vReg.getRegisterIndex();
if (vReg.spillInfo.willSpill) {
#if defined(GENERATE_FOR_X86)
if (!instruction.switchUseToSpill((usePtr - useBegin), *vReg.equivalentRegister[vrcStackSlot]))
#endif
{
switch (vReg.getClass())
{
case vrcInteger:
if (!grNeedLoad.test(registerIndex))
{
grNeedLoad.put(registerIndex);
VirtualRegister& alias = vRegManager.newVirtualRegister(vrcInteger);
if (vReg.isPreColored())
alias.preColorRegister(vReg.getPreColor());
/* if (vReg.hasSpecialInterference) {
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
alias.specialInterference = vReg.specialInterference;
alias.hasSpecialInterference = true;
} */
vReg.setAlias(alias);
vReg.retainSelf();
}
break;
case vrcFloatingPoint:
case vrcFixedPoint:
if (!fpNeedLoad.test(registerIndex))
{
fpNeedLoad.put(registerIndex);
VirtualRegister& alias = vRegManager.newVirtualRegister(vReg.getClass());
if (vReg.isPreColored())
alias.preColorRegister(vReg.getPreColor());
/*if (vReg.hasSpecialInterference) {
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
alias.specialInterference = vReg.specialInterference;
alias.hasSpecialInterference = true;
} */
vReg.setAlias(alias);
vReg.retainSelf();
}
break;
default:
break;
}
usePtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
usedInThisInstruction.set(registerIndex);
vReg.spillInfo.lastUsingInstruction = &instruction;
}
currentLive.clear(registerIndex);
} else { // will not spill
currentLive.set(registerIndex);
}
}
// Handle definitions
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
if (defPtr->isVirtualRegister())
{
VirtualRegister& vReg = defPtr->getVirtualRegister();
if (vReg.spillInfo.willSpill)
#if defined(GENERATE_FOR_X86)
if (!instruction.switchDefineToSpill((defPtr - defBegin), *vReg.equivalentRegister[vrcStackSlot]))
#endif
{
if (usedInThisInstruction.test(vReg.getRegisterIndex()))
// this virtualRegister was used in this instruction and is also defined. We need to move
// this virtual register to its alias first and then save it to memory.
{
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
vReg.getAlias(), *vReg.equivalentRegister[vrcStackSlot]);
defPtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
}
else
{
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
vReg, *vReg.equivalentRegister[vrcStackSlot]);
}
}
}
}
while (!grNeedLoad.empty())
{
PRUint32 nl = grNeedLoad.get();
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
nlReg.releaseSelf();
}
while (!fpNeedLoad.empty())
{
PRUint32 nl = fpNeedLoad.get();
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
nlReg.releaseSelf();
}
// if(node.dfsNum == 8) printf("\n________End Node %d________\n", node.dfsNum);
}
}
#endif

View File

@@ -0,0 +1,269 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPILLING_H_
#define _SPILLING_H_
#include "Fundamentals.h"
#include <string.h>
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "SparseSet.h"
template <class RegisterPressure>
class Spilling
{
private:
static void insertStoreAfter(Instruction& instruction, RegisterName name);
static void insertLoadBefore(Instruction& instruction, RegisterName name);
public:
static void calculateSpillCosts(RegisterAllocator& registerAllocator);
static void insertSpillCode(RegisterAllocator& registerAllocator);
};
struct SpillCost
{
double loads;
double stores;
double copies;
double cost;
bool infinite;
};
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertSpillCode(RegisterAllocator& registerAllocator)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
Pool& pool = registerAllocator.pool;
SparseSet currentLive(pool, rangeCount);
SparseSet needLoad(pool, rangeCount);
SparseSet mustSpill(pool, rangeCount);
SparseSet& willSpill = *registerAllocator.willSpill;
ControlGraph& controlGraph = registerAllocator.controlGraph;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
needLoad.clear();
currentLive = liveOut[n];
mustSpill = currentLive;
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i);) {
Instruction& instruction = instructions.get(i);
i = instructions.retreat(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
bool foundLiveDefine = false;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
if (currentLive.test(name2range[definePtr->getRegisterName()])) {
foundLiveDefine = true;
break;
}
} else {
foundLiveDefine = true;
break;
}
if (defineBegin != defineEnd && !foundLiveDefine) {
fprintf(stderr, "!!! Removed instruction because it was only defining unused registers !!!\n");
instruction.remove();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName range = name2range[definePtr->getRegisterName()];
#ifdef DEBUG
if (needLoad.test(range))
if (!mustSpill.test(range) && registerAllocator.spillCost[range].infinite && willSpill.test(range)) {
fprintf(stderr, "Tried to spill a register with infinite spill cost\n");
abort();
}
#endif // DEBUG
if (willSpill.test(range))
insertStoreAfter(instruction, range);
needLoad.clear(range);
}
if (instruction.getFlags() & ifCopy)
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
if (!currentLive.test(range))
for (SparseSet::iterator r = needLoad.begin(); !needLoad.done(r); r = needLoad.advance(r)) {
RegisterName load = RegisterName(needLoad.get(r));
if (willSpill.test(load))
insertLoadBefore(instruction, load);
mustSpill.set(load);
}
needLoad.clear();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
currentLive.set(range);
needLoad.set(range);
}
}
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
RegisterName load = RegisterName(needLoad.get(l));
if (willSpill.test(load))
insertLoadBefore(instructions.first(), load);
}
}
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertLoadBefore(Instruction& /*instruction*/, RegisterName name)
{
fprintf(stdout, "will insert load for range %d\n", name);
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertStoreAfter(Instruction& /*instruction*/, RegisterName name)
{
fprintf(stdout, "will insert store for range %d\n", name);
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::calculateSpillCosts(RegisterAllocator& registerAllocator)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
Pool& pool = registerAllocator.pool;
SparseSet live(pool, rangeCount);
SparseSet needLoad(pool, rangeCount);
SparseSet mustSpill(pool, rangeCount);
SparseSet alreadyStored(pool, rangeCount); // FIX: should get this from previous spilling.
SpillCost* cost = new SpillCost[rangeCount];
memset(cost, '\0', rangeCount * sizeof(SpillCost));
ControlGraph& controlGraph = registerAllocator.controlGraph;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
double weight = doLog10(node.loopDepth);
needLoad.clear();
live = liveOut[n];
mustSpill = live;
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName range = name2range[definePtr->getRegisterName()];
if (needLoad.test(range))
if (!mustSpill.test(range))
cost[range].infinite = true;
if ((false /* !rematerializable(range) */ || !needLoad.test(range)) && !alreadyStored.test(range))
cost[range].stores += weight;
needLoad.clear(range);
}
if (instruction.getFlags() & ifCopy)
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
if (!live.test(name2range[usePtr->getRegisterName()])) {
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
Uint32 range = needLoad.get(l);
cost[range].loads += weight;
mustSpill.set(range);
}
needLoad.clear();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
live.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
live.set(range);
needLoad.set(range);
}
if (instruction.getFlags() & ifCopy) {
assert(useBegin != useEnd && useBegin[0].isRegister());
assert(defineBegin != defineEnd && defineBegin[0].isRegister());
RegisterName source = name2range[useBegin[0].getRegisterName()];
RegisterName destination = name2range[defineBegin[0].getRegisterName()];
cost[source].copies += weight;
cost[destination].copies += weight;
}
}
for (SparseSet::iterator s = needLoad.begin(); !needLoad.done(s); s = needLoad.advance(s))
cost[needLoad.get(s)].loads += weight;
}
for (Uint32 r = 0; r < rangeCount; r++) {
SpillCost& c = cost[r];
c.cost = 2 * (c.loads + c.stores) - c.copies;
}
registerAllocator.spillCost = cost;
}
#endif // _SPILLING_H_

View File

@@ -0,0 +1,239 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPLITS_H_
#define _SPLITS_H_
#include "Fundamentals.h"
#include <string.h>
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
template <class RegisterPressure>
struct Splits
{
static void calculateSplitCosts(RegisterAllocator& registerAllocator);
static bool findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range);
static void insertSplitCode(RegisterAllocator& registerAllocator);
};
struct SplitCost
{
double loads;
double stores;
};
template <class RegisterPressure>
void Splits<RegisterPressure>::insertSplitCode(RegisterAllocator& /*registerAllocator*/)
{
// FIX
}
template <class RegisterPressure>
bool Splits<RegisterPressure>::findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range)
{
Pool& pool = registerAllocator.pool;
NameLinkedList** neighborsWithColor = new(pool) NameLinkedList*[6]; // FIX
memset(neighborsWithColor, '\0', 6 * sizeof(NameLinkedList*));
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = vector->count - 1; i >=0; --i) {
RegisterName neighbor = vector->neighbors[i];
RegisterName c = color[neighbor];
if (c < 6) { // FIX
NameLinkedList* node = new(pool) NameLinkedList();
node->name = neighbor;
node->next = neighborsWithColor[c];
neighborsWithColor[c] = node;
}
}
bool splitAroundName = true;
LiveRangeGraph<RegisterPressure>& lGraph = registerAllocator.lGraph;
RegisterName bestColor = RegisterName(6); // FIX
double bestCost = registerAllocator.spillCost[range].cost;
SplitCost* splitCost = registerAllocator.splitCost;
for (RegisterName i = RegisterName(0); i < 6; i = RegisterName(i + 1)) { // FIX
double splitAroundNameCost = 0.0;
bool canSplitAroundName = true;
SplitCost& sCost = splitCost[range];
double addedCost = 2.0 * (sCost.stores + sCost.loads);
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
RegisterName neighbor = node->name;
if (lGraph.haveEdge(neighbor, range)) {
canSplitAroundName = false;
break;
} else
splitAroundNameCost += addedCost;
}
if (canSplitAroundName && splitAroundNameCost < bestCost) {
bestCost = splitAroundNameCost;
bestColor = i;
splitAroundName = true;
}
double splitAroundColorCost = 0.0;
bool canSplitAroundColor = true;
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
RegisterName neighbor = node->name;
if (lGraph.haveEdge(range, neighbor)) {
canSplitAroundColor = false;
break;
} else {
SplitCost& sCost = splitCost[neighbor];
double addedCost = 2.0 * (sCost.stores + sCost.loads);
splitAroundColorCost += addedCost;
}
}
if (canSplitAroundColor && splitAroundColorCost < bestCost) {
bestCost = splitAroundColorCost;
bestColor = i;
splitAroundName = false;
}
}
if (bestColor < RegisterName(6)) {
color[range] = bestColor;
registerAllocator.splitFound = true;
NameLinkedList** splitAround = registerAllocator.splitAround;
if (splitAroundName)
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
NameLinkedList* newNode = new(pool) NameLinkedList();
newNode->name = node->name;
newNode->next = splitAround[range];
splitAround[range] = newNode;
}
else
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
NameLinkedList* newNode = new(pool) NameLinkedList();
RegisterName neighbor = node->name;
newNode->name = range;
newNode->next = splitAround[neighbor];
splitAround[neighbor] = newNode;
}
trespass("Found a split");
return true;
}
return false;
}
template <class RegisterPressure>
void Splits<RegisterPressure>::calculateSplitCosts(RegisterAllocator& registerAllocator)
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
SplitCost* splitCost = new(pool) SplitCost[rangeCount];
memset(splitCost, '\0', rangeCount * sizeof(SplitCost));
SparseSet live(pool, rangeCount);
RegisterPressure::Set* liveIn = registerAllocator.liveness.liveIn;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
double weight = doLog10(node.loopDepth);
live = liveOut[n];
ControlEdge* successorsEnd = node.getSuccessorsEnd();
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++) {
ControlNode& successor = successorsPtr->getTarget();
if (successor.getControlKind() != ckEnd) {
RegisterPressure::Set& successorLiveIn = liveIn[successor.dfsNum];
for (SparseSet::iterator i = live.begin(); !live.done(i); i = live.advance(i)) {
RegisterName name = RegisterName(live.get(i));
if (!successorLiveIn.test(name))
splitCost[name].loads += doLog10(successor.loopDepth);
}
}
}
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
splitCost[name2range[definePtr->getRegisterName()]].stores += weight;
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
if (!live.test(range)) {
if (&instruction != &instructions.last())
splitCost[range].loads += weight;
else {
ControlEdge* successorsEnd = node.getSuccessorsEnd();
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++)
splitCost[range].loads += doLog10(successorsPtr->getTarget().loopDepth);
}
}
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
live.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
live.set(name2range[usePtr->getRegisterName()]);
}
}
NameLinkedList** splitAround = new(pool) NameLinkedList*[rangeCount];
memset(splitAround, '\0', rangeCount * sizeof(NameLinkedList*));
registerAllocator.splitAround = splitAround;
registerAllocator.splitCost = splitCost;
registerAllocator.splitFound = false;
}
#endif // _SPLITS_H_

View File

@@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HashTable.h"
#include "Timer.h"
#include "Pool.h"
static Pool pool; // Pool for the Timer class.
static HashTable<TimerEntry*> timerEntries(pool); // Timers hashtable.
const nTimersInABlock = 128; // Number of timers in a block.
static PRTime *timers = new(pool) PRTime[nTimersInABlock]; // A block of timers.
static Uint8 nextTimer = 0; // nextAvailableTimer.
//
// Calibrate the call to PR_Now().
//
static PRTime calibrate()
{
PRTime t = PR_Now();
PRTime& a = *new(pool) PRTime();
// Call 10 times the PR_Now() function.
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
t = (PR_Now() - t + 9) / 10;
return t;
}
static PRTime adjust = calibrate();
//
// Return the named timer..
//
TimerEntry& Timer::getTimerEntry(const char* name)
{
if (!timerEntries.exists(name)) {
TimerEntry* newEntry = new(pool) TimerEntry();
newEntry->accumulator = 0;
newEntry->running = false;
timerEntries.add(name, newEntry);
}
return *timerEntries[name];
}
//
// Return a reference to a new timer.
//
PRTime& Timer::getNewTimer()
{
if (nextTimer >= nTimersInABlock) {
timers = new(pool) PRTime[nTimersInABlock];
nextTimer = 0;
}
return timers[nextTimer++];
}
static Uint32 timersAreFrozen = 0;
//
// Start the named timer.
//
void Timer::start(const char* name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(!timer.running);
timer.accumulator = 0;
timer.running = true;
timer.done = false;
unfreezeTimers();
}
//
// Stop the named timer.
//
void Timer::stop(const char* name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(timer.running);
timer.running = false;
timer.done = true;
unfreezeTimers();
}
//
// Freeze all the running timers.
//
void Timer::freezeTimers()
{
PRTime when = PR_Now() - adjust;
if (timersAreFrozen == 0) {
Vector<TimerEntry*> entries = timerEntries;
Uint32 count = entries.size();
for (Uint32 i = 0; i < count; i++) {
TimerEntry& entry = *entries[i];
if (entry.running) {
entry.accumulator += (when - *entry.startTime);
}
}
}
timersAreFrozen++;
}
//
// Unfreeze all the running timers.
//
void Timer::unfreezeTimers()
{
PR_ASSERT(timersAreFrozen != 0);
timersAreFrozen--;
if (timersAreFrozen == 0) {
Vector<TimerEntry *> entries = timerEntries;
Uint32 count = entries.size();
PRTime& newStart = getNewTimer();
for (Uint32 i = 0; i < count; i++) {
TimerEntry& entry = *entries[i];
if (entry.running) {
entry.startTime = &newStart;
}
}
newStart = PR_Now();
}
}
//
// Print the named timer in the file f.
//
void Timer::print(FILE* f, const char *name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(timer.done);
PRTime elapsed = timer.accumulator;
if (elapsed >> 32) {
fprintf(f, "[timer %s out of range]\n", name);
} else {
fprintf(f, "[%dus in %s]\n", Uint32(elapsed), name);
}
fflush(f);
unfreezeTimers();
}

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _TIMER_H_
#define _TIMER_H_
#include "Fundamentals.h"
#include "HashTable.h"
#include "prtime.h"
//
// Naming convention:
// As the class Timer contains only static methods, the timer's name should start with the
// module name. Otherwise starting 2 timers with the same name will assert.
//
#ifndef NO_TIMER
struct TimerEntry
{
PRTime *startTime; // Current time when we start the timer.
PRTime accumulator; // Time spent in this timer.
bool running; // True if the timer is running.
bool done; // True if the timer was running and was stopped.
};
class Timer
{
private:
// Return the named timer.
static TimerEntry& getTimerEntry(const char* name);
// Return a reference to a new Timer.
static PRTime& getNewTimer();
public:
// Start the timer.
static void start(const char* name);
// Stop the timer.
static void stop(const char* name);
// Freeze all the running timers.
static void freezeTimers();
// Unfreeze all the running timers.
static void unfreezeTimers();
// Print the timer.
static void print(FILE* f, const char *name);
};
inline void startTimer(const char* name) {Timer::start(name);}
inline void stopTimer(const char* name) {Timer::stop(name); Timer::print(stdout, name);}
#define START_TIMER_SAFE Timer::freezeTimers();
#define END_TIMER_SAFE Timer::unfreezeTimers();
#define TIMER_SAFE(x) START_TIMER_SAFE x; END_TIMER_SAFE
#else /* NO_TIMER */
inline void startTimer(const char* /*name*/) {}
inline void stopTimer(const char* /*name*/) {}
#define START_TIMER_SAFE
#define END_TIMER_SAFE
#define TIMER_SAFE(x) x;
#endif /* NO_TIMER */
#endif /* _TIMER_H_ */

View File

@@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "VirtualRegister.h"
#include "Instruction.h"
//------------------------------------------------------------------------------
// VirtualRegister -
#ifdef MANUAL_TEMPLATES
template class IndexedPool<VirtualRegister>;
#endif
// Set the defining instruction.
//
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
{
if (definingInstruction != NULL) {
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
return;
}
definingInstruction = &instruction;
}

View File

@@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _VIRTUAL_REGISTER_H_
#define _VIRTUAL_REGISTER_H_
#include "Fundamentals.h"
#include "IndexedPool.h"
#include <string.h>
#include "RegisterTypes.h"
#include "RegisterClass.h"
//------------------------------------------------------------------------------
// VirtualRegister - 24b
class Instruction;
class VirtualRegister : public IndexedObject<VirtualRegister>
{
public:
Instruction* definingInstruction; // Instruction defining this VR.
// Initialize a VR of the given classKind.
VirtualRegister(RegisterClassKind /*classKind*/) : definingInstruction(NULL) {}
// Return the defining instruction for this VR.
Instruction* getDefiningInstruction() const {return definingInstruction;}
// Set the defining instruction.
void setDefiningInstruction(Instruction& insn);
};
// Return true if the VirtualRegisters are equals. The only way 2 VRs can be equal is if
// they have the same index. If they have the same index then they are at the same
// address in the indexed pool.
//
inline bool operator == (const VirtualRegister& regA, const VirtualRegister& regB) {return &regA == &regB;}
//------------------------------------------------------------------------------
// VirtualRegisterManager -
struct PreColoredRegister
{
RegisterID id;
RegisterName color;
};
class VirtualRegisterManager
{
private:
IndexedPool<VirtualRegister> registerPool;
PreColoredRegister machineRegister[6];
public:
VirtualRegisterManager()
{
for (Uint32 i = 0; i < 6; i++)
machineRegister[i].id = invalidID;
}
// Return the VirtualRegister at the given index.
VirtualRegister& getVirtualRegister(RegisterName name) const {return registerPool.get(name);}
// Return a new VirtualRegister.
RegisterID newVirtualRegister(RegisterClassKind classKind)
{
VirtualRegister& vReg = *new(registerPool) VirtualRegister(classKind);
RegisterID rid;
setName(rid, RegisterName(vReg.getIndex()));
setClass(rid, classKind);
return rid;
}
RegisterID newMachineRegister(RegisterName name, RegisterClassKind classKind)
{
RegisterID rid = machineRegister[name].id;
if (rid == invalidID) {
rid = newVirtualRegister(classKind);
DEBUG_ONLY(setMachineRegister(rid));
machineRegister[name].id = rid;
machineRegister[name].color = name;
}
return rid;
}
PreColoredRegister* getMachineRegistersBegin() const {return (PreColoredRegister*) machineRegister;} // FIX
PreColoredRegister* getMachineRegistersEnd() const {return (PreColoredRegister*) &machineRegister[6];} // FIX
// Return the VirtualRegister universe size.
Uint32 getSize() {return registerPool.getSize();}
void setSize(Uint32 size) {registerPool.setSize(size);}
};
#endif // _VIRTUAL_REGISTER_H_

View File

@@ -1,44 +0,0 @@
STLPORT = /usr/local/include/stlport
CC = gcc
CFLAGS = -g -ggdb -DDEBUG -DXP_UNIX -Wall -W -Wpointer-arith \
-Wbad-function-cast -Wstrict-prototypes -Wmissing-prototypes \
-Wno-non-virtual-dtor -I$(STLPORT)
objs = hash.o \
icodegenerator.o \
interpreter.o \
js2.o \
jsmath.o \
jstypes.o \
numerics.o \
parser.o \
utilities.o \
world.o \
vmtypes.o \
debugger.o
gc_path = ../../gc/boehm/
libs = gc.a -lstdc++ -lm
%.o : %.cpp
$(CC) -c $(CFLAGS) $< -o $@
js2: $(objs) gc.a
$(CC) -o $@ -ggdb $(objs) $(libs)
gc.a:
(cd $(gc_path) ; ln -f -s Makefile.unix Makefile ; make gc.a)
ln -f -s $(gc_path)gc.a ./gc.a
gctest: gc_allocator.o
$(CC) -o $@ -ggdb $^ $(libs)
clean:
rm -f $(objs)
depend:
gcc -MM *.cpp > dependencies
include dependencies

View File

@@ -1,111 +0,0 @@
# Microsoft Developer Studio Project File - Name="CPlusPlusTests" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=CPlusPlusTests - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "CPlusPlusTests.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "CPlusPlusTests.mak" CFG="CPlusPlusTests - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "CPlusPlusTests - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "CPlusPlusTests - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "CPlusPlusTests - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
!ELSEIF "$(CFG)" == "CPlusPlusTests - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "CPlusPlusTests - Win32 Release"
# Name "CPlusPlusTests - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\cplusplustests.cpp
!IF "$(CFG)" == "CPlusPlusTests - Win32 Release"
!ELSEIF "$(CFG)" == "CPlusPlusTests - Win32 Debug"
# ADD CPP /Ob1 /FR
# SUBTRACT CPP /O<none> /YX
!ENDIF
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@@ -1,29 +0,0 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "CPlusPlusTests"=.\CPlusPlusTests.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -1,129 +0,0 @@
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <new>
using namespace std;
struct Arena {
const char *name;
Arena(const char *name): name(name) {}
};
void *operator new(size_t size, Arena &arena);
void operator delete(void *p);
void *operator new(size_t size, Arena &arena)
{
void *p = malloc(size);
printf("Allocating %d bytes at %p using arena \"%s\"\n", size, p, arena.name);
return p;
}
#ifndef __MWERKS__
void operator delete(void *p, Arena &arena)
{
printf("Deleting object at %p using arena \"%s\"\n", p, arena.name);
}
#endif
void operator delete(void *p)
{
printf("Deleting object at %p\n", p);
}
struct C {
int n;
C(int n, bool bad = false);
~C();
};
struct Exception {
int num;
explicit Exception(int n): num(n) {}
};
C::C(int n, bool bad): n(n)
{
printf("Constructing C #%d at %p\n", n, this);
if (bad) {
printf("Throwing %d; constructor aborted\n", n);
throw Exception(n);
}
}
C::~C()
{
printf("Destroying C #%d at %p\n", n, this);
}
static void constructorTest1(int n, bool bad)
{
try {
printf("Calling C(%d,%d)\n", n, (int)bad);
{
C c(n, bad);
printf("We have C #%d\n", c.n);
}
printf("C is out of scope\n");
} catch (Exception &e) {
printf("Caught exception %d\n", e.num);
}
printf("\n");
}
static void constructorTest2(int n, bool bad)
{
try {
printf("Calling new C(%d,%d)\n", n, (int)bad);
{
C *c = new C(n, bad);
printf("We have C #%d\n", c->n);
delete c;
}
printf("C is out of scope\n");
} catch (Exception &e) {
printf("Caught exception %d\n", e.num);
}
printf("\n");
}
static void constructorTest3(int n, bool bad)
{
try {
printf("Calling new(arena) C(%d,%d)\n", n, (int)bad);
{
Arena arena("My arena");
C *c = new(arena) C(n, bad);
printf("We have C #%d\n", c->n);
}
printf("C is out of scope\n");
} catch (Exception &e) {
printf("Caught exception %d\n", e.num);
}
printf("\n");
}
int main()
{
printf("Beginning constructor tests\n\n");
constructorTest1(1, false);
constructorTest1(2, true);
constructorTest2(3, false);
constructorTest2(4, true);
constructorTest3(5, false);
constructorTest3(6, true);
printf("Ending constructor tests\n");
return 0;
}

View File

@@ -1,191 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef cpucfg_h
#define cpucfg_h
#define JS_HAVE_LONG_LONG
#ifdef XP_MAC
#undef IS_LITTLE_ENDIAN
#define IS_BIG_ENDIAN 1
#define JS_BYTES_PER_BYTE 1L
#define JS_BYTES_PER_SHORT 2L
#define JS_BYTES_PER_INT 4L
#define JS_BYTES_PER_INT64 8L
#define JS_BYTES_PER_LONG 4L
#define JS_BYTES_PER_FLOAT 4L
#define JS_BYTES_PER_DOUBLE 8L
#define JS_BYTES_PER_WORD 4L
#define JS_BYTES_PER_DWORD 8L
#define JS_BITS_PER_BYTE 8L
#define JS_BITS_PER_SHORT 16L
#define JS_BITS_PER_INT 32L
#define JS_BITS_PER_INT64 64L
#define JS_BITS_PER_LONG 32L
#define JS_BITS_PER_FLOAT 32L
#define JS_BITS_PER_DOUBLE 64L
#define JS_BITS_PER_WORD 32L
#define JS_BITS_PER_BYTE_LOG2 3L
#define JS_BITS_PER_SHORT_LOG2 4L
#define JS_BITS_PER_INT_LOG2 5L
#define JS_BITS_PER_INT64_LOG2 6L
#define JS_BITS_PER_LONG_LOG2 5L
#define JS_BITS_PER_FLOAT_LOG2 5L
#define JS_BITS_PER_DOUBLE_LOG2 6L
#define JS_BITS_PER_WORD_LOG2 5L
#define JS_ALIGN_OF_SHORT 2L
#define JS_ALIGN_OF_INT 4L
#define JS_ALIGN_OF_LONG 4L
#define JS_ALIGN_OF_INT64 2L
#define JS_ALIGN_OF_FLOAT 4L
#define JS_ALIGN_OF_DOUBLE 4L
#define JS_ALIGN_OF_POINTER 4L
#define JS_ALIGN_OF_WORD 4L
#define JS_BYTES_PER_WORD_LOG2 2L
#define JS_BYTES_PER_DWORD_LOG2 3L
#define PR_WORDS_PER_DWORD_LOG2 1L
#elif defined(XP_PC)
#ifdef _WIN32
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#define JS_BYTES_PER_BYTE 1L
#define JS_BYTES_PER_SHORT 2L
#define JS_BYTES_PER_INT 4L
#define JS_BYTES_PER_INT64 8L
#define JS_BYTES_PER_LONG 4L
#define JS_BYTES_PER_FLOAT 4L
#define JS_BYTES_PER_DOUBLE 8L
#define JS_BYTES_PER_WORD 4L
#define JS_BYTES_PER_DWORD 8L
#define JS_BITS_PER_BYTE 8L
#define JS_BITS_PER_SHORT 16L
#define JS_BITS_PER_INT 32L
#define JS_BITS_PER_INT64 64L
#define JS_BITS_PER_LONG 32L
#define JS_BITS_PER_FLOAT 32L
#define JS_BITS_PER_DOUBLE 64L
#define JS_BITS_PER_WORD 32L
#define JS_BITS_PER_BYTE_LOG2 3L
#define JS_BITS_PER_SHORT_LOG2 4L
#define JS_BITS_PER_INT_LOG2 5L
#define JS_BITS_PER_INT64_LOG2 6L
#define JS_BITS_PER_LONG_LOG2 5L
#define JS_BITS_PER_FLOAT_LOG2 5L
#define JS_BITS_PER_DOUBLE_LOG2 6L
#define JS_BITS_PER_WORD_LOG2 5L
#define JS_ALIGN_OF_SHORT 2L
#define JS_ALIGN_OF_INT 4L
#define JS_ALIGN_OF_LONG 4L
#define JS_ALIGN_OF_INT64 8L
#define JS_ALIGN_OF_FLOAT 4L
#define JS_ALIGN_OF_DOUBLE 4L
#define JS_ALIGN_OF_POINTER 4L
#define JS_ALIGN_OF_WORD 4L
#define JS_BYTES_PER_WORD_LOG2 2L
#define JS_BYTES_PER_DWORD_LOG2 3L
#define PR_WORDS_PER_DWORD_LOG2 1L
#endif /* _WIN32 */
#if defined(_WINDOWS) && !defined(_WIN32) /* WIN16 */
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#define JS_BYTES_PER_BYTE 1L
#define JS_BYTES_PER_SHORT 2L
#define JS_BYTES_PER_INT 2L
#define JS_BYTES_PER_INT64 8L
#define JS_BYTES_PER_LONG 4L
#define JS_BYTES_PER_FLOAT 4L
#define JS_BYTES_PER_DOUBLE 8L
#define JS_BYTES_PER_WORD 4L
#define JS_BYTES_PER_DWORD 8L
#define JS_BITS_PER_BYTE 8L
#define JS_BITS_PER_SHORT 16L
#define JS_BITS_PER_INT 16L
#define JS_BITS_PER_INT64 64L
#define JS_BITS_PER_LONG 32L
#define JS_BITS_PER_FLOAT 32L
#define JS_BITS_PER_DOUBLE 64L
#define JS_BITS_PER_WORD 32L
#define JS_BITS_PER_BYTE_LOG2 3L
#define JS_BITS_PER_SHORT_LOG2 4L
#define JS_BITS_PER_INT_LOG2 4L
#define JS_BITS_PER_INT64_LOG2 6L
#define JS_BITS_PER_LONG_LOG2 5L
#define JS_BITS_PER_FLOAT_LOG2 5L
#define JS_BITS_PER_DOUBLE_LOG2 6L
#define JS_BITS_PER_WORD_LOG2 5L
#define JS_ALIGN_OF_SHORT 2L
#define JS_ALIGN_OF_INT 2L
#define JS_ALIGN_OF_LONG 2L
#define JS_ALIGN_OF_INT64 2L
#define JS_ALIGN_OF_FLOAT 2L
#define JS_ALIGN_OF_DOUBLE 2L
#define JS_ALIGN_OF_POINTER 2L
#define JS_ALIGN_OF_WORD 2L
#define JS_BYTES_PER_WORD_LOG2 2L
#define JS_BYTES_PER_DWORD_LOG2 3L
#define PR_WORDS_PER_DWORD_LOG2 1L
#endif /* defined(_WINDOWS) && !defined(_WIN32) */
#elif defined(XP_UNIX) || defined(XP_BEOS)
#error "This file is supposed to be auto-generated on UNIX platforms, but the"
#error "static version for Mac and Windows platforms is being used."
#error "Something's probably wrong with paths/headers/dependencies/Makefiles."
#else
#error "Must define one of XP_MAC, XP_PC, or XP_UNIX"
#endif
#endif

View File

@@ -1,466 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include "world.h"
#include "debugger.h"
#include <string>
#include <ctype.h>
#include <assert.h>
namespace JavaScript {
namespace Debugger {
using namespace Interpreter;
/* keep in sync with list in debugger.h */
static const char *shell_cmds[][3] = {
{"assemble", "", 0},
{"ambiguous", "", "Test command for ambiguous command detection"},
{"ambiguous2", "", "Test command for ambiguous command detection"},
{"continue", "", "Continue execution until complete."},
{"dissassemble", "[start_pc] [end_pc]", "Dissassemble entire module, or subset of module."},
{"exit", "", 0},
{"help", "", "Display this message."},
{"istep", "", "Execute the current opcode and stop."},
{"let", "", "Set a debugger environment variable."},
{"print", "", 0},
{"register", "", "(nyi) Show the value of a single register or all registers, or set the value of a single register."},
{"step", "", "Execute the current JS statement and stop."},
{0, 0} /* sentry */
};
enum ShellVariable {
TRACE_SOURCE,
TRACE_ICODE,
VARIABLE_COUNT
};
static const char *shell_vars[][3] = {
{"tracesource", "", "(bool) Show JS source while executing."},
{"traceicode", " ", "(bool) Show opcodes while executing."},
{0, 0} /* sentry */
};
/* return true if str2 starts with/is str1
* XXX ignore case */
static bool
startsWith (const String &str1, const String &str2)
{
uint n;
size_t m = str1.size();
if (m > str2.size())
return false;
for (n = 0; n < m; ++n)
if (str1[n] != str2[n])
return false;
return true;
}
/**
* locate the best match for |partial| in the command list |list|.
* if no matches are found, return |length|, if multiple matches are found,
* return |length| plus the number of ambiguous matches
*/
static uint32
matchElement (const String &partial, const char *list[][3], size_t length)
{
uint32 ambig_matches = 0;
uint32 match = length;
for (uint32 i = 0; i < length ; ++i)
{
String possibleMatch (widenCString(list[i][0]));
if (startsWith(partial, possibleMatch))
{
if (partial.size() == possibleMatch.size())
{
/* exact match */
ambig_matches = 0;
return i;
}
else if (match == COMMAND_COUNT) /* no match yet */
match = i;
else
++ambig_matches; /* something already matched,
* ambiguous command */
}
}
if (ambig_matches == 0)
return match;
else
return length + ambig_matches;
}
static void
showHelp(Formatter &out)
{
int i;
out << "JavaScript 2.0 Debugger Help...\n\n";
for (i = 0; shell_cmds[i][0] != 0; i++)
{
out << "Command : " << shell_cmds[i][0] << " " <<
shell_cmds[i][1] << "\n";
if (shell_cmds[i][2])
out << "Help : " << shell_cmds[i][2] << "\n";
else
out << "Help : (probably) Not Implemented.\n";
}
}
static uint32
getClosestSourcePosForPC (Context *cx, InstructionIterator pc)
{
ICodeModule *iCode = cx->getICode();
if (iCode->mInstructionMap->begin() == iCode->mInstructionMap->end())
return NotABanana;
/*NOT_REACHED ("Instruction map is empty, waah.");*/
InstructionMap::iterator pos_iter =
iCode->mInstructionMap->upper_bound (pc - iCode->its_iCode->begin());
if (pos_iter != iCode->mInstructionMap->begin())
--pos_iter;
return pos_iter->second;
}
void
Shell::showSourceAtPC (Context *cx, InstructionIterator pc)
{
if (!mResolveFileCallback)
{
mErr << "Source not available (Debugger was improperly initialized.)\n";
return;
}
ICodeModule *iCode = cx->getICode();
String fn = iCode->getFileName();
const Reader *reader = mResolveFileCallback(fn);
if (!reader)
{
mErr << "Source not available.\n";
return;
}
uint32 pos = getClosestSourcePosForPC(cx, pc);
if (pos == NotABanana)
{
mErr << "Map is empty, cannot display source.\n";
return;
}
uint32 lineNum = reader->posToLineNum (pos);
const char16 *lineBegin, *lineEnd;
uint32 lineStartPos = reader->getLine (lineNum, lineBegin, lineEnd);
String sourceLine (lineBegin, lineEnd);
mOut << fn << ":" << lineNum << " " << sourceLine << "\n";
uint padding = fn.length() + (uint32)(lineNum / 10) + 3;
uint i;
for (i = 0; i < padding; i++)
mOut << " ";
padding = (pos - lineStartPos);
for (i = 0; i < padding; i++)
mOut << ".";
mOut << "^\n";
}
void
Shell::showOpAtPC(Context* cx, InstructionIterator pc)
{
ICodeModule *iCode = cx->getICode();
if ((pc < iCode->its_iCode->begin()) ||
(pc >= iCode->its_iCode->end()))
{
mErr << "PC Out Of Range.";
return;
}
JSValues &registers = cx->getRegisters();
printFormat(mOut, "trace [%02u:%04u]: ",
iCode->mID, (pc - iCode->its_iCode->begin()));
Instruction* i = *pc;
stdOut << *i;
if (i->op() != BRANCH && i->count() > 0) {
mOut << " [";
i->printOperands(stdOut, registers);
mOut << "]\n";
} else {
mOut << '\n';
}
}
void
Shell::listen(Context* cx, Context::Event event)
{
InstructionIterator pc = cx->getPC();
if (mTraceSource)
showSourceAtPC (cx, pc);
if (mTraceICode)
showOpAtPC (cx, pc);
if (!(mStopMask & event))
return;
if ((mLastCommand == STEP) && (mLastICodeID == cx->getICode()->mID) &&
(mLastSourcePos == getClosestSourcePosForPC (cx, cx->getPC())))
/* we're in source-step mode, and the source position hasn't
* changed yet */
return;
if (!mTraceSource && !mTraceICode)
showSourceAtPC (cx, pc);
static String lastLine(widenCString("help\n"));
String line;
LineReader reader(mIn);
do {
stdOut << "jsd";
if (mLastCommand != COMMAND_COUNT)
stdOut << " (" << shell_cmds[mLastCommand][0] << ") ";
stdOut << "> ";
reader.readLine(line);
if (line[0] == uni::lf)
line = lastLine;
else
lastLine = line;
} while (doCommand(cx, line));
}
/**
* lex and execute the debugger command in |source|, return true if the
* command does not require the script being debugged to continue (eg, ask
* for more debugger input.)
*/
bool
Shell::doCommand (Interpreter::Context *cx, const String &source)
{
Lexer lex (mWorld, source, widenCString("debugger console"), 0);
const String *cmd;
uint32 match;
bool rv = true;
const Token &t = lex.get(true);
if (t.hasKind(Token::identifier))
cmd = &(t.getIdentifier());
else
{
mErr << "you idiot.\n";
return true;
}
match = matchElement (*cmd, shell_cmds, (size_t)COMMAND_COUNT);
if (match <= (uint32)COMMAND_COUNT)
{
switch ((ShellCommand)match)
{
case COMMAND_COUNT:
mErr << "Unknown command '" << *cmd << "'.\n";
break;
case AMBIGUOUS:
case AMBIGUOUS2:
mErr << "I pity the foogoo.\n";
break;
case CONTINUE:
mStopMask &= (Context::EV_ALL ^ Context::EV_STEP);
rv = false;
break;
case DISSASSEMBLE:
mOut << *cx->getICode();
break;
case HELP:
showHelp (mOut);
break;
case PRINT:
doPrint (cx, lex);
break;
case STEP:
mStopMask |= Context::EV_STEP;
rv = false;
break;
case LET:
doSetVariable (lex);
break;
default:
mErr << "Input '" << *cmd << "' matched unimplemented " <<
"command '" << shell_cmds[match][0] << "'.\n";
break;
}
mLastSourcePos = getClosestSourcePosForPC (cx, cx->getPC());
mLastICodeID = cx->getICode()->mID;
mLastCommand = (ShellCommand)match;
} else
mErr << "Ambiguous command '" << *cmd << "', " <<
(match - (uint32)COMMAND_COUNT + 1) << " similar commands.\n";
return rv;
}
void
Shell::doSetVariable (Lexer &lex)
{
uint32 match;
const String *varname;
const Token *t = &(lex.get(true));
if (t->hasKind(Token::identifier))
varname = &(t->getIdentifier());
else
{
mErr << "invalid variable name.\n";
return;
}
match = matchElement (*varname, shell_vars, (size_t)VARIABLE_COUNT);
if (match <= (uint32)VARIABLE_COUNT)
switch ((ShellVariable)match)
{
case VARIABLE_COUNT:
mErr << "Unknown variable '" << *varname << "'.\n";
break;
case TRACE_SOURCE:
t = &(lex.get(true));
if (t->hasKind(Token::assignment))
t = &(lex.get(true)); /* optional = */
if (t->hasKind(Token::True))
mTraceSource = true;
else if (t->hasKind(Token::False))
mTraceSource = false;
else
goto badval;
break;
case TRACE_ICODE:
t = &(lex.get(true));
if (t->hasKind(Token::assignment))
t = &(lex.get(true)); /* optional = */
if (t->hasKind(Token::True))
mTraceICode = true;
else if (t->hasKind(Token::False))
mTraceICode = false;
else
goto badval;
break;
default:
mErr << "Variable '" << *varname <<
"' matched unimplemented variable '" <<
shell_vars[match][0] << "'.\n";
}
else
mErr << "Ambiguous variable '" << *varname << "', " <<
(match - (uint32)COMMAND_COUNT + 1) << " similar variables.\n";
return;
badval:
mErr << "Invalid value for variable '" <<
shell_vars[(ShellVariable)match][0] << "'\n";
}
void
Shell::doPrint (Context *, Lexer &lex)
{
const Token *t = &(lex.get(true));
if (!(t->hasKind(Token::identifier)))
{
mErr << "Invalid register name.\n";
return;
}
/*
const StringAtom *name = &(t->getIdentifier());
VariableMap::iterator i = ((cx->getICode())->itsVariables)->find(*name);
// if (i)
mOut << (*i).first << " = " << (*i).second << "\n";
// else
// mOut << "No " << *name << " defined.\n";
*/
}
} /* namespace Debugger */
} /* namespace JavaScript */

View File

@@ -1,163 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/* this is all vapor, don't take it to serious yet */
#ifndef debugger_h
#define debugger_h
#include "utilities.h"
#include "interpreter.h"
#include <stdio.h>
namespace JavaScript {
namespace Debugger {
using namespace Interpreter;
class Shell;
typedef const Reader *ResolveFileCallback (const String &fileName);
typedef bool DebuggerCommandCallback (Shell &debugger, const Lexer &lex);
class Breakpoint {
public:
/* representation of a breakpoint */
void set();
void clear();
bool getState();
InstructionIterator getPC();
};
struct DebuggerCommand
{
DebuggerCommand(String aName, String aParamDesc, String aShortHelp,
String aLongHelp = widenCString("No more help available."),
DebuggerCommandCallback *aCommandFunction = 0)
: mName(aName), mParamDesc(aParamDesc), mShortHelp(aShortHelp),
mLongHelp(aLongHelp), mCommandFunction(aCommandFunction) {}
String mName;
String mParamDesc;
String mShortHelp;
String mLongHelp;
DebuggerCommandCallback *mCommandFunction;
};
/* keep in sync with list in debugger.cpp */
enum ShellCommand {
ASSEMBLE,
AMBIGUOUS,
AMBIGUOUS2,
CONTINUE,
DISSASSEMBLE,
EXIT,
HELP,
ISTEP,
LET,
PRINT,
REGISTER,
STEP,
COMMAND_COUNT
};
class Shell : public Context::Listener {
public:
Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr,
ResolveFileCallback *aCallback = 0) :
mWorld(aWorld), mIn(aIn), mOut(aOut), mErr(aErr),
mResolveFileCallback(aCallback), mStopMask(Context::EV_DEBUG),
mTraceSource(false), mTraceICode(false), mLastSourcePos(0),
mLastICodeID(NotABanana), mLastCommand(COMMAND_COUNT)
{
}
~Shell ()
{
}
ResolveFileCallback
*setResolveFileCallback (ResolveFileCallback *aCallback)
{
ResolveFileCallback *rv = mResolveFileCallback;
mResolveFileCallback = aCallback;
return rv;
}
void listen(Context *context, Context::Event event);
/**
* install on a context
*/
bool attachToContext (Context *aContext)
{
aContext->addListener (this);
return true;
}
/**
* detach an icdebugger from a context
*/
bool detachFromContext (Context *aContext)
{
aContext->removeListener (this);
return true;
}
FILE *getIStream() { return mIn; }
Formatter &getOStream() { return mOut; }
Formatter &getEStream() { return mErr; }
private:
bool doCommand (Context *cx, const String &aSource);
void doSetVariable (Lexer &lex);
void doPrint (Context *cx, Lexer &lex);
void showOpAtPC(Context* cx, InstructionIterator pc);
void showSourceAtPC(Context* cx, InstructionIterator pc);
World &mWorld;
FILE *mIn;
Formatter &mOut, &mErr;
ResolveFileCallback *mResolveFileCallback;
uint32 mStopMask;
bool mTraceSource, mTraceICode;
uint32 mLastSourcePos, mLastICodeID;
ShellCommand mLastCommand;
};
} /* namespace Debugger */
} /* namespace JavaScript */
#endif /* debugger_h */

View File

@@ -1,26 +0,0 @@
debugger.o: debugger.cpp world.h utilities.h systemtypes.h hash.h \
parser.h debugger.h interpreter.h jstypes.h gc_allocator.h vmtypes.h \
numerics.h jsclasses.h icode.h icodegenerator.h
gc_allocator.o: gc_allocator.cpp gc_allocator.h gc_container.h
hash.o: hash.cpp hash.h utilities.h systemtypes.h
icodegenerator.o: icodegenerator.cpp numerics.h utilities.h \
systemtypes.h world.h hash.h parser.h vmtypes.h jstypes.h \
gc_allocator.h jsclasses.h icode.h icodegenerator.h interpreter.h
interpreter.o: interpreter.cpp interpreter.h utilities.h systemtypes.h \
jstypes.h gc_allocator.h vmtypes.h numerics.h jsclasses.h world.h \
hash.h parser.h icode.h icodegenerator.h jsmath.h
js2.o: js2.cpp world.h utilities.h systemtypes.h hash.h parser.h \
interpreter.h jstypes.h gc_allocator.h vmtypes.h numerics.h \
jsclasses.h icode.h icodegenerator.h debugger.h
jsmath.o: jsmath.cpp jsmath.h jstypes.h utilities.h systemtypes.h \
gc_allocator.h
jstypes.o: jstypes.cpp jstypes.h utilities.h systemtypes.h \
gc_allocator.h jsclasses.h numerics.h icodegenerator.h parser.h \
vmtypes.h world.h hash.h icode.h
numerics.o: numerics.cpp numerics.h utilities.h systemtypes.h
parser.o: parser.cpp numerics.h utilities.h systemtypes.h parser.h \
world.h hash.h
utilities.o: utilities.cpp utilities.h systemtypes.h
vmtypes.o: vmtypes.cpp utilities.h systemtypes.h vmtypes.h numerics.h \
jstypes.h gc_allocator.h jsclasses.h world.h hash.h parser.h icode.h
world.o: world.cpp world.h utilities.h systemtypes.h hash.h parser.h

View File

@@ -1,150 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 2000 Netscape Communications Corporation. All
// Rights Reserved.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "gc_allocator.h"
#include "gc_container.h"
/*
namespace JavaScript {
template <class T>
typename gc_allocator<T>::pointer
gc_allocator<T>::allocate(gc_allocator<T>::size_type n, const void*)
{
return static_cast<pointer>(GC_malloc(n*sizeof(T)));
}
template <class T>
void gc_allocator<T>::deallocate(gc_allocator<T>::pointer ptr, gc_allocator<T>::size_type)
{
// this can really be a NO-OP with the GC.
// ::GC_free(static_cast<void*>(ptr));
}
}
*/
// test driver for standalone GC development.
namespace JS = JavaScript;
template <class T>
void* operator new(std::size_t, const JS::gc_allocator<T>& alloc)
{
return alloc.allocate(1);
}
/**
* Define a C++ class that is garbage collectable, and wants to have its destructor
* called when it is finalized.
*/
class A {
public:
typedef JS::gc_traits_finalizable<A> traits;
typedef JS::gc_allocator<A, traits> allocator;
friend struct traits;
static int instances;
void* operator new(std::size_t)
{
return allocator::allocate(1);
}
A()
{
++instances;
std::cout << "A::A() here." << std::endl;
}
protected:
~A()
{
--instances;
std::cout << "A::~A() here." << std::endl;
}
private:
// void operator delete(void*) {}
};
int A::instances = 0;
int main(int /* argc */, char* /* argv[] */)
{
using namespace std;
using namespace JS;
cout << "testing the GC allocator." << endl;
#ifdef XP_MAC
// allocate a string, using the GC, and owned by an auto_ptr, that knows how to correctly destroy the string.
typedef gc_container<char>::string char_string;
typedef gc_allocator<char_string> char_string_alloc;
auto_ptr<char_string, char_string_alloc> ptr(new(char_string_alloc()) char_string("This is a garbage collectable string."));
const char_string& str = *ptr;
cout << str << endl;
#endif
// question, how can we partially evaluate a template?
// can we say, typedef template <class T> vector<typename T>.
// typedef vector<int, gc_allocator<int> > int_vector;
typedef gc_container<int>::vector int_vector;
// generate 1000 random values.
int_vector values;
for (int i = 0; i < 1000; ++i) {
int value = rand() % 32767;
values.push_back(value);
// allocate a random amount of garbage.
if (!GC_malloc(static_cast<size_t>(value)))
cerr << "GC_malloc failed." << endl;
// allocate an object that has a finalizer to call its destructor.
A* a = new A();
}
// run a collection.
// gc_allocator<void>::collect();
GC_gcollect();
// print out instance count.
cout << "A::instances = " << A::instances << endl;
// sort the values.
sort(values.begin(), values.end());
// print the values.
int_vector::iterator iter = values.begin(), last = values.end();
cout << *iter++;
while (iter < last)
cout << ' ' << *iter++;
cout << endl;
#ifdef XP_MAC
// finally, print the string again.
cout << str << endl;
#endif
return 0;
}

View File

@@ -1,178 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 2000 Netscape Communications Corporation. All
// Rights Reserved.
#ifndef gc_allocator_h
#define gc_allocator_h
#include <memory>
#ifndef _WIN32 // Microsoft VC6 bug: standard identifiers should be in std namespace
using std::size_t;
using std::ptrdiff_t;
#endif
namespace JavaScript {
extern "C" {
void* GC_malloc(size_t bytes);
void* GC_malloc_atomic(size_t bytes);
void GC_free(void* ptr);
void GC_gcollect(void);
typedef void (*GC_finalization_proc) (void* obj, void* client_data);
void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data,
GC_finalization_proc *old_proc, void* *old_client_data);
}
#if 0 && !defined(XP_MAC)
// for platforms where GC doesn't exist yet.
inline void* GC_malloc(size_t bytes) { return ::operator new(bytes); }
inline void* GC_malloc_atomic(size_t bytes) { return ::operator new(bytes); }
inline void GC_free(void* ptr) { operator delete(ptr); }
inline void GC_gcollect() {}
inline void GC_register_finalizer(void* obj, GC_finalization_proc proc, void* client_data,
GC_finalization_proc *old_proc, void* *old_client_data) {}
#endif
/**
* General case: memory for type must be allocated as a conservatively
* scanned block of memory.
*/
template <class T> struct gc_traits {
static T* allocate(size_t n) { return static_cast<T*>(GC_malloc(n * sizeof(T))); }
};
/**
* Specializations for blocks of atomic types: the macro define_atomic_type(_type)
* specializes gc_traits<T> for types that need not be scanned by the
* GC. Implementors are free to define other types as atomic, if they are
* guaranteed not to contain pointers.
*/
#define define_atomic_type(_type) \
template <> struct gc_traits<_type> { \
static _type* allocate(size_t n) \
{ \
return static_cast<_type*>(GC_malloc_atomic(n * sizeof(_type))); \
} \
};
define_atomic_type(char)
define_atomic_type(unsigned char)
define_atomic_type(short)
define_atomic_type(unsigned short)
define_atomic_type(int)
define_atomic_type(unsigned int)
define_atomic_type(long)
define_atomic_type(unsigned long)
define_atomic_type(float)
define_atomic_type(double)
#undef define_atomic_type
/**
* Traits for classes that need to have their destructor called
* when reclaimed by the garbage collector.
*/
template <class T> struct gc_traits_finalizable {
static void finalizer(void* obj, void* client_data)
{
T* t = static_cast<T*>(obj);
size_t n = reinterpret_cast<size_t>(client_data);
for (size_t i = 0; i < n; ++i)
t[i].~T();
}
static T* allocate(size_t n)
{
T* t = gc_traits<T>::allocate(n);
GC_finalization_proc old_proc; void* old_client_data;
GC_register_finalizer(t, &finalizer, reinterpret_cast<void*>(n), &old_proc, &old_client_data);
return t;
}
};
/**
* An allocator that can be used to allocate objects in the garbage collected heap.
*/
template <class T, class traits = gc_traits<T> > class gc_allocator {
public:
typedef T value_type;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
gc_allocator() {}
template<typename U, typename UTraits> gc_allocator(const gc_allocator<U, UTraits>&) {}
// ~gc_allocator() {}
static pointer address(reference r) { return &r; }
static const_pointer address(const_reference r) { return &r; }
static pointer allocate(size_type n, const void* /* hint */ = 0) { return traits::allocate(n); }
static void deallocate(pointer, size_type) {}
static void construct(pointer p, const T &val) { new(p) T(val);}
static void destroy(pointer p) { p->~T(); }
#if defined(__GNUC__) || defined(_WIN32)
static size_type max_size() { return size_type(-1) / sizeof(T); }
#else
static size_type max_size() { return std::numeric_limits<size_type>::max() / sizeof(T); }
#endif
template<class U> struct rebind { typedef gc_allocator<U> other; };
#ifdef _WIN32
// raw byte allocator used on some platforms (grrr).
typedef char _Char[1];
static char* _Charalloc(size_type n) { return (char*) rebind<_Char>::other::allocate(n); }
// funky operator required for calling basic_string<T> constructor (grrr).
template<typename U, typename UTraits> int operator==(const gc_allocator<U, UTraits>&) { return 0; }
#endif
// void* deallocate used on some platforms (grrr).
static void deallocate(void*, size_type) {}
static void collect() { GC_gcollect(); }
};
/**
* Generic base class for objects allocated using a gc_allocator. How they are allocated
* can be controlled by specializing gc_traits for the specific class.
*/
template <typename T> class gc_object {
public:
void* operator new(size_t) { return gc_allocator<T>::allocate(1, 0); }
void operator delete(void* /* ptr */) {}
};
/**
* Simpler base class for classes that have no need to specialize allocation behavior.
*/
class gc_base {
public:
void* operator new(size_t n) { return GC_malloc(n); }
void operator delete(void*) {}
};
}
#endif /* gc_allocator_h */

View File

@@ -1,71 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 2000 Netscape Communications Corporation. All
// Rights Reserved.
#ifndef gc_container_h
#define gc_container_h
#include "gc_allocator.h"
#include <list>
#include <vector>
#include <string>
#define LIST std::list
#define VECTOR std::vector
#if defined(__GNUC__)
// grr, what kind of standard is this?
#define STRING basic_string
#define CHAR_TRAITS string_char_traits
#else
#define STRING std::basic_string
#define CHAR_TRAITS std::char_traits
#endif
namespace JavaScript {
/**
* Rebind some of the basic container types to use a GC_allocator.
* What I really want is something more general, something like:
* template <typename Container, typename T> class gc_rebind {
* typedef typename Container<T, gc_allocator<T> > other;
* };
* But I can't figure out how to do that with C++ templates.
*/
template <class T> struct gc_container {
typedef typename LIST<T, gc_allocator<T> > list;
typedef typename VECTOR<T, gc_allocator<T> > vector;
typedef typename STRING<T, CHAR_TRAITS<T>, gc_allocator<T> > string;
};
/**
* But, it's pretty easy to do with macros:
*/
#define GC_CONTAINER(container, type) container<T, gc_allocator<T> >
/*
// this gives an "unimplemented C++ feature" error using CWPro5.
// maybe someday.
template <template<class, class> typename Container, typename T>
struct gc_rebind {
typedef typename Container<T, gc_allocator<T> > container;
};
*/
}
#endif /* gc_container_h */

View File

@@ -1,173 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 1998 Netscape Communications Corporation. All
// Rights Reserved.
#include "hash.h"
#include <new>
namespace JS = JavaScript;
//
// Hash Codes
//
// General-purpose null-terminated C string hash function
JS::HashNumber JS::hashString(const char *s)
{
HashNumber h = 0;
uchar ch;
while ((ch = (uchar)*s++) != 0)
h = (h >> 28) ^ (h << 4) ^ ch;
return h;
}
// General-purpose String hash function
JS::HashNumber JS::hashString(const String &s)
{
HashNumber h = 0;
String::const_iterator p = s.begin();
String::size_type n = s.size();
if (n < 16)
// Hash every character in a short string.
while (n--)
h = (h >> 28) ^ (h << 4) ^ *p++;
else
// Sample a la java.lang.String.hash().
for (String::size_type m = n / 8; n >= m; p += m, n -= m)
h = (h >> 28) ^ (h << 4) ^ *p;
return h;
}
//
// Hash Tables
//
const uint minLgNBuckets = 4;
JS::GenericHashTableIterator::GenericHashTableIterator(GenericHashTable &ht):
ht(ht), entry(0), nextBucket(ht.buckets)
{
DEBUG_ONLY(++ht.nReferences);
operator++();
}
JS::GenericHashTableIterator &
JS::GenericHashTableIterator::operator++()
{
GenericHashEntry *e = entry;
if (e) {
backpointer = &e->next;
e = e->next;
}
if (!e) {
GenericHashEntry **const bucketsEnd = ht.bucketsEnd;
GenericHashEntry **bucket = nextBucket;
while (bucket != bucketsEnd) {
e = *bucket++;
if (e) {
backpointer = bucket-1;
break;
}
}
nextBucket = bucket;
}
entry = e;
return *this;
}
JS::GenericHashTable::GenericHashTable(uint32 nEntriesDefault):
nEntries(0)
{
DEBUG_ONLY(nReferences = 0);
uint lgNBuckets = ceilingLog2(nEntriesDefault);
if (lgNBuckets < minLgNBuckets)
lgNBuckets = minLgNBuckets;
defaultLgNBuckets = lgNBuckets;
recomputeMinMaxNEntries(lgNBuckets);
uint32 nBuckets = JS_BIT(lgNBuckets);
buckets = new GenericHashEntry*[nBuckets];
// No exceptions after this point unless buckets is deleted.
bucketsEnd = buckets + nBuckets;
zero(buckets, bucketsEnd);
}
// Initialize shift, minNEntries, and maxNEntries based on the lg2 of the
// number of buckets.
void JS::GenericHashTable::recomputeMinMaxNEntries(uint lgNBuckets)
{
uint32 nBuckets = JS_BIT(lgNBuckets);
shift = 32 - lgNBuckets;
maxNEntries = nBuckets; // Maximum ratio is 100%
minNEntries = lgNBuckets <= defaultLgNBuckets ? 0 : 3*(nBuckets>>3); // Minimum ratio is 37.5%
}
// Rehash the table. This method cannot throw out-of-memory exceptions, so it is
// safe to call from a destructor.
void JS::GenericHashTable::rehash()
{
uint32 newLgNBuckets = ceilingLog2(nEntries);
if (newLgNBuckets < defaultLgNBuckets)
newLgNBuckets = defaultLgNBuckets;
uint32 newNBuckets = JS_BIT(newLgNBuckets);
try {
GenericHashEntry **newBuckets = new GenericHashEntry*[newNBuckets];
// No exceptions after this point.
GenericHashEntry **newBucketsEnd = newBuckets + newNBuckets;
zero(newBuckets, newBucketsEnd);
recomputeMinMaxNEntries(newLgNBuckets);
GenericHashEntry **be = bucketsEnd;
for (GenericHashEntry **b = buckets; b != be; b++) {
GenericHashEntry *e = *b;
while (e) {
GenericHashEntry *next = e->next;
// Place e in the new set of buckets.
GenericHashEntry **nb = newBuckets + (e->keyHash*goldenRatio >> shift);
e->next = *nb;
*nb = e;
e = next;
}
}
delete[] buckets;
buckets = newBuckets;
bucketsEnd = newBucketsEnd;
} catch (std::bad_alloc) {
// Out of memory. Ignore the error and just relax the resizing boundaries.
if (buckets + JS_BIT(newLgNBuckets) > bucketsEnd)
maxNEntries >>= 1;
else
minNEntries <<= 1;
}
}

View File

@@ -1,373 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 1998 Netscape Communications Corporation. All
// Rights Reserved.
#ifndef hash_h
#define hash_h
#include "utilities.h"
namespace JavaScript {
//
// Hash Codes
//
typedef uint32 HashNumber;
HashNumber hashString(const char *s);
HashNumber hashString(const String &s);
template<class Key>
struct Hash {
HashNumber operator()(Key key) const;
};
template<class Key>
inline HashNumber Hash<Key>::operator()(Key key) const
{
return hashString(key);
}
const HashNumber goldenRatio = 0x9E3779B9U;
//
// Private
//
// Base class for user-defined hash entries.
// private
class GenericHashEntry {
public:
GenericHashEntry *next; // Link to next entry in the same bucket
const HashNumber keyHash; // This entry's hash value
protected:
explicit GenericHashEntry(HashNumber keyHash): next(0), keyHash(keyHash) {}
friend class GenericHashTable;
};
// private
class GenericHashTableIterator;
class GenericHashTable {
protected:
GenericHashEntry **buckets; // Vector of hash buckets
GenericHashEntry **bucketsEnd; // Pointer past end of vector of hash buckets
uint defaultLgNBuckets; // lg2 of minimum number of buckets for which to size the table
uint32 nEntries; // Number of entries in table
uint32 minNEntries; // Minimum number of entries without rehashing
uint32 maxNEntries; // Maximum number of entries without rehashing
uint32 shift; // 32 - lg2(number of buckets)
#ifdef DEBUG
public:
uint32 nReferences; // Number of iterators and references currently pointing to this hash table
#endif
public:
explicit GenericHashTable(uint32 nEntriesDefault);
~GenericHashTable() {
#ifndef _WIN32
ASSERT(nReferences == 0);
#endif
delete[] buckets;
}
void recomputeMinMaxNEntries(uint lgNBuckets);
void rehash();
void maybeGrow() {if (nEntries > maxNEntries) rehash();}
void maybeShrink() {if (nEntries < minNEntries) rehash();}
friend class GenericHashTableIterator;
typedef GenericHashTableIterator Iterator;
};
// This ought to be GenericHashTable::Iterator, but this doesn't work due to a
// Microsoft VC6 bug.
class GenericHashTableIterator {
protected:
GenericHashTable &ht; // Hash table being iterated
GenericHashEntry *entry; // Current entry; nil if done
GenericHashEntry **backpointer; // Pointer to pointer to current entry
GenericHashEntry **nextBucket; // Next bucket; pointer past end of vector of hash buckets if done
public:
explicit GenericHashTableIterator(GenericHashTable &ht);
~GenericHashTableIterator() {ht.maybeShrink(); DEBUG_ONLY(--ht.nReferences);}
operator bool() const {return entry != 0;} // Return true if there are entries left.
GenericHashTableIterator &operator++();
};
//
// Hash Tables
//
template<class Data, class Key, class H = Hash<Key> >
class HashTable: private GenericHashTable {
H hasher; // Hash function
struct Entry: public GenericHashEntry {
Data data;
Entry(HashNumber keyHash, Key key): GenericHashEntry(keyHash), data(key) {}
template<class Value>
Entry(HashNumber keyHash, Key key, Value value): GenericHashEntry(keyHash), data(key, value) {}
};
public:
class Reference {
#ifdef _WIN32 // Microsoft VC6 bug: friend declarations to inner classes don't work
public:
#endif
Entry *entry; // Current entry; nil if done
GenericHashEntry **backpointer; // Pointer to pointer to current entry
const HashNumber keyHash; // This entry's key's hash value
#ifdef DEBUG
GenericHashTable *ht; // Hash table to which this Reference points
#endif
public:
#ifndef _WIN32
Reference(HashTable &ht, Key key); // Search for an entry with the given key.
#else // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
Reference(HashTable &ht, Key key): keyHash(ht.hasher(key)) {
#ifdef DEBUG
Reference::ht = &ht;
++ht.nReferences;
#endif
HashNumber kh = keyHash;
HashNumber h = kh*goldenRatio >> ht.shift;
GenericHashEntry **bp = ht.buckets + h;
Entry *e;
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
bp = &e->next;
entry = e;
backpointer = bp;
}
#endif
private:
Reference(const Reference&); // No copy constructor
void operator=(const Reference&); // No assignment operator
public:
#if defined(DEBUG) && !defined(_WIN32)
~Reference() {if (ht) --ht->nReferences;}
#endif
operator bool() const {return entry != 0;} // Return true if an entry was found.
Data &operator*() const {ASSERT(entry); return entry->data;} // Return the data of the entry that was found.
friend class HashTable;
};
class Iterator: public GenericHashTableIterator {
public:
explicit Iterator(HashTable &ht): GenericHashTableIterator(ht) {}
private:
Iterator(const Iterator&); // No copy constructor
void operator=(const Iterator&); // No assignment operator
public:
// Go to next entry.
Iterator &operator++() {return *static_cast<Iterator*>(&GenericHashTableIterator::operator++());}
Data &operator*() const {ASSERT(entry); return static_cast<Entry *>(entry)->data;} // Return current entry's data.
void erase();
};
HashTable(uint32 nEntriesDefault = 0, const H &hasher = H()): GenericHashTable(nEntriesDefault), hasher(hasher) {}
~HashTable();
template<class Value> Data &insert(Reference &r, Key key, Value value);
Data &insert(Reference &r, Key key);
Data &insert(Key key);
void erase(Reference &r);
void erase(Key key);
Data *operator[](Key key);
friend class Reference;
friend class Iterator;
#ifndef _WIN32
template<class Value> Data &insert(Key key, Value value);
#else // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
template<class Value> Data &insert(Key key, Value value) {
Reference r(*this, key);
if (r)
return *r = value;
else
return insert(r, key, value);
}
#endif
};
//
// Implementation
//
template<class Data, class Key, class H>
HashTable<Data, Key, H>::~HashTable()
{
GenericHashEntry **be = bucketsEnd;
for (GenericHashEntry **b = buckets; b != be; b++) {
Entry *e = static_cast<Entry *>(*b);
while (e) {
Entry *next = static_cast<Entry *>(e->next);
delete e;
e = next;
}
}
}
#ifndef _WIN32
template<class Data, class Key, class H>
HashTable<Data, Key, H>::Reference::Reference(HashTable &ht, Key key):
keyHash(ht.hasher(key))
{
#ifdef DEBUG
Reference::ht = &ht;
++ht.nReferences;
#endif
HashNumber kh = keyHash;
HashNumber h = kh*goldenRatio >> ht.shift;
GenericHashEntry **bp = ht.buckets + h;
Entry *e;
while ((e = static_cast<Entry *>(*bp)) != 0 && !(e->keyHash == kh && e->data == key))
bp = &e->next;
entry = e;
backpointer = bp;
}
// Insert the given key/value pair into the hash table. Reference must
// be the result of an unsuccessful search for that key in the table.
// The reference is not valid after this method is called.
// Return a reference to the new entry's value.
template<class Data, class Key, class H> template<class Value>
inline Data &HashTable<Data, Key, H>::insert(Reference &r, Key key, Value value)
{
ASSERT(r.ht == this && !r.entry);
Entry *e = new Entry(r.keyHash, key, value);
*r.backpointer = e;
++nEntries;
maybeGrow();
#ifdef DEBUG
--r.ht->nReferences;
r.ht = 0;
#endif
return e->data;
}
#endif
// Same as above but without a Value argument.
template<class Data, class Key, class H>
inline Data &HashTable<Data, Key, H>::insert(Reference &r, Key key)
{
ASSERT(r.ht == this && !r.entry);
Entry *e = new Entry(r.keyHash, key);
*r.backpointer = e;
++nEntries;
maybeGrow();
#ifdef DEBUG
--r.ht->nReferences;
r.ht = 0;
#endif
return e->data;
}
// Insert the given key/value pair into the hash table. If an entry with a
// matching key already exists, replace that entry's value.
// Return a reference to the new entry's value.
#ifndef _WIN32 // Microsoft VC6 bug: VC6 doesn't allow this to be defined outside the class
template<class Data, class Key, class H> template<class Value>
Data &HashTable<Data, Key, H>::insert(Key key, Value value)
{
Reference r(*this, key);
if (r)
return *r = value;
else
return insert(r, key, value);
}
#endif
// Same as above but without a Value argument.
template<class Data, class Key, class H>
Data &HashTable<Data, Key, H>::insert(Key key)
{
Reference r(*this, key);
if (r)
return *r;
else
return insert(r, key);
}
// Reference r must point to an existing entry. Delete that entry.
// The reference is not valid after this method is called.
template<class Data, class Key, class H>
inline void HashTable<Data, Key, H>::erase(Reference &r)
{
Entry *e = r.entry;
ASSERT(r.ht == this && e);
*r.backpointer = e->next;
--nEntries;
delete e;
#ifdef DEBUG
--r.ht->nReferences;
r.ht = 0;
#endif
maybeShrink();
}
// Remove the hash table entry, if any, matching the given key.
template<class Data, class Key, class H>
void HashTable<Data, Key, H>::erase(Key key)
{
Reference r(*this, key);
if (r)
erase(r);
}
// Return a pointer to the value of the hash table entry matching the given key.
// Return nil if no entry matches.
template<class Data, class Key, class H>
Data *HashTable<Data, Key, H>::operator[](Key key)
{
Reference r(*this, key);
if (r)
return &*r;
else
return 0;
}
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,306 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef icodegenerator_h
#define icodegenerator_h
#include <vector>
#include <stack>
#include "utilities.h"
#include "parser.h"
#include "vmtypes.h"
#include "jsclasses.h"
namespace JavaScript {
namespace ICG {
using namespace VM;
using namespace JSTypes;
using namespace JSClasses;
typedef std::map<String, TypedRegister, std::less<String> > VariableList;
typedef std::map<uint32, uint32, std::less<uint32> > InstructionMap;
class ICodeModule {
public:
ICodeModule(InstructionStream *iCode, VariableList *variables,
uint32 maxRegister, uint32 maxParameter,
InstructionMap *instructionMap) :
its_iCode(iCode), itsVariables(variables),
itsParameterCount(maxParameter), itsMaxRegister(maxRegister),
mID(++sMaxID), mInstructionMap(instructionMap) { }
~ICodeModule()
{
delete its_iCode;
delete itsVariables;
delete mInstructionMap;
}
Formatter& print(Formatter& f);
void setFileName (String aFileName) { mFileName = aFileName; }
String getFileName () { return mFileName; }
InstructionStream *its_iCode;
VariableList *itsVariables;
uint32 itsParameterCount;
uint32 itsMaxRegister;
uint32 mID;
InstructionMap *mInstructionMap;
String mFileName;
static uint32 sMaxID;
};
typedef std::vector<const StringAtom *> LabelSet;
class LabelEntry {
public:
LabelEntry(LabelSet *labelSet, Label *breakLabel)
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(NULL) { }
LabelEntry(LabelSet *labelSet, Label *breakLabel, Label *continueLabel)
: labelSet(labelSet), breakLabel(breakLabel), continueLabel(continueLabel) { }
bool containsLabel(const StringAtom *label);
LabelSet *labelSet;
Label *breakLabel;
Label *continueLabel;
};
typedef std::vector<LabelEntry *> LabelStack;
Formatter& operator<<(Formatter &f, ICodeModule &i);
/****************************************************************/
// An ICodeGenerator provides the interface between the parser and the
// interpreter. The parser constructs one of these for each
// function/script, adds statements and expressions to it and then
// converts it into an ICodeModule, ready for execution.
class ICodeGenerator {
public:
typedef enum { kNoFlags = 0, kIsTopLevel = 0x01, kIsStaticMethod = 0x02, kIsWithinWith = 0x04 } ICodeGeneratorFlags;
private:
InstructionStream *iCode;
bool iCodeOwner;
LabelList labels;
Register mTopRegister; // highest (currently) alloacated register
uint32 mParameterCount; // number of parameters declared for the function
// these must come before any variables declared.
TypedRegister mExceptionRegister; // reserved to carry the exception object.
VariableList *variableList; // name|register pair for each variable
World *mWorld; // used to register strings
JSScope *mGlobal; // the scope for compiling within
LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct
// maps source position to instruction index
InstructionMap *mInstructionMap;
JSClass *mClass; // enclosing class when generating code for methods
ICodeGeneratorFlags mFlags; // assorted flags
std::vector<bool> mPermanentRegister;
Register getTempRegister()
{
while (mTopRegister < mPermanentRegister.size())
if (!mPermanentRegister[mTopRegister])
return mTopRegister++;
else
++mTopRegister;
mPermanentRegister.resize(mTopRegister + 1);
mPermanentRegister[mTopRegister] = false;
return mTopRegister++;
}
void resetTopRegister() { mTopRegister = mParameterCount; }
void resetStatement() { resetTopRegister(); }
TypedRegister allocateRegister(const StringAtom& name, JSType *type);
void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; }
JSType *findType(const StringAtom& typeName);
void setLabel(Label *label);
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
void rts() { iCode->push_back(new Rts()); }
void branch(Label *label);
GenericBranch *branchTrue(Label *label, TypedRegister condition);
GenericBranch *branchFalse(Label *label, TypedRegister condition);
void beginTry(Label *catchLabel, Label *finallyLabel)
{ iCode->push_back(new Tryin(catchLabel, finallyLabel)); }
void endTry() { iCode->push_back(new Tryout()); }
void beginWith(TypedRegister obj) { iCode->push_back(new Within(obj)); }
void endWith() { iCode->push_back(new Without()); }
void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; }
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
bool isTopLevel() { return (mFlags & kIsTopLevel) != 0; }
bool isWithinWith() { return (mFlags & kIsWithinWith) != 0; }
bool isStaticMethod() { return (mFlags & kIsStaticMethod) != 0; }
void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); }
typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind;
LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex);
TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args);
ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass);
public:
ICodeGenerator(World *world, JSScope *global, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel);
~ICodeGenerator()
{
if (iCodeOwner) {
delete iCode;
delete mInstructionMap;
}
}
ICodeModule *complete();
TypedRegister genExpr(ExprNode *p,
bool needBoolValueInBranch = false,
Label *trueBranch = NULL,
Label *falseBranch = NULL);
TypedRegister genStmt(StmtNode *p, LabelSet *currentLabelSet = NULL);
void returnStmt(TypedRegister r);
void returnStmt();
void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); }
void debuggerStmt() { iCode->push_back(new Debugger()); }
TypedRegister allocateVariable(const StringAtom& name);
TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName);
TypedRegister findVariable(const StringAtom& name)
{
VariableList::iterator i = variableList->find(name);
return (i == variableList->end()) ? TypedRegister(NotARegister, &None_Type) : (*i).second;
}
TypedRegister allocateParameter(const StringAtom& name) { mParameterCount++; return allocateRegister(name, &Any_Type); }
TypedRegister allocateParameter(const StringAtom& name, const StringAtom& typeName)
{ mParameterCount++; return allocateRegister(name, findType(typeName)); }
TypedRegister allocateParameter(const StringAtom& name, JSType *type)
{ mParameterCount++; return allocateRegister(name, type); }
Formatter& print(Formatter& f);
TypedRegister op(ICodeOp op, TypedRegister source);
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister call(TypedRegister base, TypedRegister target, RegisterList *args);
TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex);
void move(TypedRegister destination, TypedRegister source);
TypedRegister logicalNot(TypedRegister source);
TypedRegister test(TypedRegister source);
TypedRegister loadBoolean(bool value);
TypedRegister loadImmediate(double value);
TypedRegister loadString(const String &value);
TypedRegister loadString(const StringAtom &name);
TypedRegister newObject(TypedRegister constructor);
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister newClass(JSClass *clazz);
TypedRegister cast(TypedRegister arg, JSType *toType);
TypedRegister super();
TypedRegister loadName(const StringAtom &name, JSType *t = &Any_Type);
void saveName(const StringAtom &name, TypedRegister value);
TypedRegister nameXcr(const StringAtom &name, ICodeOp op);
TypedRegister deleteProperty(TypedRegister base, const StringAtom &name);
TypedRegister getProperty(TypedRegister base, const StringAtom &name);
void setProperty(TypedRegister base, const StringAtom &name, TypedRegister value);
TypedRegister propertyXcr(TypedRegister base, const StringAtom &name, ICodeOp op);
TypedRegister getStatic(JSClass *base, const String &name);
void setStatic(JSClass *base, const StringAtom &name, TypedRegister value);
TypedRegister staticXcr(JSClass *base, const StringAtom &name, ICodeOp op);
TypedRegister getElement(TypedRegister base, TypedRegister index);
void setElement(TypedRegister base, TypedRegister index, TypedRegister value);
TypedRegister elementXcr(TypedRegister base, TypedRegister index, ICodeOp op);
TypedRegister getSlot(TypedRegister base, uint32 slot);
void setSlot(TypedRegister base, uint32 slot, TypedRegister value);
TypedRegister slotXcr(TypedRegister base, uint32 slot, ICodeOp op);
TypedRegister varXcr(TypedRegister var, ICodeOp op);
InstructionStream *getICode() { return iCode; }
Label *getLabel();
};
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
Formatter& operator<<(Formatter &f, ICodeModule &i);
/*
std::ostream &operator<<(std::ostream &s, ICodeGenerator &i);
std::ostream &operator<<(std::ostream &s, StringAtom &str);
*/
} /* namespace IGC */
} /* namespace JavaScript */
#endif /* icodegenerator_h */

File diff suppressed because it is too large Load Diff

View File

@@ -1,113 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 2000 Netscape Communications Corporation. All
// Rights Reserved.
#ifndef interpreter_h
#define interpreter_h
#include "utilities.h"
#include "jstypes.h"
#include "vmtypes.h"
#include "icodegenerator.h"
#include "gc_allocator.h"
namespace JavaScript {
namespace Interpreter {
using namespace ICG;
using namespace JSTypes;
struct Activation;
struct Linkage;
class Context : public gc_base {
void initContext();
public:
explicit Context(World& world, JSScope* aGlobal)
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); }
World& getWorld() { return mWorld; }
JSScope* getGlobalObject() { return mGlobal; }
InstructionIterator getPC() { return mPC; }
JSValues& getRegisters();
ICodeModule* getICode();
enum Event {
EV_NONE = 0x0000,
EV_STEP = 0x0001,
EV_THROW = 0x0002,
EV_DEBUG = 0x0004,
EV_ALL = 0xffff
};
class Listener {
public:
virtual void listen(Context *context, Event event) = 0;
};
void addListener(Listener* listener);
void removeListener(Listener* listener);
class Frame {
public:
virtual Frame* getNext() = 0;
virtual void getState(InstructionIterator& pc, JSValues*& registers,
ICodeModule*& iCode) = 0;
};
Frame* getFrames();
JSValue interpret(ICodeModule* iCode, const JSValues& args);
void doCall(JSFunction *target, Instruction *pc);
ICodeModule* compile(const String &source);
ICodeModule* genCode(StmtNode *p, const String &fileName);
JSValue readEvalFile(FILE* in, const String& fileName);
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);
bool hasOperatorsPackageLoaded() { return mHasOperatorsPackageLoaded; }
private:
void broadcast(Event event);
void initOperatorsPackage();
private:
World& mWorld;
JSScope* mGlobal;
Linkage* mLinkage;
typedef std::vector<Listener*, gc_allocator<Listener*> > ListenerList;
typedef ListenerList::iterator ListenerIterator;
ListenerList mListeners;
Activation* mActivation;
bool mHasOperatorsPackageLoaded;
InstructionIterator mPC;
BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount];
}; /* class Context */
} /* namespace Interpreter */
} /* namespace JavaScript */
#endif /* interpreter_h */

View File

@@ -1,33 +0,0 @@
class ArithmeticNode extends BinaryNode {
ArithmeticNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
{
super(aOp, aLeft, aRight);
}
JSValue eval(Environment theEnv)
{
JSValue lV = left.eval(theEnv);
JSValue rV = right.eval(theEnv);
if (op == "+")
return lV.add(theEnv, rV);
else
if (op == "-")
return lV.subtract(theEnv, rV);
else
if (op == "*")
return lV.multiply(theEnv, rV);
else
if (op == "/")
return lV.divide(theEnv, rV);
else
if (op == "%")
return lV.remainder(theEnv, rV);
else {
System.out.println("missing arithmetic op " + op);
return null;
}
}
}

View File

@@ -1,16 +0,0 @@
class AssignmentNode extends BinaryNode {
AssignmentNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
{
super(aOp, aLeft, aRight);
}
JSValue eval(Environment theEnv)
{
JSReference lV = left.evalLHS(theEnv);
JSValue rV = right.eval(theEnv);
return lV.base.putProp(theEnv, lV.id, rV);
}
}

View File

@@ -1,72 +0,0 @@
class BinaryNode extends ExpressionNode {
BinaryNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
{
left = aLeft;
right = aRight;
op = aOp;
}
JSReference evalLHS(Environment theEnv)
{
if (op == ".") {
JSValue lV = left.eval(theEnv);
JSString id;
if (right instanceof JSIdentifier)
id = (JSString)right;
else
id = right.eval(theEnv).toJSString(theEnv);
return new JSReference(lV, id);
}
else
throw new RuntimeException("bad lValue operator " + op);
}
JSValue eval(Environment theEnv)
{
JSValue lV = left.eval(theEnv);
JSValue rV = right.eval(theEnv);
if (op == ".")
return lV.getProp(theEnv, rV.toJSString(theEnv));
else
if (op == "()")
return lV.call(theEnv, rV);
else
if (op == ",")
return JSValueList.buildList(lV, rV);
else {
System.out.println("missing binary op " + op);
return null;
}
}
String print(String indent)
{
StringBuffer result = new StringBuffer(indent);
result.append(getClass().toString());
result.append(" ");
result.append(op);
result.append("\n");
indent += " ";
if (left == null) {
result.append(indent);
result.append("null\n");
}
else
result.append(left.print(indent));
if (right == null) {
result.append(indent);
result.append("null\n");
}
else
result.append(right.print(indent));
return result.toString();
}
protected ExpressionNode left;
protected ExpressionNode right;
protected String op;
}

View File

@@ -1,36 +0,0 @@
class BitwiseNode extends BinaryNode {
BitwiseNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
{
super(aOp, aLeft, aRight);
}
JSValue eval(Environment theEnv)
{
JSInteger lV = left.eval(theEnv).toJSInteger(theEnv);
JSValue rV = right.eval(theEnv);
if (op == "&")
return lV.and(theEnv, rV);
else
if (op == "|")
return lV.or(theEnv, rV);
else
if (op == "^")
return lV.xor(theEnv, rV);
else
if (op == "<<")
return lV.shr(theEnv, rV);
else
if (op == ">>")
return lV.shl(theEnv, rV);
else
if (op == ">>>")
return lV.ushl(theEnv, rV);
else {
System.out.println("missing bitwise op " + op);
return null;
}
}
}

View File

@@ -1,24 +0,0 @@
import java.io.*;
class Brenda {
public static void main(String[] args) {
try {
JSLexer lexer = new JSLexer((args != null) ? new DataInputStream(new FileInputStream(args[0])) : new DataInputStream(System.in));
JSParser parser = new JSParser(lexer);
ControlNodeGroup tree = new ControlNodeGroup();
parser.statements(0, tree);
System.out.println(ControlNode.printAll());
Environment theEnv = new Environment();
ControlNode c = tree.getHead();
while (c != null) c = c.eval(theEnv);
System.out.println("After eval :\n" + theEnv.print());
} catch(Exception e) {
System.err.println("exception: "+e);
}
}
}

View File

@@ -1,59 +0,0 @@
class ConditionalNode extends ControlNode {
ConditionalNode(ExpressionNode aCondition)
{
super(aCondition);
}
ConditionalNode(ExpressionNode aCondition, ControlNode aTrueCode)
{
super(aCondition);
trueCode = aTrueCode;
}
ConditionalNode(ExpressionNode aCondition, ControlNode aTrueCode, ControlNode aFalseCode)
{
super(aCondition);
trueCode = aTrueCode;
setNext(aFalseCode);
}
void moveNextToTrue()
{
trueCode = next;
setNext(null);
}
ControlNode eval(Environment theEnv)
{
JSBoolean b = expr.eval(theEnv).toJSBoolean(theEnv);
if (b.isTrue())
return trueCode;
else
return next;
}
String print()
{
StringBuffer result = new StringBuffer("ConditionalNode ");
result.append(index);
result.append("\nexpr:\n");
if (expr == null)
result.append("expr = null\n");
else
result.append(expr.print(""));
result.append("true branch:\n");
if (trueCode == null)
result.append("true branch = null\n");
else
result.append("true branch->" + trueCode.index + "\n");
result.append("false branch:\n");
if (next == null)
result.append("false branch = null\n");
else
result.append("false branch->" + next.index + "\n");
return result.toString();
}
protected ControlNode trueCode;
}

View File

@@ -1,67 +0,0 @@
import java.util.Vector;
class ControlNode {
private static Vector gList = new Vector();
static String printAll()
{
StringBuffer result = new StringBuffer();
for (int i = 0; i < gList.size(); i++) {
result.append(((ControlNode)(gList.elementAt(i))).print());
}
return result.toString();
}
ControlNode(ExpressionNode anExpr)
{
expr = anExpr;
index = gList.size();
gList.addElement(this);
}
ExpressionNode getExpression()
{
return expr;
}
void setNext(ControlNode aNext)
{
next = aNext;
}
ControlNode eval(Environment theEnv)
{
if (expr != null) theEnv.resultValue = expr.eval(theEnv);
return next;
}
String print()
{
StringBuffer result = new StringBuffer(getClass().toString().substring(6));
result.append(" #");
result.append(index);
result.append("\nexpr: \n");
if (expr == null)
result.append("expr = null\n");
else
result.append(expr.print(""));
result.append("next: ");
if (next == null)
result.append("next = null\n");
else
result.append("next->" + next.index + "\n");
return result.toString();
}
protected ExpressionNode expr;
protected ControlNode next;
protected int index;
}

View File

@@ -1,153 +0,0 @@
import java.util.Vector;
class ControlNodeGroup {
ControlNodeGroup()
{
}
ControlNodeGroup(ControlNode aHead)
{
head = aHead;
}
void add(ControlNodeGroup aGroup)
{
if (head == null) {
head = aGroup.head;
}
else {
fixTails(aGroup.getHead());
}
addTails(aGroup);
}
void add(ControlNode aNode)
{
fixTails(aNode);
addTail(aNode);
if (head == null) head = aNode;
}
void addBreak(ControlNode aNode)
{
fixTails(aNode);
addBreakTail(aNode);
if (head == null) head = aNode;
}
void addContinue(ControlNode aNode)
{
fixTails(aNode);
addContinueTail(aNode);
if (head == null) head = aNode;
}
void fixTails(ControlNode butt)
{
int count = tails.size();
for (int i = 0; i < count; i++)
{
ControlNode aNode = (ControlNode)(tails.elementAt(i));
aNode.setNext(butt);
}
tails.removeAllElements();
}
void fixContinues(ControlNode butt, String label)
{
int count = continueTails.size();
int i = 0;
while (i < count) {
ControlNode c = (ControlNode)(continueTails.elementAt(i));
ExpressionNode e = c.getExpression();
String tgt = (e == null) ? null : ((JSIdentifier)e).s;
if ((tgt == null) || tgt.equals(label)) {
c.setNext(butt);
continueTails.removeElementAt(i);
count--;
}
else
i++;
}
}
void setHead(ControlNode aHead)
{
head = aHead;
}
ControlNode getHead()
{
return head;
}
void addTail(ControlNode aTail)
{
tails.addElement(aTail);
}
void addBreakTail(ControlNode aTail)
{
breakTails.addElement(aTail);
}
void addContinueTail(ControlNode aTail)
{
continueTails.addElement(aTail);
}
void removeTail(ControlNode aTail)
{
tails.removeElement(aTail);
}
void addTails(ControlNodeGroup aGroup)
{
int count = aGroup.tails.size();
for (int i = 0; i < count; i++)
{
tails.addElement(aGroup.tails.elementAt(i));
}
aGroup.tails.removeAllElements();
count = aGroup.breakTails.size();
for (int i = 0; i < count; i++)
{
breakTails.addElement(aGroup.breakTails.elementAt(i));
}
aGroup.breakTails.removeAllElements();
count = aGroup.continueTails.size();
for (int i = 0; i < count; i++)
{
continueTails.addElement(aGroup.continueTails.elementAt(i));
}
aGroup.continueTails.removeAllElements();
}
void shiftBreakTails(String label)
{
int count = breakTails.size();
int i = 0;
while (i < count) {
ControlNode c = (ControlNode)(breakTails.elementAt(i));
ExpressionNode e = c.getExpression();
String tgt = (e == null) ? null : ((JSIdentifier)e).s;
if ((tgt == null) || tgt.equals(label)) {
tails.addElement(c);
breakTails.removeElementAt(i);
count--;
}
else
i++;
}
}
ControlNode head;
Vector tails = new Vector();
Vector breakTails = new Vector();
Vector continueTails = new Vector();
}

View File

@@ -1,30 +0,0 @@
import java.util.Hashtable;
class Environment {
JSScope scope = new JSScope("globals");
JSScope globalScope = scope;
void enterNewScope(JSScope newScope)
{
newScope.parent = scope;
scope = newScope;
}
void leaveScope()
{
scope = scope.parent;
}
String print()
{
StringBuffer result = new StringBuffer("Globals contents :\n");
result.append(scope.toString());
return result.toString();
}
JSValue resultValue;
}

View File

@@ -1,24 +0,0 @@
class ExpressionNode {
ExpressionNode()
{
}
String print(String indent)
{
return indent + "ExpressionNode(" + getClass().toString() + ")\n";
}
JSReference evalLHS(Environment theEnv)
{
System.out.println("Unimplemented evalLHS for " + print(""));
return null;
}
JSValue eval(Environment theEnv)
{
System.out.println("Unimplemented eval for " + print(""));
return null;
}
}

View File

@@ -1,36 +0,0 @@
class FunctionNode extends ExpressionNode {
FunctionNode(JSIdentifier aName, ControlNodeGroup aBody, ExpressionNode parameterList)
{
fn = new NativeFunction(aBody.getHead());
name = aName;
if (parameterList != null) {
if (parameterList instanceof BinaryNode)
buildParameterVector((BinaryNode)parameterList);
else
fn.parameters.addElement(parameterList);
}
}
void buildParameterVector(BinaryNode x)
{
if (x.left instanceof BinaryNode) {
buildParameterVector((BinaryNode)(x.left));
fn.parameters.addElement(x.right);
}
else {
fn.parameters.addElement(x.left);
fn.parameters.addElement(x.right);
}
}
JSValue eval(Environment theEnv)
{
theEnv.scope.putProp(theEnv, name, fn);
return fn;
}
JSString name;
NativeFunction fn;
}

View File

@@ -1,52 +0,0 @@
class JSBoolean extends JSValue {
static JSBoolean JSTrue = new JSBoolean(true);
static JSBoolean JSFalse = new JSBoolean(false);
private JSBoolean(boolean p)
{
b = p;
}
JSValue eval(Environment theEnv)
{
return this;
}
boolean isTrue()
{
return b;
}
boolean isFalse()
{
return !b;
}
JSValue bang(Environment theEnv) {
return (b) ? JSFalse : JSTrue;
}
JSValue typeof(Environment theEnv) {
return new JSString("boolean");
}
JSBoolean toJSBoolean(Environment theEnv) {
return this;
}
JSValue toPrimitive(Environment theEnv, String hint) {
return this;
}
JSString toJSString(Environment theEnv) {
return (b) ? new JSString("true") : new JSString("false");
}
JSDouble toJSDouble(Environment theEnv) {
return (b) ? new JSDouble(1) : new JSDouble(0);
}
boolean b;
}

View File

@@ -1,111 +0,0 @@
class JSDouble extends JSNumber {
JSDouble(double p)
{
d = p;
}
JSDouble(String s)
{
d = new Double(s).doubleValue();
}
String print(String indent)
{
return indent + "JSDouble " + d + "\n";
}
public String toString()
{
return Double.toString(d);
}
JSValue eval(Environment theEnv)
{
return this;
}
JSValue plus(Environment theEnv) {
return this;
}
JSValue minus(Environment theEnv) {
return new JSDouble(-d);
}
JSValue add(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return toJSString(theEnv).add(theEnv, rV);
else
return new JSDouble(d + rV.toJSDouble(theEnv).d);
}
JSValue subtract(Environment theEnv, JSValue rV) {
return new JSDouble(d - rV.toJSDouble(theEnv).d);
}
JSValue multiply(Environment theEnv, JSValue rV) {
return new JSDouble(d * rV.toJSDouble(theEnv).d);
}
JSValue divide(Environment theEnv, JSValue rV) {
return new JSDouble(d / rV.toJSDouble(theEnv).d);
}
JSValue remainder(Environment theEnv, JSValue rV) {
return new JSDouble(d % rV.toJSDouble(theEnv).d);
}
JSValue gt(Environment theEnv, JSValue rV) {
return (d > rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSValue ge(Environment theEnv, JSValue rV) {
return (d >= rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSValue lt(Environment theEnv, JSValue rV) {
return (d < rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSValue le(Environment theEnv, JSValue rV) {
return (d <= rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSValue eq(Environment theEnv, JSValue rV) {
return (d == rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSValue ne(Environment theEnv, JSValue rV) {
return (d != rV.toJSDouble(theEnv).d) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSDouble toJSDouble(Environment theEnv) {
return this;
}
JSValue toPrimitive(Environment theEnv, String hint) {
return this;
}
JSInteger toJSInteger(Environment theEnv) {
return new JSInteger((int)d);
}
JSBoolean toJSBoolean(Environment theEnv) {
return ((d == d) && (d != 0.0)) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSString toJSString(Environment theEnv) {
return new JSString(Double.toString(d));
}
JSObject toJSObject(Environment theEnv) {
return new NativeNumber(d);
}
double d;
}

View File

@@ -1,22 +0,0 @@
class JSException extends RuntimeException {
JSException(JSValue x)
{
value = x;
}
JSValue getValue()
{
return value;
}
public String toString()
{
return value.toJSString(null).s;
}
JSValue value;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
class JSIdentifier extends JSString {
JSIdentifier(String s)
{
super(s);
}
String print(String indent)
{
return indent + "JSIdentifier : " + s + "\n";
}
JSValue eval(Environment theEnv)
{
return theEnv.scope.getProp(theEnv, this);
}
JSReference evalLHS(Environment theEnv)
{
return new JSReference(theEnv.scope, this);
}
}

View File

@@ -1,68 +0,0 @@
class JSInteger extends JSNumber {
JSInteger(String s)
{
i = new Integer(s).intValue();
}
JSInteger(int p)
{
i = p;
}
JSValue eval(Environment theEnv)
{
return this;
}
JSBoolean toJSBoolean(Environment theEnv) {
return (i != 0) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
}
JSDouble toJSDouble(Environment theEnv) {
return new JSDouble(i);
}
JSInteger toJSInteger(Environment theEnv) {
return this;
}
JSValue toPrimitive(Environment theEnv, String hint) {
return this;
}
JSString toJSString(Environment theEnv) {
return new JSString(Integer.toString(i));
}
JSValue twiddle(Environment theEnv) {
return new JSInteger(~i);
}
JSValue and(Environment theEnv, JSValue rV) {
return new JSInteger(i & rV.toJSInteger(theEnv).i);
}
JSValue or(Environment theEnv, JSValue rV) {
return new JSInteger(i | rV.toJSInteger(theEnv).i);
}
JSValue xor(Environment theEnv, JSValue rV) {
return new JSInteger(i ^ rV.toJSInteger(theEnv).i);
}
JSValue shl(Environment theEnv, JSValue rV) {
return new JSInteger(i >> rV.toJSInteger(theEnv).i);
}
JSValue shr(Environment theEnv, JSValue rV) {
return new JSInteger(i << rV.toJSInteger(theEnv).i);
}
JSValue ushl(Environment theEnv, JSValue rV) {
return new JSInteger(i >>> rV.toJSInteger(theEnv).i);
}
int i;
}

View File

@@ -1,41 +0,0 @@
class JSName extends ExpressionNode {
JSName(JSIdentifier anID, int aScope)
{
id = anID;
scope = aScope; // this is the scope that the name was used in
}
String print(String indent)
{
return indent + "JSName : " + id.s + ", scope : " + scope + "\n";
}
JSReference evalLHS(Environment theEnv)
{
JSScope scope = theEnv.scope;
while (scope != null) {
if (scope.hasProp(theEnv, id))
return new JSReference(scope, id);
else
scope = scope.parent;
}
return new JSReference(theEnv.globalScope, id);
}
JSValue eval(Environment theEnv)
{
JSScope scope = theEnv.scope;
while (scope != null) {
if (scope.hasProp(theEnv, id))
return scope.getProp(theEnv, id);
else
scope = scope.parent;
}
throw new JSException(new JSString(id.s + " undefined"));
}
JSIdentifier id;
int scope;
}

View File

@@ -1,8 +0,0 @@
abstract class JSNumber extends JSValue {
JSValue typeof(Environment theEnv) {
return new JSString("number");
}
}

View File

@@ -1,84 +0,0 @@
import java.util.Hashtable;
class JSObject extends JSValue {
static JSObject objectPrototype = new JSObject("Object");
static JSObject JSUndefined = new JSObject("undefined");
JSObject(String aClass)
{
oClass = aClass;
prototype = objectPrototype;
}
void setPrototype(JSObject aPrototype)
{
prototype = aPrototype;
}
String print(String indent)
{
return indent + "JSObject : " + oClass + "\n";
}
public String toString() {
return oClass + contents.toString();
}
JSValue eval(Environment theEnv)
{
return this;
}
JSValue typeof(Environment theEnv) {
if (this == JSUndefined)
return new JSString("undefined");
else
return new JSString("object");
}
JSBoolean toJSBoolean(Environment theEnv) {
return JSBoolean.JSTrue;
}
JSDouble toJSDouble(Environment theEnv) {
return toPrimitive(theEnv, "Number").toJSDouble(theEnv);
}
JSValue getProp(Environment theEnv, JSString id)
{
Object v = contents.get(id.s);
if (v == null)
if (prototype == null)
return JSUndefined;
else
return prototype.getProp(theEnv, id);
else
return (JSValue)v;
}
boolean hasProp(Environment theEnv, JSString id)
{
Object v = contents.get(id.s);
if (v == null)
if (prototype == null)
return false;
else
return prototype.hasProp(theEnv, id);
else
return true;
}
JSValue putProp(Environment theEnv, JSString id, JSValue rV) {
contents.put(id.s, rV);
return rV;
}
Hashtable contents = new Hashtable();
String oClass;
JSObject prototype;
}

View File

@@ -1,12 +0,0 @@
class JSReference {
JSReference(JSValue aBase, JSString aID)
{
base = aBase;
id = aID;
}
JSValue base;
JSString id;
}

View File

@@ -1,10 +0,0 @@
class JSScope extends JSObject {
JSScope(String s)
{
super(s);
}
JSScope parent;
}

View File

@@ -1,83 +0,0 @@
class JSString extends JSValue {
JSString(String p)
{
s = p;
}
JSValue eval(Environment theEnv)
{
return this;
}
JSValue typeof(Environment theEnv) {
return new JSString("string");
}
JSValue add(Environment theEnv, JSValue rV)
{
return new JSString(s + rV.toJSString(theEnv).s);
}
JSValue gt(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return (s.compareTo(rV.toJSString(theEnv).s) == 1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
else
return toJSDouble(theEnv).gt(theEnv, rV);
}
JSValue ge(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return (s.compareTo(rV.toJSString(theEnv).s) != -1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
else
return toJSDouble(theEnv).ge(theEnv, rV);
}
JSValue lt(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return (s.compareTo(rV.toJSString(theEnv).s) == -1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
else
return toJSDouble(theEnv).lt(theEnv, rV);
}
JSValue le(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return (s.compareTo(rV.toJSString(theEnv).s) != 1) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
else
return toJSDouble(theEnv).le(theEnv, rV);
}
JSValue eq(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return (s.compareTo(rV.toJSString(theEnv).s) == 0) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
else
return toJSDouble(theEnv).eq(theEnv, rV);
}
JSValue ne(Environment theEnv, JSValue rV) {
if (rV instanceof JSString)
return (s.compareTo(rV.toJSString(theEnv).s) != 0) ? JSBoolean.JSTrue : JSBoolean.JSFalse;
else
return toJSDouble(theEnv).ne(theEnv, rV);
}
JSDouble toJSDouble(Environment theEnv) {
return new JSDouble(s); // XXX Way More To Do, see Rhino ScriptRuntime.java
}
JSString toJSString(Environment theEnv) {
return this;
}
JSValue toPrimitive(Environment theEnv, String hint) {
return this;
}
String print(String indent)
{
return indent + "JSString : " + s + "\n";
}
protected String s;
}

View File

@@ -1,222 +0,0 @@
class JSValue extends ExpressionNode {
String print(String indent)
{
return indent + "JSValue\n";
}
JSReference evalLHS(Environment theEnv)
{
throw new RuntimeException("EvalLHS on non-lvalue");
}
JSValue eval(Environment theEnv)
{
throw new RuntimeException("Eval on JSValue");
}
JSValue unimplemented(String op)
{
throw new RuntimeException("unimplemented " + op + " called");
}
JSValue gt(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "Number");
rV = rV.toPrimitive(theEnv, "Number");
if ((lV instanceof JSString) && (rV instanceof JSString))
return lV.gt(theEnv, rV);
else
return lV.toJSDouble(theEnv).gt(theEnv, rV.toJSDouble(theEnv));
}
JSValue ge(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "Number");
rV = rV.toPrimitive(theEnv, "Number");
if ((lV instanceof JSString) && (rV instanceof JSString))
return lV.ge(theEnv, rV);
else
return lV.toJSDouble(theEnv).ge(theEnv, rV.toJSDouble(theEnv));
}
JSValue lt(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "Number");
rV = rV.toPrimitive(theEnv, "Number");
if ((lV instanceof JSString) && (rV instanceof JSString))
return lV.lt(theEnv, rV);
else
return lV.toJSDouble(theEnv).lt(theEnv, rV.toJSDouble(theEnv));
}
JSValue le(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "Number");
rV = rV.toPrimitive(theEnv, "Number");
if ((lV instanceof JSString) && (rV instanceof JSString))
return lV.le(theEnv, rV);
else
return lV.toJSDouble(theEnv).le(theEnv, rV.toJSDouble(theEnv));
}
JSValue eq(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "Number");
rV = rV.toPrimitive(theEnv, "Number");
if ((lV instanceof JSString) && (rV instanceof JSString))
return lV.eq(theEnv, rV);
else
return lV.toJSDouble(theEnv).eq(theEnv, rV.toJSDouble(theEnv));
}
JSValue ne(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "Number");
rV = rV.toPrimitive(theEnv, "Number");
if ((lV instanceof JSString) && (rV instanceof JSString))
return lV.ne(theEnv, rV);
else
return lV.toJSDouble(theEnv).ne(theEnv, rV.toJSDouble(theEnv));
}
JSValue plus(Environment theEnv) {
return toJSDouble(theEnv).plus(theEnv);
}
JSValue minus(Environment theEnv) {
return toJSDouble(theEnv).minus(theEnv);
}
JSValue twiddle(Environment theEnv) {
return toJSInteger(theEnv).twiddle(theEnv);
}
JSValue bang(Environment theEnv) {
return toJSBoolean(theEnv).bang(theEnv);
}
JSValue typeof(Environment theEnv) {
return unimplemented("typeof");
}
JSValue add(Environment theEnv, JSValue rV) {
JSValue lV = toPrimitive(theEnv, "");
rV = rV.toPrimitive(theEnv, "");
if ((lV instanceof JSString) || (rV instanceof JSString))
return lV.add(theEnv, rV);
else
return lV.toJSDouble(theEnv).add(theEnv, rV);
}
JSValue subtract(Environment theEnv, JSValue rV) {
return toJSDouble(theEnv).subtract(theEnv, rV.toJSDouble(theEnv));
}
JSValue multiply(Environment theEnv, JSValue rV) {
return toJSDouble(theEnv).multiply(theEnv, rV.toJSDouble(theEnv));
}
JSValue divide(Environment theEnv, JSValue rV) {
return toJSDouble(theEnv).divide(theEnv, rV.toJSDouble(theEnv));
}
JSValue remainder(Environment theEnv, JSValue rV) {
return toJSDouble(theEnv).remainder(theEnv, rV.toJSDouble(theEnv));
}
JSValue and(Environment theEnv, JSValue rV) {
return toJSInteger(theEnv).and(theEnv, rV.toJSInteger(theEnv));
}
JSValue or(Environment theEnv, JSValue rV) {
return toJSInteger(theEnv).or(theEnv, rV.toJSInteger(theEnv));
}
JSValue xor(Environment theEnv, JSValue rV) {
return toJSInteger(theEnv).xor(theEnv, rV.toJSInteger(theEnv));
}
JSValue shl(Environment theEnv, JSValue rV) {
return toJSInteger(theEnv).shl(theEnv, rV.toJSInteger(theEnv));
}
JSValue shr(Environment theEnv, JSValue rV) {
return toJSInteger(theEnv).shr(theEnv, rV.toJSInteger(theEnv));
}
JSValue ushl(Environment theEnv, JSValue rV) {
return toJSInteger(theEnv).ushl(theEnv, rV.toJSInteger(theEnv));
}
JSValue getProp(Environment theEnv, JSString id) {
return toJSObject(theEnv).getProp(theEnv, id);
}
boolean hasProp(Environment theEnv, JSString id) {
return toJSObject(theEnv).hasProp(theEnv, id);
}
JSValue putProp(Environment theEnv, JSString id, JSValue rV) {
return toJSObject(theEnv).putProp(theEnv, id, rV);
}
JSValue call(Environment theEnv, JSValue rV) {
throw new JSException(new JSString("[[call]] not implemented"));
}
JSValue defaultValue(Environment theEnv, String hint) {
/*
When the [[DefaultValue]] method of O is called with hint String, the following steps are taken:
1. Call the [[Get]] method of object O with argument "toString".
2. If Result(1) is not an object, go to step 5.
3. Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
4. If Result(3) is a primitive value, return Result(3).
5. Call the [[Get]] method of object O with argument "valueOf".
6. If Result(5) is not an object, go to step 9.
7. Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
8. If Result(7) is a primitive value, return Result(7).
9. Generate a runtime error.
*/
JSValue v = null;
if (hint.equals("String")) {
v = getProp(theEnv, new JSString("toString"));
if (v instanceof JSObject) {
// invoke 'v.Call' with 'this' as the JS this
}
else {
v = getProp(theEnv, new JSString("valueOf"));
if (v instanceof JSObject) {
}
else
throw new JSException(new JSString("No default value"));
}
}
else { // hint.equals("Number")
/*
When the [[DefaultValue]] method of O is called with hint Number, the following steps are taken:
1. Call the [[Get]] method of object O with argument "valueOf".
2. If Result(1) is not an object, go to step 5.
3. Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
4. If Result(3) is a primitive value, return Result(3).
5. Call the [[Get]] method of object O with argument "toString".
6. If Result(5) is not an object, go to step 9.
7. Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
8. If Result(7) is a primitive value, return Result(7).
9. Generate a runtime error.
*/
}
return null;
}
JSValue toPrimitive(Environment theEnv, String hint) {
JSValue result = defaultValue(theEnv, hint);
if (result instanceof JSObject)
throw new JSException(new JSString("default value returned object"));
else
return result;
}
JSObject toJSObject(Environment theEnv) { unimplemented("toJSObjet"); return null; }
JSDouble toJSDouble(Environment theEnv) { unimplemented("toJSDouble"); return null; }
JSInteger toJSInteger(Environment theEnv) { unimplemented("toJSInteger"); return null; }
JSString toJSString(Environment theEnv) { unimplemented("toJSString"); return null; }
JSBoolean toJSBoolean(Environment theEnv) { unimplemented("toJSBoolean"); return null; }
}

View File

@@ -1,40 +0,0 @@
import java.util.Vector;
class JSValueList extends JSValue {
static JSValueList buildList(JSValue left, JSValue right)
{
JSValueList theList;
if (left instanceof JSValueList) {
theList = (JSValueList)left;
theList.add(right);
}
else
if (right instanceof JSValueList) {
theList = (JSValueList)right;
theList.add(left);
}
else {
theList = new JSValueList();
theList.add(left);
theList.add(right);
}
return theList;
}
void add(JSValue v)
{
if (v instanceof JSValueList) {
JSValueList vl = (JSValueList)v;
for (int i = 0; i < vl.contents.size(); i++)
contents.addElement((JSValue)(vl.contents.elementAt(i)));
}
else
contents.addElement(v);
}
Vector contents = new Vector();
}

View File

@@ -1,39 +0,0 @@
class LogicalNode extends BinaryNode {
LogicalNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
{
super(aOp, aLeft, aRight);
}
JSValue eval(Environment theEnv)
{
JSBoolean b = left.eval(theEnv).toJSBoolean(theEnv);
if (op == "&&") {
if (b.isFalse())
return b;
else {
b = right.eval(theEnv).toJSBoolean(theEnv);
if (b.isFalse())
return b;
else
return JSBoolean.JSTrue;
}
}
if (op == "||") {
if (b.isTrue())
return b;
else {
b = right.eval(theEnv).toJSBoolean(theEnv);
if (b.isTrue())
return b;
else
return JSBoolean.JSFalse;
}
}
else {
System.out.println("missing logical op " + op);
return null;
}
}
}

View File

@@ -1,35 +0,0 @@
import java.util.Vector;
class NativeFunction extends JSObject {
NativeFunction(ControlNode aBody)
{
super("Function");
body = aBody;
}
JSValue call(Environment theEnv, JSValue rV)
{
JSScope args = new JSScope("Arguments");
theEnv.enterNewScope(args);
for (int i = 0; i < parameters.size(); i++) {
if (rV instanceof JSValueList)
args.putProp(theEnv, (JSString)(parameters.elementAt(i)), (JSValue) ( ((JSValueList)rV).contents.elementAt(i)) );
else
args.putProp(theEnv, (JSString)(parameters.elementAt(i)), rV );
}
ControlNode c = body;
while (c != null) c = c.eval(theEnv);
theEnv.leaveScope();
return theEnv.resultValue;
}
ControlNode body;
Vector parameters = new Vector();
}

View File

@@ -1,18 +0,0 @@
class NativeNumber extends JSObject {
NativeNumber(double p) {
super("Number");
d = p;
}
JSValue defaultValue(Environment theEnv, String hint) {
if (hint.equals("String"))
return new JSString(Double.toString(d));
else
return new JSDouble(d);
}
double d;
}

View File

@@ -1,35 +0,0 @@
class RelationalNode extends BinaryNode {
RelationalNode(String aOp, ExpressionNode aLeft, ExpressionNode aRight)
{
super(aOp, aLeft, aRight);
}
JSValue eval(Environment theEnv)
{
JSValue lV = left.eval(theEnv);
JSValue rV = right.eval(theEnv);
if (op == ">")
return lV.gt(theEnv, rV);
else
if (op == ">=")
return lV.ge(theEnv, rV);
else
if (op == "<")
return lV.lt(theEnv, rV);
else
if (op == "<=")
return lV.le(theEnv, rV);
else
if (op == "==")
return lV.eq(theEnv, rV);
else
if (op == "!=")
return lV.ne(theEnv, rV);
else {
System.out.println("missing relational op");
return null;
}
}
}

View File

@@ -1,43 +0,0 @@
import java.util.Vector;
class SwitchNode extends ControlNode {
SwitchNode(ExpressionNode e)
{
super(e);
}
void addCase(ExpressionNode e, ControlNode c)
{
if (e == null)
defaultCode = c;
else {
caseExpr.addElement(e);
caseCode.addElement(c);
}
}
ControlNode eval(Environment theEnv)
{
JSValue v = expr.eval(theEnv);
int count = caseExpr.size();
for (int i = 0; i < count; i++) {
ExpressionNode e = (ExpressionNode)(caseExpr.elementAt(i));
JSBoolean b = v.eq(theEnv, e.eval(theEnv)).toJSBoolean(theEnv);
if (b.isTrue())
return (ControlNode)(caseCode.elementAt(i));
}
if (defaultCode != null)
return defaultCode;
else
return next;
}
Vector caseExpr = new Vector();
Vector caseCode = new Vector();
ControlNode defaultCode;
}

View File

@@ -1,13 +0,0 @@
class ThrowNode extends ControlNode {
ThrowNode(ExpressionNode e)
{
super(e);
}
ControlNode eval(Environment theEnv)
{
throw new JSException(expr.eval(theEnv));
}
}

View File

@@ -1,47 +0,0 @@
import java.util.Vector;
class TryNode extends ControlNode {
TryNode(ControlNode tryCode)
{
super(null);
tryBody = tryCode;
}
void addFinally(ControlNode finallyCode)
{
finallyBody = finallyCode;
}
void addCatchClause(ExpressionNode e, ControlNode c)
{
catchExpr.addElement(e);
catchCode.addElement(c);
}
ControlNode eval(Environment theEnv)
{
try {
ControlNode c = tryBody;
while (c != null) c = c.eval(theEnv);
}
catch (JSException x) {
int count = catchExpr.size();
for (int i = 0; i < count; i++) {
ExpressionNode e = (ExpressionNode)(catchExpr.elementAt(i));
String id = ((JSObject)e).oClass;
theEnv.scope.contents.put(id, x.getValue()); // XXX YAARGH !!!
return (ControlNode)(catchCode.elementAt(i));
}
}
return next;
}
Vector catchExpr = new Vector();
Vector catchCode = new Vector();
ControlNode tryBody;
ControlNode finallyBody;
}

View File

@@ -1,62 +0,0 @@
class UnaryNode extends ExpressionNode {
UnaryNode(String aOp, ExpressionNode aChild)
{
child = aChild;
op = aOp;
}
String print(String indent)
{
StringBuffer result = new StringBuffer(indent);
result.append("UnaryNode ");
result.append(op);
result.append("\n");
indent += " ";
if (child == null) {
result.append(indent);
result.append("null\n");
}
else
result.append(child.print(indent));
return result.toString();
}
JSValue eval(Environment theEnv)
{
JSValue cV = child.eval(theEnv);
if (op == "+")
return cV.plus(theEnv);
else
if (op == "-")
return cV.minus(theEnv);
else
if (op == "~")
return cV.twiddle(theEnv);
else
if (op == "!")
return cV.bang(theEnv);
else
if (op == "typeof")
return cV.typeof(theEnv);
else {
System.out.println("missing unary op " + op);
return null;
}
}
String getOperator()
{
return op;
}
ExpressionNode getChild()
{
return child;
}
protected ExpressionNode child;
protected String op;
}

View File

@@ -1,343 +0,0 @@
// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
//
// The contents of this file are subject to the Netscape 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/NPL/
//
// Software distributed under the License is distributed on an "AS
// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
// The Original Code is the JavaScript 2 Prototype.
//
// The Initial Developer of the Original Code is Netscape
// Communications Corporation. Portions created by Netscape are
// Copyright (C) 1998 Netscape Communications Corporation. All
// Rights Reserved.
//
// JS2 shell.
//
#if 1
#define DEBUGGER_FOO
#define INTERPRET_INPUT
#else
#undef DEBUGGER_FOO
#undef INTERPRET_INPUT
#endif
#include <assert.h>
#include "world.h"
#include "interpreter.h"
#include "icodegenerator.h"
#ifdef DEBUGGER_FOO
#include "debugger.h"
#endif
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
#include <SIOUX.h>
#include <MacTypes.h>
static char *mac_argv[] = {"js2", 0};
static void initConsole(StringPtr consoleName,
const char* startupMessage,
int &argc, char **&argv)
{
SIOUXSettings.autocloseonquit = false;
SIOUXSettings.asktosaveonclose = false;
SIOUXSetTitle(consoleName);
// Set up a buffer for stderr (otherwise it's a pig).
static char buffer[BUFSIZ];
setvbuf(stderr, buffer, _IOLBF, BUFSIZ);
JavaScript::stdOut << startupMessage;
argc = 1;
argv = mac_argv;
}
#endif
namespace JavaScript {
namespace Shell {
using namespace ICG;
using namespace JSTypes;
using namespace Interpreter;
// Interactively read a line from the input stream in and put it into
// s. Return false if reached the end of input before reading anything.
static bool promptLine(LineReader &inReader, string &s, const char *prompt)
{
if (prompt) {
stdOut << prompt;
#ifdef XP_MAC_MPW
// Print a CR after the prompt because MPW grabs the entire
// line when entering an interactive command.
stdOut << '\n';
#endif
}
return inReader.readLine(s) != 0;
}
World world;
/* "filename" of the console */
const String ConsoleName = widenCString("<console>");
const bool showTokens = false;
#ifdef DEBUGGER_FOO
Reader *sourceReader; /* Reader for console file */
static
const Reader *ResolveFile (const String& fileName)
{
if (fileName == ConsoleName)
return sourceReader;
else
{
stdErr << "Could not locate source for file '" << fileName << "'\n";
return 0;
}
}
JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut,
JavaScript::stdOut, &ResolveFile);
#endif
static JSValue print(Context *cx, const JSValues &argv)
{
size_t n = argv.size();
if (n > 1) { // the 'this' parameter is un-interesting
stdOut << argv[1];
for (size_t i = 2; i < n; ++i)
stdOut << ' ' << argv[i];
}
stdOut << "\n";
return kUndefinedValue;
}
static JSValue dump(Context *cx, const JSValues &argv)
{
size_t n = argv.size();
if (n > 1) { // the 'this' parameter is un-interesting
if (argv[1].isFunction()) {
JSFunction *f = static_cast<JSFunction *>(argv[1].function);
if (f->isNative())
stdOut << "Native function";
else
stdOut << *f->getICode();
}
else
stdOut << "Not a function";
}
stdOut << "\n";
return kUndefinedValue;
}
inline char narrow(char16 ch) { return char(ch); }
static JSValue load(Context *cx, const JSValues &argv)
{
JSValue result;
size_t n = argv.size();
if (n > 1) {
for (size_t i = 1; i < n; ++i) {
JSValue val = argv[i].toString();
if (val.isString()) {
String fileName(*val.string);
std::string str(fileName.length(), char());
std::transform(fileName.begin(), fileName.end(), str.begin(), narrow);
FILE* f = fopen(str.c_str(), "r");
if (f) {
result = cx->readEvalFile(f, fileName);
fclose(f);
}
}
}
}
return result;
}
#if 0 // need a XP version of this, rip off from Monkey?
#include <sys/timeb.h>
static JSValue time(Context *cx, const JSValues &argv)
{
struct _timeb timebuffer;
_ftime(&timebuffer);
return JSValue((double)timebuffer.time * 1000 + timebuffer.millitm);
}
#endif
static void readEvalPrint(FILE *in, World &world)
{
JSScope global;
Context cx(world, &global);
#ifdef DEBUGGER_FOO
jsd.attachToContext (&cx);
#endif
global.defineNativeFunction(world.identifiers["print"], print);
global.defineNativeFunction(world.identifiers["dump"], dump);
global.defineNativeFunction(world.identifiers["load"], load);
// global.defineNativeFunction(world.identifiers["time"], time);
String buffer;
string line;
LineReader inReader(in);
while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) {
appendChars(buffer, line.data(), line.size());
try {
Arena a;
Parser p(world, a, buffer, ConsoleName);
if (showTokens) {
Lexer &l = p.lexer;
while (true) {
const Token &t = l.get(true);
if (t.hasKind(Token::end))
break;
stdOut << ' ';
t.print(stdOut, true);
}
stdOut << '\n';
} else {
StmtNode *parsedStatements = p.parseProgram();
ASSERT(p.lexer.peek(true).hasKind(Token::end));
{
PrettyPrinter f(stdOut, 30);
{
PrettyPrinter::Block b(f, 2);
f << "Program =";
f.linearBreak(1);
StmtNode::printStatements(f, parsedStatements);
}
f.end();
}
stdOut << '\n';
#ifdef INTERPRET_INPUT
#ifdef DEBUGGER_FOO
sourceReader = &(p.lexer.reader);
#endif
// Generate code for parsedStatements, which is a linked
// list of zero or more statements
ICodeModule* icm = cx.genCode(parsedStatements, ConsoleName);
if (icm) {
stdOut << *icm;
JSValue result = cx.interpret(icm, JSValues());
stdOut << "result = " << result << "\n";
delete icm;
}
#endif
}
clear(buffer);
} catch (Exception &e) {
/* If we got a syntax error on the end of input,
* then wait for a continuation
* of input rather than printing the error message. */
if (!(e.hasKind(Exception::syntaxError) &&
e.lineNum && e.pos == buffer.size() &&
e.sourceFile == ConsoleName)) {
stdOut << '\n' << e.fullMessage();
clear(buffer);
}
}
}
stdOut << '\n';
}
/**
* Poor man's instruction tracing facility.
*/
class Tracer : public Context::Listener {
typedef InstructionStream::difference_type InstructionOffset;
void listen(Context* context, Context::Event event)
{
if (event & Context::EV_STEP) {
ICodeModule *iCode = context->getICode();
JSValues &registers = context->getRegisters();
InstructionIterator pc = context->getPC();
InstructionOffset offset = (pc - iCode->its_iCode->begin());
printFormat(stdOut, "trace [%02u:%04u]: ",
iCode->mID, offset);
Instruction* i = *pc;
stdOut << *i;
if (i->op() != BRANCH && i->count() > 0) {
stdOut << " [";
i->printOperands(stdOut, registers);
stdOut << "]\n";
} else {
stdOut << '\n';
}
}
}
};
char * tests[] = {
"function fact(n) { if (n > 1) return n * fact(n-1); else return 1; } print(fact(6), \" should be 720\"); return;" ,
"a = { f1: 1, f2: 2}; print(a.f2++, \" should be 2\"); print(a.f2 <<= 1, \" should be 6\"); return;" ,
"class A { static var b = 3; static function s() { return b++; }function x() { return \"Ax\"; } function y() { return \"Ay\"; } } var a:A = new A; print(a.s(), \" should be 3\"); print(A.b, \" should be 4\"); return;",
"class B extends A { function x() { return \"Bx\"; } } var b:B = new B; print(b.x(), \" should be Bx\"); print(b.y(), \" should be Ay\"); return;"
};
static void testCompile()
{
JSScope glob;
Context cx(world, &glob);
glob.defineNativeFunction(world.identifiers["print"], print);
for (uint i = 0; i < sizeof(tests) / sizeof(char *); i++) {
String testScript = widenCString(tests[i]);
Arena a;
Parser p(world, a, testScript, widenCString("testCompile"));
StmtNode *parsedStatements = p.parseProgram();
ICodeGenerator icg(&world, &glob);
StmtNode *s = parsedStatements;
while (s) {
icg.genStmt(s);
s = s->next;
}
cx.interpret(icg.complete(), JSValues());
}
}
} /* namespace Shell */
} /* namespace JavaScript */
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
int main(int argc, char **argv)
{
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
#else
int main(int , char **)
{
#endif
using namespace JavaScript;
using namespace Shell;
#if 1
testCompile();
#endif
readEvalPrint(stdin, world);
return 0;
// return ProcessArgs(argv + 1, argc - 1);
}

View File

@@ -1,316 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef jsclasses_h
#define jsclasses_h
#include "jstypes.h"
namespace JavaScript {
namespace JSClasses {
using JSTypes::JSValue;
using JSTypes::JSObject;
using JSTypes::JSType;
using JSTypes::JSScope;
using JSTypes::JSFunction;
using ICG::ICodeModule;
struct JSSlot {
typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc
JSType* mType;
uint32 mIndex;
SlotFlags mFlags;
JSSlot() : mType(0), mFlags(kNoFlag)
{
}
bool isConstructor() const { return (mFlags & kIsConstructor) != 0; }
};
#if defined(XP_MAC)
// copied from default template parameters in map.
typedef gc_allocator<std::pair<const String, JSSlot> > gc_slot_allocator;
#elif defined(XP_UNIX)
typedef JSTypes::gc_map_allocator gc_slot_allocator;
#elif defined(_WIN32)
typedef gc_allocator<JSSlot> gc_slot_allocator;
#endif
typedef std::map<String, JSSlot, std::less<const String>, gc_slot_allocator> JSSlots;
typedef std::pair<String, JSFunction*> MethodEntry;
typedef std::vector<MethodEntry> JSMethods;
/**
* Represents a class in the JavaScript 2 (ECMA 4) language.
* Since a class defines a scope, and is defined in a scope,
* a new scope is created whose parent scope is the scope of
* class definition.
*/
class JSClass : public JSType {
protected:
JSScope* mScope;
uint32 mSlotCount;
JSSlots mSlots;
uint32 mStaticCount;
JSSlots mStaticSlots;
JSValue* mStaticData;
JSMethods mMethods;
public:
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
: JSType(name, superClass),
mScope(new JSScope(scope)),
mSlotCount(superClass ? superClass->mSlotCount : 0),
mStaticCount(0),
mStaticData(0)
{
if (superClass) {
// inherit superclass methods
JSMethods::iterator end = superClass->mMethods.end();
for (JSMethods::iterator i = superClass->mMethods.begin(); i != end; i++)
mMethods.push_back(*i);
}
}
JSClass* getSuperClass()
{
return static_cast<JSClass*>(mBaseType);
}
JSScope* getScope()
{
return mScope;
}
const JSSlot& defineSlot(const String& name, JSType* type)
{
JSSlot& slot = mSlots[name];
ASSERT(slot.mType == 0);
slot.mType = type;
slot.mIndex = mSlotCount++; // starts at 0.
return slot;
}
const JSSlot& getSlot(const String& name)
{
return mSlots[name];
}
bool hasSlot(const String& name)
{
return (mSlots.find(name) != mSlots.end());
}
JSSlots& getSlots()
{
return mSlots;
}
uint32 getSlotCount()
{
return mSlotCount;
}
/**
* Define a static/class variable.
*/
const JSSlot& defineStatic(const String& name, JSType* type)
{
JSSlot& slot = mStaticSlots[name];
ASSERT(slot.mType == 0);
slot.mType = type;
slot.mIndex = mStaticCount++;
return slot;
}
const JSSlot& defineConstructor(const String& name)
{
JSSlot& slot = mStaticSlots[name];
ASSERT(slot.mType == 0);
slot.mType = &JSTypes::Function_Type;
slot.mIndex = mStaticCount++;
slot.mFlags = JSSlot::kIsConstructor;
return slot;
}
const JSSlot& getStatic(const String& name)
{
return mStaticSlots[name];
}
bool hasStatic(const String& name, JSType*& type, bool &isConstructor)
{
JSSlots::const_iterator i = mStaticSlots.find(name);
if (i != mStaticSlots.end()) {
type = i->second.mType;
isConstructor = i->second.isConstructor();
return true;
}
return false;
}
bool hasStatic(const String& name)
{
return (mStaticSlots.find(name) != mStaticSlots.end());
}
bool complete()
{
mStaticData = new JSValue[mStaticCount];
return (mStaticData != 0);
}
JSValue& operator[] (uint32 index)
{
return mStaticData[index];
}
virtual void printProperties(Formatter& f)
{
f << "Properties:\n";
JSObject::printProperties(f);
f << "Statics:\n";
printStatics(f);
}
void printStatics(Formatter& f)
{
JSClass* superClass = getSuperClass();
if (superClass) superClass->printStatics(f);
for (JSSlots::iterator i = mStaticSlots.begin(), end = mStaticSlots.end(); i != end; ++i) {
f << i->first << " : " << mStaticData[i->second.mIndex] << "\n";
}
}
void defineMethod(const String& name, JSFunction *f)
{
uint32 slot;
if (hasMethod(name, slot))
mMethods[slot] = MethodEntry(name, f);
else
mMethods.push_back(MethodEntry(name, f));
}
bool hasMethod(const String& name, uint32& index)
{
JSMethods::iterator end = mMethods.end();
for (JSMethods::iterator i = mMethods.begin(); i != end; i++) {
if (i->first == name) {
index = i - mMethods.begin();
return true;
}
}
return false;
}
JSFunction* getMethod(uint32 index)
{
return mMethods[index].second;
}
};
/**
* Represents an instance of a JSClass.
*/
class JSInstance : public JSObject {
protected:
JSValue mSlots[1];
public:
void* operator new(size_t n, JSClass* thisClass)
{
uint32 slotCount = thisClass->getSlotCount();
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
return gc_base::operator new(n);
}
#if !defined(XP_MAC)
void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {}
#endif
JSInstance(JSClass* thisClass)
{
mType = thisClass;
// initialize extra slots with undefined.
uint32 slotCount = thisClass->getSlotCount();
if (slotCount > 0) {
std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1),
JSTypes::kUndefinedValue);
}
// for grins, use the prototype link to access methods.
setPrototype(thisClass->getScope());
}
JSFunction* getMethod(uint32 index)
{
return getClass()->getMethod(index);
}
JSClass* getClass()
{
return static_cast<JSClass*>(mType);
}
JSValue& operator[] (uint32 index)
{
return mSlots[index];
}
virtual void printProperties(Formatter& f)
{
f << "Properties:\n";
JSObject::printProperties(f);
f << "Slots:\n";
printSlots(f, getClass());
}
private:
void printSlots(Formatter& f, JSClass* thisClass)
{
JSClass* superClass = thisClass->getSuperClass();
if (superClass) printSlots(f, superClass);
JSSlots& slots = thisClass->getSlots();
for (JSSlots::iterator i = slots.begin(), end = slots.end(); i != end; ++i) {
f << i->first << " : " << mSlots[i->second.mIndex] << "\n";
}
}
};
} /* namespace JSClasses */
} /* namespace JavaScript */
#endif /* jsclasses_h */

View File

@@ -1,208 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include <math.h>
#include "jsmath.h"
namespace JavaScript {
namespace JSMathClass {
using namespace JSTypes;
#ifndef M_E
#define M_E 2.7182818284590452354
#endif
#ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074
#endif
#ifndef M_LOG10E
#define M_LOG10E 0.43429448190325182765
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif
#ifndef M_SQRT1_2
#define M_SQRT1_2 0.70710678118654752440
#endif
/*
Concept copied from SpiderMonkey -
fd_XXX needs to be defined either as a call to the fdlibm routine
or the native C library routine depending on the platform
*/
#define JS_USE_FDLIBM_MATH 0
#if !JS_USE_FDLIBM_MATH
/*
* Use system provided math routines.
*/
#define fd_acos acos
#define fd_asin asin
#define fd_atan atan
#define fd_atan2 atan2
#define fd_ceil ceil
#define fd_copysign copysign
#define fd_cos cos
#define fd_exp exp
#define fd_fabs fabs
#define fd_floor floor
#define fd_fmod fmod
#define fd_log log
#define fd_pow pow
#define fd_sin sin
#define fd_sqrt sqrt
#define fd_tan tan
#endif
JSValue math_abs(Context *cx, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
if (num.isNaN()) return num;
if (num.isNegativeZero()) return kPositiveZero;
if (num.isNegativeInfinity()) return kPositiveInfinity;
if (num.f64 < 0) return JSValue(-num.f64);
return num;
}
return kUndefinedValue;
}
JSValue math_acos(Context *cx, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_acos(num.f64));
}
return kUndefinedValue;
}
JSValue math_asin(Context *cx, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_asin(num.f64));
}
return kUndefinedValue;
}
JSValue math_atan(Context *cx, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_atan(num.f64));
}
return kUndefinedValue;
}
JSValue math_atan2(Context *cx, const JSValues& argv)
{
if (argv.size() > 1) {
JSValue num1 = argv[1].toNumber();
JSValue num2 = argv[1].toNumber();
return JSValue(fd_atan2(num1.f64, num2.f64));
}
return kUndefinedValue;
}
JSValue math_ceil(Context *cx, const JSValues& argv)
{
if (argv.size() > 0) {
JSValue num = argv[1].toNumber();
return JSValue(fd_ceil(num.f64));
}
return kUndefinedValue;
}
struct MathFunctionEntry {
char *name;
JSNativeFunction::JSCode fn;
} MathFunctions[] = {
{ "abs", math_abs },
{ "acos", math_acos },
{ "asin", math_asin },
{ "atan", math_atan },
{ "atan2", math_atan2 },
{ "ceil", math_acos },
{ "acos", math_acos },
{ "acos", math_acos }
};
struct MathConstantEntry {
char *name;
double value;
} MathConstants[] = {
{ "E", M_E },
{ "LOG2E", M_LOG2E },
{ "LOG10E", M_LOG10E },
{ "LN2", M_LN2 },
{ "LN10", M_LN10 },
{ "PI", M_PI },
{ "SQRT2", M_SQRT2 },
{ "SQRT1_2", M_SQRT1_2 }
};
// There is no constructor for Math, we simply initialize
// the properties of the Math object
void JSMath::initMathObject(JSScope *g)
{
int i;
JSMath *m = new JSMath();
m->setClass(new JSString("Math"));
for (i = 0; i < sizeof(MathFunctions) / sizeof(MathFunctionEntry); i++)
m->setProperty(widenCString(MathFunctions[i].name), JSValue(new JSNativeFunction(MathFunctions[i].fn) ) );
for (i = 0; i < sizeof(MathConstants) / sizeof(MathConstantEntry); i++)
m->setProperty(widenCString(MathConstants[i].name), JSValue(MathConstants[i].value) );
g->setProperty(widenCString("Math"), JSValue(m));
}
} /* JSMathClass */
} /* JavaScript */

View File

@@ -1,58 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef jsmath_h
#define jsmath_h
#include "jstypes.h"
namespace JavaScript {
namespace JSMathClass {
using JSTypes::JSObject;
using JSTypes::JSString;
using JSTypes::JSScope;
class JSMath : public JSObject {
private:
JSMath() { }
public:
static void initMathObject(JSScope *g);
};
} /* JSMathClass */
} /* JavaScript */
#endif jsmath_h

View File

@@ -1,775 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include "jstypes.h"
#include "jsclasses.h"
#include "numerics.h"
#include "icodegenerator.h"
#include "interpreter.h"
namespace JavaScript {
namespace JSTypes {
using namespace JSClasses;
using namespace Interpreter;
/********** Object Object Stuff **************************/
JSValue object_toString(Context *cx, const JSValues& argv)
{
if (argv.size() > 0) {
JSString *s = new JSString("[object ");
JSValue theThis = argv[0];
ASSERT(theThis.isObject());
s->append(theThis.object->getClass());
s->append("]");
return JSValue(s);
}
return kUndefinedValue;
}
JSValue objectConstructor(Context *cx, const JSValues& argv)
{
ASSERT(argv.size() > 0);
JSValue theThis = argv[0];
// the prototype and class have been established already
return theThis;
}
struct ObjectFunctionEntry {
char *name;
JSNativeFunction::JSCode fn;
} ObjectFunctions[] = {
{ "toString", object_toString },
};
JSObject *JSObject::objectPrototypeObject = JSObject::initJSObject();
String JSObject::ObjectString = widenCString("Object");
// This establishes the ur-prototype, there's a timing issue
// here - the JSObject static initializers have to run before
// any other JSObject objects are constructed.
JSObject *JSObject::initJSObject()
{
JSObject *result = new JSObject();
for (int i = 0; i < sizeof(ObjectFunctions) / sizeof(ObjectFunctionEntry); i++)
result->setProperty(widenCString(ObjectFunctions[i].name), JSValue(new JSNativeFunction(ObjectFunctions[i].fn) ) );
return result;
}
// Install the 'Object' constructor into the scope, mostly irrelevant since making
// a new JSObject does all the work of setting the prototype and [[class]] values.
void JSObject::initObjectObject(JSScope *g)
{
JSNativeFunction *objCon = new JSNativeFunction(objectConstructor);
objCon->setProperty(widenCString("prototype"), JSValue(objectPrototypeObject));
g->setProperty(ObjectString, JSValue(objCon));
}
/********** Function Object Stuff **************************/
// An empty function that returns undefined
JSValue functionPrototypeFunction(Context *cx, const JSValues& argv)
{
return kUndefinedValue;
}
JSValue function_constructor(Context *cx, const JSValues& argv)
{
// build a function from the arguments into the this.
ASSERT(argv.size() > 0);
JSValue theThis = argv[0];
ASSERT(theThis.isObject());
if (argv.size() == 2) {
JSValue s = JSValue::valueToString(argv[1]);
theThis = new JSFunction(cx->compile((String)(*s.string)));
}
return theThis;
}
JSValue function_toString(Context *cx, const JSValues& argv)
{
return JSValue(new JSString("function XXX() { }" ));
}
JSValue function_apply(Context *cx, const JSValues& argv)
{
// XXX
return kUndefinedValue;
}
JSValue function_call(Context *cx, const JSValues& argv)
{
// XXX
return kUndefinedValue;
}
String JSFunction::FunctionString = widenCString("Function");
JSObject *JSFunction::functionPrototypeObject = NULL; // the 'original Function prototype object'
struct FunctionFunctionEntry {
char *name;
JSNativeFunction::JSCode fn;
} FunctionFunctions[] = {
{ "constructor", function_constructor },
{ "toString", function_toString },
{ "apply", function_apply },
{ "call", function_call },
};
void JSFunction::initFunctionObject(JSScope *g)
{
// first build the Function Prototype Object
functionPrototypeObject = new JSNativeFunction(functionPrototypeFunction);
for (int i = 0; i < sizeof(FunctionFunctions) / sizeof(FunctionFunctionEntry); i++)
functionPrototypeObject->setProperty(widenCString(FunctionFunctions[i].name), JSValue(new JSNativeFunction(FunctionFunctions[i].fn) ) );
// now the Function Constructor Object
JSNativeFunction *functionConstructorObject = new JSNativeFunction(function_constructor);
functionConstructorObject->setPrototype(functionPrototypeObject);
functionConstructorObject->setProperty(widenCString("length"), JSValue((int32)1));
functionConstructorObject->setProperty(widenCString("prototype"), JSValue(functionPrototypeObject));
// This is interesting - had to use defineVariable here to specify a type because
// when left as Any_Type (via setProperty), the Function predefined type interacted
// badly with this value. (I think setProperty perhaps should have reset the entry
// in mTypes) (?)
g->defineVariable(FunctionString, &Function_Type, JSValue(functionConstructorObject));
}
/**************************************************************************************/
JSType Any_Type = JSType(widenCString("any"), NULL);
JSType Integer_Type = JSType(widenCString("Integer"), &Any_Type);
JSType Number_Type = JSType(widenCString("Number"), &Integer_Type);
JSType Character_Type = JSType(widenCString("Character"), &Any_Type);
JSType String_Type = JSType(widenCString("String"), &Character_Type);
JSType Function_Type = JSType(widenCString("Function"), &Any_Type);
JSType Array_Type = JSType(widenCString("Array"), &Any_Type);
JSType Type_Type = JSType(widenCString("Type"), &Any_Type);
JSType Boolean_Type = JSType(widenCString("Boolean"), &Any_Type);
JSType Null_Type = JSType(widenCString("Null"), &Any_Type);
JSType Void_Type = JSType(widenCString("void"), &Any_Type);
JSType None_Type = JSType(widenCString("none"), &Any_Type);
#ifdef IS_LITTLE_ENDIAN
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[1])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[0])
#else
#define JSDOUBLE_HI32(x) (((uint32 *)&(x))[0])
#define JSDOUBLE_LO32(x) (((uint32 *)&(x))[1])
#endif
#define JSDOUBLE_HI32_SIGNBIT 0x80000000
#define JSDOUBLE_HI32_EXPMASK 0x7ff00000
#define JSDOUBLE_HI32_MANTMASK 0x000fffff
#define JSDOUBLE_IS_NaN(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) == JSDOUBLE_HI32_EXPMASK && \
(JSDOUBLE_LO32(x) || (JSDOUBLE_HI32(x) & JSDOUBLE_HI32_MANTMASK)))
#define JSDOUBLE_IS_INFINITE(x) \
((JSDOUBLE_HI32(x) & ~JSDOUBLE_HI32_SIGNBIT) == JSDOUBLE_HI32_EXPMASK && \
!JSDOUBLE_LO32(x))
#define JSDOUBLE_IS_FINITE(x) \
((JSDOUBLE_HI32(x) & JSDOUBLE_HI32_EXPMASK) != JSDOUBLE_HI32_EXPMASK)
#define JSDOUBLE_IS_NEGZERO(d) (JSDOUBLE_HI32(d) == JSDOUBLE_HI32_SIGNBIT && \
JSDOUBLE_LO32(d) == 0)
// the canonical undefined value, etc.
const JSValue kUndefinedValue;
const JSValue kNaNValue = JSValue(nan);
const JSValue kTrueValue = JSValue(true);
const JSValue kFalseValue = JSValue(false);
const JSValue kNullValue = JSValue((JSObject*)NULL);
const JSValue kNegativeZero = JSValue(-0.0);
const JSValue kPositiveZero = JSValue(0.0);
const JSValue kNegativeInfinity = JSValue(negativeInfinity);
const JSValue kPositiveInfinity = JSValue(positiveInfinity);
const JSType *JSValue::getType() const
{
switch (tag) {
case JSValue::i32_tag:
return &Integer_Type;
case JSValue::u32_tag:
return &Integer_Type;
case JSValue::integer_tag:
return &Integer_Type;
case JSValue::f64_tag:
return &Number_Type;
case JSValue::object_tag:
{
//
// XXX why isn't there a class for Object? XXX
//
JSClass *clazz = dynamic_cast<JSClass *>(object->getType());
if (clazz)
return clazz;
else
return &Any_Type;
}
case JSValue::array_tag:
return &Array_Type;
case JSValue::function_tag:
return &Function_Type;
case JSValue::string_tag:
return &String_Type;
case JSValue::boolean_tag:
return &Boolean_Type;
case JSValue::undefined_tag:
return &Void_Type;
case JSValue::type_tag:
return &Type_Type;
default:
NOT_REACHED("Bad tag");
return &None_Type;
}
}
bool JSValue::isNaN() const
{
ASSERT(isNumber());
switch (tag) {
case i32_tag:
case u32_tag:
return false;
case integer_tag:
case f64_tag:
return JSDOUBLE_IS_NaN(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
bool JSValue::isNegativeInfinity() const
{
ASSERT(isNumber());
switch (tag) {
case i32_tag:
case u32_tag:
return false;
case integer_tag:
case f64_tag:
return (f64 < 0) && JSDOUBLE_IS_INFINITE(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
bool JSValue::isPositiveInfinity() const
{
ASSERT(isNumber());
switch (tag) {
case i32_tag:
case u32_tag:
return false;
case integer_tag:
case f64_tag:
return (f64 > 0) && JSDOUBLE_IS_INFINITE(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
bool JSValue::isNegativeZero() const
{
ASSERT(isNumber());
switch (tag) {
case i32_tag:
case u32_tag:
return false;
case integer_tag:
case f64_tag:
return JSDOUBLE_IS_NEGZERO(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
bool JSValue::isPositiveZero() const
{
ASSERT(isNumber());
switch (tag) {
case i32_tag:
return (i32 == 0);
case u32_tag:
return (u32 == 0);
case integer_tag:
case f64_tag:
return (f64 == 0.0) && !JSDOUBLE_IS_NEGZERO(f64);
default:
NOT_REACHED("Broken compiler?");
return true;
}
}
int JSValue::operator==(const JSValue& value) const
{
if (this->tag == value.tag) {
#define CASE(T) case T##_tag: return (this->T == value.T)
switch (tag) {
CASE(i8); CASE(u8);
CASE(i16); CASE(u16);
CASE(i32); CASE(u32); CASE(f32);
CASE(i64); CASE(u64); CASE(f64);
CASE(object); CASE(array); CASE(function); CASE(string);
CASE(type); CASE(boolean);
#undef CASE
case integer_tag : return (this->f64 == value.f64);
// question: are all undefined values equal to one another?
case undefined_tag: return 1;
}
}
return 0;
}
Formatter& operator<<(Formatter& f, JSObject& obj)
{
obj.printProperties(f);
return f;
}
void JSObject::printProperties(Formatter& f)
{
for (JSProperties::const_iterator i = mProperties.begin(); i != mProperties.end(); i++) {
f << (*i).first << " : " << (*i).second;
f << "\n";
}
}
Formatter& operator<<(Formatter& f, const JSValue& value)
{
switch (value.tag) {
case JSValue::i32_tag:
f << float64(value.i32);
break;
case JSValue::u32_tag:
f << float64(value.u32);
break;
case JSValue::integer_tag:
case JSValue::f64_tag:
f << value.f64;
break;
case JSValue::object_tag:
printFormat(f, "Object @ 0x%08X\n", value.object);
f << *value.object;
break;
case JSValue::array_tag:
printFormat(f, "Array @ 0x%08X", value.object);
break;
case JSValue::function_tag:
printFormat(f, "Function @ 0x%08X", value.object);
break;
case JSValue::string_tag:
f << *value.string;
break;
case JSValue::boolean_tag:
f << ((value.boolean) ? "true" : "false");
break;
case JSValue::undefined_tag:
f << "undefined";
break;
case JSValue::type_tag:
printFormat(f, "Type @ 0x%08X\n", value.type);
f << *value.type;
break;
default:
NOT_REACHED("Bad tag");
}
return f;
}
JSValue JSValue::toPrimitive(ECMA_type /*hint*/) const
{
JSObject *obj;
switch (tag) {
case i32_tag:
case u32_tag:
case integer_tag:
case f64_tag:
case string_tag:
case boolean_tag:
case undefined_tag:
return *this;
case object_tag:
obj = object;
break;
case array_tag:
obj = array;
break;
case function_tag:
obj = function;
break;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
const JSValue &toString = obj->getProperty(widenCString("toString"));
if (toString.isObject()) {
if (toString.isFunction()) {
}
else // right? The spec doesn't say
throw new JSException("Runtime error from toPrimitive"); // XXX
}
const JSValue &valueOf = obj->getProperty(widenCString("valueOf"));
if (!valueOf.isObject())
throw new JSException("Runtime error from toPrimitive"); // XXX
return kUndefinedValue;
}
JSValue JSValue::valueToString(const JSValue& value) // can assume value is not a string
{
const char* chrp;
char buf[dtosStandardBufferSize];
switch (value.tag) {
case i32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.i32, dtosStandard, 0);
break;
case u32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0);
break;
case integer_tag:
case f64_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0);
break;
case object_tag:
chrp = "object";
break;
case array_tag:
chrp = "array";
break;
case function_tag:
chrp = "function";
break;
case string_tag:
return value;
case boolean_tag:
chrp = (value.boolean) ? "true" : "false";
break;
case undefined_tag:
chrp = "undefined";
break;
default:
NOT_REACHED("Bad tag");
}
return JSValue(new JSString(chrp));
}
JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not a number
{
switch (value.tag) {
case i32_tag:
return JSValue((float64)value.i32);
case u32_tag:
return JSValue((float64)value.u32);
case integer_tag:
case f64_tag:
return value;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
double d = stringToDouble(str->begin(), str->end(), numEnd);
return JSValue(d);
}
case object_tag:
case array_tag:
case function_tag:
// XXX more needed :
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
case boolean_tag:
return JSValue((value.boolean) ? 1.0 : 0.0);
case undefined_tag:
return kNaNValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
}
JSValue JSValue::valueToInteger(const JSValue& value)
{
JSValue result = valueToNumber(value);
ASSERT(result.tag == f64_tag);
result.tag = i64_tag;
bool neg = (result.f64 < 0);
result.f64 = floor((neg) ? -result.f64 : result.f64);
result.f64 = (neg) ? -result.f64 : result.f64;
return result;
}
JSValue JSValue::valueToBoolean(const JSValue& value)
{
switch (value.tag) {
case i32_tag:
return JSValue(value.i32 != 0);
case u32_tag:
return JSValue(value.u32 != 0);
case integer_tag:
case f64_tag:
return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64));
case string_tag:
return JSValue(value.string->length() != 0);
case boolean_tag:
return value;
case object_tag:
case array_tag:
case function_tag:
return kTrueValue;
case undefined_tag:
return kFalseValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
}
static const double two32 = 4294967296.0;
static const double two31 = 2147483648.0;
JSValue JSValue::valueToInt32(const JSValue& value)
{
double d;
switch (value.tag) {
case i32_tag:
return value;
case u32_tag:
d = value.u32;
break;
case integer_tag:
case f64_tag:
d = value.f64;
break;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
d = stringToDouble(str->begin(), str->end(), numEnd);
}
break;
case boolean_tag:
return JSValue((int32)((value.boolean) ? 1 : 0));
case object_tag:
case array_tag:
case undefined_tag:
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d) )
return JSValue((int32)0);
d = fmod(d, two32);
d = (d >= 0) ? d : d + two32;
if (d >= two31)
return JSValue((int32)(d - two32));
else
return JSValue((int32)d);
}
JSValue JSValue::valueToUInt32(const JSValue& value)
{
double d;
switch (value.tag) {
case i32_tag:
return JSValue((uint32)value.i32);
case u32_tag:
return value;
case f64_tag:
d = value.f64;
break;
case string_tag:
{
JSString* str = value.string;
const char16 *numEnd;
d = stringToDouble(str->begin(), str->end(), numEnd);
}
break;
case boolean_tag:
return JSValue((uint32)((value.boolean) ? 1 : 0));
case object_tag:
case array_tag:
case undefined_tag:
// toNumber(toPrimitive(hint Number))
return kUndefinedValue;
default:
NOT_REACHED("Bad tag");
return kUndefinedValue;
}
if ((d == 0.0) || !JSDOUBLE_IS_FINITE(d))
return JSValue((uint32)0);
bool neg = (d < 0);
d = floor(neg ? -d : d);
d = neg ? -d : d;
d = fmod(d, two32);
d = (d >= 0) ? d : d + two32;
return JSValue((uint32)d);
}
JSValue JSValue::convert(JSType *toType)
{
if (toType == &Any_Type) // yuck, something wrong with this
// maybe the base types should be
// a family of classes, not just instances
// of JSType ???
return *this;
else if (toType == &Integer_Type)
return valueToInteger(*this);
else {
JSClass *toClass = dynamic_cast<JSClass *>(toType);
if (toClass) {
if (tag == object_tag) {
JSClass *fromClass = dynamic_cast<JSClass *>(object->getType());
if (fromClass) {
while (fromClass != toClass) {
fromClass = fromClass->getSuperClass();
if (fromClass == NULL)
throw new JSException("Can't cast to unrelated class");
}
return *this;
}
else
throw new JSException("Can't cast a generic object to a class");
}
else
throw new JSException("Can't cast a non-object to a class");
}
}
return kUndefinedValue;
}
JSFunction::~JSFunction()
{
delete mICode;
}
JSString::JSString(const String& str)
{
size_t n = str.size();
resize(n);
traits_type::copy(begin(), str.begin(), n);
}
JSString::JSString(const String* str)
{
size_t n = str->size();
resize(n);
traits_type::copy(begin(), str->begin(), n);
}
JSString::JSString(const char* str)
{
size_t n = ::strlen(str);
resize(n);
std::transform(str, str + n, begin(), JavaScript::widen);
}
void JSString::append(const char* str)
{
size_t n = ::strlen(str);
size_t oldSize = size();
resize(oldSize + n);
std::transform(str, str + n, begin() + oldSize, JavaScript::widen);
}
void JSString::append(const JSStringBase* str)
{
size_t n = str->size();
size_t oldSize = size();
resize(oldSize + n);
traits_type::copy(begin() + oldSize, str->begin(), n);
}
JSString::operator String()
{
return String(begin(), size());
}
// # of sub-type relationship between this type and the other type
// (== MAX_INT if other is not a base type)
int32 JSType::distance(const JSType *other) const
{
if (other == this)
return 0;
if (mBaseType == NULL)
return NoRelation;
int32 baseDistance = mBaseType->distance(other);
if (baseDistance != NoRelation)
++baseDistance;
return baseDistance;
}
} /* namespace JSTypes */
} /* namespace JavaScript */

View File

@@ -1,579 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#ifndef jstypes_h
#define jstypes_h
#include "utilities.h"
#include "gc_allocator.h"
#include <vector>
#include <map>
#include <stack>
/* forward declare classes from JavaScript::ICG */
namespace JavaScript {
namespace ICG {
class ICodeModule;
} /* namespace ICG */
namespace Interpreter {
class Context;
} /* namespace Interpreter */
} /* namespace JavaScript */
namespace JavaScript {
namespace JSTypes {
using ICG::ICodeModule;
using Interpreter::Context;
class JSObject;
class JSArray;
class JSFunction;
class JSScope;
class JSString;
class JSType;
class Context;
/**
* All JavaScript data types.
*/
struct JSValue {
union {
int8 i8;
uint8 u8;
int16 i16;
uint16 u16;
int32 i32;
uint32 u32;
int64 i64;
uint64 u64;
float32 f32;
float64 f64;
JSObject* object;
JSArray* array;
JSFunction *function;
JSString *string;
JSType *type;
bool boolean;
};
/* These are the ECMA types, for use in 'toPrimitive' calls */
enum ECMA_type {
Undefined, Null, Boolean, Number, Object, String,
NoHint
};
enum {
i8_tag, u8_tag,
i16_tag, u16_tag,
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
integer_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
undefined_tag
} tag;
JSValue() : f64(0.0), tag(undefined_tag) {}
explicit JSValue(int32 i32) : i32(i32), tag(i32_tag) {}
explicit JSValue(uint32 u32) : u32(u32), tag(u32_tag) {}
explicit JSValue(float64 f64) : f64(f64), tag(f64_tag) {}
explicit JSValue(JSObject* object) : object(object), tag(object_tag) {}
explicit JSValue(JSArray* array) : array(array), tag(array_tag) {}
explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {}
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
explicit JSValue(JSType* type) : type(type), tag(type_tag) {}
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
float64& operator=(float64 f64) { return (tag = f64_tag, this->f64 = f64); }
JSObject*& operator=(JSObject* object) { return (tag = object_tag, this->object = object); }
JSArray*& operator=(JSArray* array) { return (tag = array_tag, this->array = array); }
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); }
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
JSType*& operator=(JSType* type) { return (tag = type_tag, this->type = type); }
bool isFunction() const { return (tag == function_tag); }
bool isObject() const { return ((tag == object_tag) || (tag == function_tag) || (tag == array_tag) || (tag == type_tag)); }
bool isString() const { return (tag == string_tag); }
bool isBoolean() const { return (tag == boolean_tag); }
bool isNumber() const { return (tag == f64_tag) || (tag == integer_tag); }
/* this is correct wrt ECMA, The i32 & u32 kinds
will have to be converted (to doubles?) anyway because
we can't have overflow happening in generic arithmetic */
bool isUndefined() const { return (tag == undefined_tag); }
bool isNull() const { return ((tag == object_tag) && (this->object == NULL)); }
bool isNaN() const;
bool isNegativeInfinity() const;
bool isPositiveInfinity() const;
bool isNegativeZero() const;
bool isPositiveZero() const;
bool isType() const { return (tag == type_tag); }
JSValue toString() const { return (isString() ? *this : valueToString(*this)); }
JSValue toNumber() const { return (isNumber() ? *this : valueToNumber(*this)); }
JSValue toInt32() const { return ((tag == i32_tag) ? *this : valueToInt32(*this)); }
JSValue toUInt32() const { return ((tag == u32_tag) ? *this : valueToUInt32(*this)); }
JSValue toBoolean() const { return ((tag == boolean_tag) ? *this : valueToBoolean(*this)); }
JSValue toPrimitive(ECMA_type hint = NoHint) const;
JSValue convert(JSType *toType);
static JSValue valueToString(const JSValue& value);
static JSValue valueToNumber(const JSValue& value);
static JSValue valueToInteger(const JSValue& value);
static JSValue valueToInt32(const JSValue& value);
static JSValue valueToUInt32(const JSValue& value);
static JSValue valueToBoolean(const JSValue& value);
const JSType *getType() const; // map from tag type to JS2 type
int operator==(const JSValue& value) const;
};
Formatter& operator<<(Formatter& f, const JSValue& value);
#if defined(XP_MAC)
// copied from default template parameters in map.
typedef gc_allocator<std::pair<const String, JSValue> > gc_map_allocator;
#elif defined(XP_UNIX)
// FIXME: in libg++, they assume the map's allocator is a byte allocator,
// which is wrapped in a simple_allocator. this is crap.
typedef char _Char[1];
typedef gc_allocator<_Char> gc_map_allocator;
#elif defined(_WIN32)
// FIXME: MSVC++'s notion. this is why we had to add _Charalloc().
typedef gc_allocator<JSValue> gc_map_allocator;
#endif
/**
* GC-scannable array of values.
*/
typedef std::vector<JSValue, gc_allocator<JSValue> > JSValues;
extern const JSValue kUndefinedValue;
extern const JSValue kNaNValue;
extern const JSValue kTrueValue;
extern const JSValue kFalseValue;
extern const JSValue kNullValue;
extern const JSValue kNegativeZero;
extern const JSValue kPositiveZero;
extern const JSValue kNegativeInfinity;
extern const JSValue kPositiveInfinity;
extern JSType Any_Type;
extern JSType Integer_Type;
extern JSType Number_Type;
extern JSType Character_Type;
extern JSType String_Type;
extern JSType Function_Type;
extern JSType Array_Type;
extern JSType Type_Type;
extern JSType Boolean_Type;
extern JSType Null_Type;
extern JSType Void_Type;
extern JSType None_Type;
typedef std::map<String, JSValue, std::less<String>, gc_map_allocator> JSProperties;
/**
* Basic behavior of all JS objects, mapping a name to a value,
* with prototype-based inheritance.
*/
class JSObject : public gc_base {
protected:
JSProperties mProperties;
JSObject* mPrototype;
JSType* mType;
JSString* mClass; // this is the internal [[Class]] property
static JSObject *initJSObject();
static String ObjectString;
static JSObject *objectPrototypeObject;
void init(JSObject* prototype);
public:
JSObject() { init(objectPrototypeObject); }
JSObject(JSValue &constructor) { init(constructor.object->getProperty(widenCString("prototype")).object); }
JSObject(JSObject *prototype) { init(prototype); }
static void initObjectObject(JSScope *g);
bool hasProperty(const String& name)
{
return (mProperties.count(name) != 0);
}
const JSValue& getProperty(const String& name)
{
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end())
return i->second;
if (mPrototype)
return mPrototype->getProperty(name);
return kUndefinedValue;
}
// return the property AND the object it's found in
// (would rather return references, but couldn't get that to work)
const JSValue getReference(JSValue &prop, const String& name)
{
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end()) {
prop = i->second;
return JSValue(this);
}
if (mPrototype)
return mPrototype->getReference(prop, name);
return kUndefinedValue;
}
JSValue& setProperty(const String& name, const JSValue& value)
{
return (mProperties[name] = value);
}
const JSValue& deleteProperty(const String& name)
{
JSProperties::iterator i = mProperties.find(name);
if (i != mProperties.end()) {
mProperties.erase(i);
return kTrueValue;
}
if (mPrototype)
return mPrototype->deleteProperty(name);
return kFalseValue;
}
void setPrototype(JSObject* prototype)
{
mPrototype = prototype;
}
JSObject* getPrototype()
{
return mPrototype;
}
JSType* getType()
{
return mType;
}
JSString* getClass()
{
return mClass;
}
void setClass(JSString* s)
{
mClass = s;
}
virtual void printProperties(Formatter& f);
};
Formatter& operator<<(Formatter& f, JSObject& obj);
/**
* Private representation of a JavaScript array.
*/
class JSArray : public JSObject {
JSValues elements;
public:
JSArray() : elements(1) {}
JSArray(uint32 size) : elements(size) {}
JSArray(const JSValues &v) : elements(v) {}
uint32 length()
{
return elements.size();
}
JSValue& operator[](const JSValue& index)
{
// for now, we can only handle f64 index values.
uint32 n = (uint32)index.f64;
// obviously, a sparse representation might be better.
uint32 size = elements.size();
if (n >= size) expand(n, size);
return elements[n];
}
JSValue& operator[](uint32 n)
{
// obviously, a sparse representation might be better.
uint32 size = elements.size();
if (n >= size) expand(n, size);
return elements[n];
}
void resize(uint32 size)
{
elements.resize(size);
}
private:
void expand(uint32 n, uint32 size)
{
do {
size *= 2;
} while (n >= size);
elements.resize(size);
}
};
/**
* Private representation of a JS function. This simply
* holds a reference to the iCode module that is the
* compiled code of the function.
*/
class JSFunction : public JSObject {
static String FunctionString;
static JSObject *functionPrototypeObject;
ICodeModule* mICode;
protected:
JSFunction() : mICode(0) {}
typedef JavaScript::gc_traits_finalizable<JSFunction> traits;
typedef gc_allocator<JSFunction, traits> allocator;
public:
static void JSFunction::initFunctionObject(JSScope *g);
JSFunction(ICodeModule* iCode);
~JSFunction();
void* operator new(size_t) { return allocator::allocate(1); }
ICodeModule* getICode() { return mICode; }
virtual bool isNative() { return false; }
};
class JSNativeFunction : public JSFunction {
public:
typedef JSValue (*JSCode)(Context *cx, const JSValues& argv);
JSCode mCode;
JSNativeFunction(JSCode code) : mCode(code) {}
virtual bool isNative() { return true; }
};
class JSBinaryOperator : public JSFunction {
public:
typedef JSValue (*JSBinaryCode)(const JSValue& arg1, const JSValue& arg2);
JSBinaryCode mCode;
JSBinaryOperator(JSBinaryCode code) : mCode(code) {}
virtual bool isNative() { return true; }
};
#ifndef STLPORT
# if defined(XP_UNIX)
// bastring.cc defines a funky operator new that assumes a byte-allocator.
typedef string_char_traits<char16> JSCharTraits;
typedef gc_allocator<_Char> JSStringAllocator;
# else
typedef std::char_traits<char16> JSCharTraits;
typedef gc_allocator<char16> JSStringAllocator;
# endif
#else
typedef std::char_traits<char16> JSCharTraits;
typedef gc_allocator<char16> JSStringAllocator;
#endif
typedef std::basic_string<char16, JSCharTraits, JSStringAllocator> JSStringBase;
/**
* Garbage collectable UNICODE string.
*/
class JSString : public JSStringBase, public gc_base {
public:
JSString() {}
explicit JSString(const JSStringBase& str) : JSStringBase(str) {}
explicit JSString(const JSStringBase* str) : JSStringBase(*str) {}
explicit JSString(const String& str);
explicit JSString(const String* str);
explicit JSString(const char* str);
operator String();
void append(const char* str);
void append(const JSStringBase* str);
};
class JSException : public gc_base {
public:
JSException(char *mess) : value(JSValue(new JSString(mess))) { }
JSException(JSValue v) : value(v) { }
JSValue value;
};
inline Formatter& operator<<(Formatter& f, const JSString& str)
{
printString(f, str.begin(), str.end());
return f;
}
/**
* Provides a set of nested scopes.
*/
class JSScope : public JSObject {
protected:
JSScope* mParent;
JSProperties mTypes;
public:
JSScope(JSScope* parent = 0, JSObject* prototype = 0)
: mParent(parent)
{
if (prototype)
setPrototype(prototype);
}
JSScope* getParent()
{
return mParent;
}
bool isDefined(const String& name)
{
if (hasProperty(name))
return true;
if (mParent)
return mParent->isDefined(name);
return false;
}
const JSValue& getVariable(const String& name)
{
const JSValue& ret = getProperty(name);
if (ret.isUndefined() && mParent)
return mParent->getVariable(name);
return ret;
}
JSValue& setVariable(const String& name, const JSValue& value)
{
return (mProperties[name] = value);
}
JSValue& defineVariable(const String& name, JSType* type, const JSValue& value)
{
if (type != &Any_Type)
mTypes[name] = type;
return (mProperties[name] = value);
}
JSValue& defineVariable(const String& name, JSType* type)
{
if (type != &Any_Type)
mTypes[name] = type;
return (mProperties[name] = kUndefinedValue);
}
void setType(const String& name, JSType* type)
{
// only type variables that are defined in this scope.
JSProperties::iterator i = mProperties.find(name);
if (i != mProperties.end())
mTypes[name] = type;
else
if (mParent)
mParent->setType(name, type);
}
JSType* getType(const String& name)
{
JSType* result = &Any_Type;
// only consider types for variables defined in this scope.
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end()) {
i = mTypes.find(name);
if (i != mTypes.end())
result = i->second.type;
} else {
// see if variable is defined in parent scope.
if (mParent)
result = mParent->getType(name);
}
return result;
}
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value(new JSFunction(iCode));
return defineVariable(name, &Function_Type, value);
}
JSValue& defineNativeFunction(const String& name, JSNativeFunction::JSCode code)
{
JSValue value(new JSNativeFunction(code));
return defineVariable(name, &Function_Type, value);
}
};
class JSType : public JSObject {
protected:
String mName;
JSType *mBaseType;
public:
JSType(const String &name, JSType *baseType) : mName(name), mBaseType(baseType)
{
mType = &Type_Type;
}
enum { NoRelation = 0x7FFFFFFF };
const String& getName() const { return mName; }
int32 distance(const JSType *other) const;
};
inline void JSObject::init(JSObject* prototype) { mPrototype = prototype; mType = &Any_Type; mClass = new JSString(ObjectString); }
inline JSFunction::JSFunction(ICodeModule* iCode) : mICode(iCode), JSObject(functionPrototypeObject) { setClass(new JSString(FunctionString)); }
} /* namespace JSTypes */
} /* namespace JavaScript */
#endif /* jstypes_h */

Binary file not shown.

Binary file not shown.

View File

@@ -1 +0,0 @@
#define XP_MAC 1

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
#define XP_MAC 1
#define DEBUG 1

View File

@@ -1,2 +0,0 @@
#define XP_MAC 1
#define XP_MAC_MPW 1

Some files were not shown because too many files have changed in this diff Show More