Compare commits
2 Commits
XMLTO_Docu
...
regalloc_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c43d4984f | ||
|
|
cfe021ff88 |
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal file
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal 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
|
||||
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal file
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal 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
|
||||
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal file
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal 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_
|
||||
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal file
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal 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
|
||||
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal file
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal 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));
|
||||
}
|
||||
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal file
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal 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
|
||||
|
||||
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal 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_
|
||||
20
mozilla/ef/Compiler/RegisterAllocator/HashSet.cpp
Normal file
20
mozilla/ef/Compiler/RegisterAllocator/HashSet.cpp
Normal 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"
|
||||
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal file
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal 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_
|
||||
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal file
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal 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_
|
||||
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal file
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal 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_
|
||||
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal file
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal 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_
|
||||
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal file
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal 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_
|
||||
21
mozilla/ef/Compiler/RegisterAllocator/Liveness.cpp
Normal file
21
mozilla/ef/Compiler/RegisterAllocator/Liveness.cpp
Normal 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"
|
||||
|
||||
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal file
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal 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_
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal 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)
|
||||
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal file
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal 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_
|
||||
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal file
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal 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;
|
||||
}
|
||||
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal file
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal 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_
|
||||
|
||||
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal file
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal 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
|
||||
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal file
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal 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_
|
||||
38
mozilla/ef/Compiler/RegisterAllocator/RegisterAssigner.h
Normal file
38
mozilla/ef/Compiler/RegisterAllocator/RegisterAssigner.h
Normal 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_ */
|
||||
25
mozilla/ef/Compiler/RegisterAllocator/RegisterClass.h
Normal file
25
mozilla/ef/Compiler/RegisterAllocator/RegisterClass.h
Normal 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_
|
||||
37
mozilla/ef/Compiler/RegisterAllocator/RegisterPressure.h
Normal file
37
mozilla/ef/Compiler/RegisterAllocator/RegisterPressure.h
Normal 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_
|
||||
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal file
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal 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_
|
||||
32
mozilla/ef/Compiler/RegisterAllocator/SSATools.cpp
Normal file
32
mozilla/ef/Compiler/RegisterAllocator/SSATools.cpp
Normal 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);
|
||||
}
|
||||
29
mozilla/ef/Compiler/RegisterAllocator/SSATools.h
Normal file
29
mozilla/ef/Compiler/RegisterAllocator/SSATools.h
Normal 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_
|
||||
37
mozilla/ef/Compiler/RegisterAllocator/SparseSet.cpp
Normal file
37
mozilla/ef/Compiler/RegisterAllocator/SparseSet.cpp
Normal 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
|
||||
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal file
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal 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_
|
||||
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal file
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal 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
|
||||
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal file
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal 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_
|
||||
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal file
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal 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_
|
||||
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal file
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal 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();
|
||||
}
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal 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_ */
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.cpp
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.cpp
Normal 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;
|
||||
}
|
||||
|
||||
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal file
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal 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 ®A == ®B;}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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_
|
||||
@@ -1,135 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
|
||||
]>
|
||||
|
||||
|
||||
<!-- Coding standards for this document
|
||||
|
||||
* Other than the GFDL, please use the "section" tag instead of "sect1",
|
||||
"sect2", etc.
|
||||
* Use Entities to include files for new chapters in Bugzilla-Guide.xml.
|
||||
* Try to use Entities for frequently-used passages of text as well.
|
||||
* Ensure all documents compile cleanly to HTML after modification.
|
||||
The warning, "DTDDECL catalog types not supported" is normal.
|
||||
* Try to index important terms wherever possible.
|
||||
* Use "glossterm" whenever you introduce a new term.
|
||||
* Follow coding standards at http://www.tldp.org, and
|
||||
check out the KDE guidelines (they are nice, too)
|
||||
http://i18n.kde.org/doc/markup.html
|
||||
* All tags should be lowercase.
|
||||
* Please use sensible spacing. The comments at the very end of each
|
||||
file define reasonable defaults for PSGML mode in EMACS.
|
||||
* Double-indent tags, use double spacing whenever possible, and
|
||||
try to avoid clutter and feel free to waste space in the code to make it
|
||||
more readable.
|
||||
|
||||
-->
|
||||
|
||||
<book id="index">
|
||||
|
||||
<!-- Header -->
|
||||
|
||||
<bookinfo>
|
||||
<title>The Bugzilla Guide - &bz-ver;
|
||||
<!-- BZ-DEVEL -->Development <!-- /BZ-DEVEL -->
|
||||
Release</title>
|
||||
|
||||
<authorgroup>
|
||||
<corpauthor>The Bugzilla Team</corpauthor>
|
||||
</authorgroup>
|
||||
|
||||
<pubdate>&bz-date;</pubdate>
|
||||
|
||||
<abstract>
|
||||
<para>
|
||||
This is the documentation for Bugzilla, a
|
||||
bug-tracking system from mozilla.org.
|
||||
Bugzilla is an enterprise-class piece of software
|
||||
that tracks millions of bugs and issues for hundreds of
|
||||
organizations around the world.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The most current version of this document can always be found on the
|
||||
<ulink url="http://www.bugzilla.org/docs/">Bugzilla
|
||||
Documentation Page</ulink>.
|
||||
</para>
|
||||
|
||||
</abstract>
|
||||
|
||||
<keywordset>
|
||||
<keyword>Bugzilla</keyword>
|
||||
<keyword>Guide</keyword>
|
||||
<keyword>installation</keyword>
|
||||
<keyword>FAQ</keyword>
|
||||
<keyword>administration</keyword>
|
||||
<keyword>integration</keyword>
|
||||
<keyword>MySQL</keyword>
|
||||
<keyword>Mozilla</keyword>
|
||||
<keyword>webtools</keyword>
|
||||
</keywordset>
|
||||
</bookinfo>
|
||||
|
||||
<!-- About This Guide -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="about.xml" />
|
||||
|
||||
<!-- Installing Bugzilla -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="installation.xml" />
|
||||
|
||||
<!-- Administering Bugzilla -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="administration.xml" />
|
||||
|
||||
<!-- Securing Bugzilla -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="security.xml" />
|
||||
|
||||
<!-- Customizing Bugzilla -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="customization.xml" />
|
||||
|
||||
<!-- Using Bugzilla -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="using.xml" />
|
||||
|
||||
<!-- Appendix: Troubleshooting -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="troubleshooting.xml" />
|
||||
|
||||
<!-- Appendix: Custom Patches -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="patches.xml" />
|
||||
|
||||
<!-- Appendix: Manually Installing Perl Modules -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="modules.xml" />
|
||||
|
||||
<!-- Appendix: GNU Free Documentation License -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="gfdl.xml" />
|
||||
|
||||
<!-- Glossary -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="glossary.xml" />
|
||||
|
||||
<!-- Index -->
|
||||
<!--xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="index.xml" /-->
|
||||
|
||||
</book>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<!-- $Id: about.xml,v 1.26.4.1 2008-07-13 16:44:28 mozilla%colinogilvie.co.uk Exp $ -->
|
||||
|
||||
<chapter id="about">
|
||||
<title>About This Guide</title>
|
||||
|
||||
<section id="copyright">
|
||||
<title>Copyright Information</title>
|
||||
|
||||
<para>This document is copyright (c) 2000-¤t-year; by the various
|
||||
Bugzilla contributors who wrote it.</para>
|
||||
|
||||
<blockquote>
|
||||
<para>
|
||||
Permission is granted to copy, distribute and/or modify this
|
||||
document under the terms of the GNU Free Documentation
|
||||
License, Version 1.1 or any later version published by the
|
||||
Free Software Foundation; with no Invariant Sections, no
|
||||
Front-Cover Texts, and with no Back-Cover Texts. A copy of
|
||||
the license is included in <xref linkend="gfdl"/>.
|
||||
</para>
|
||||
</blockquote>
|
||||
<para>
|
||||
If you have any questions regarding this document, its
|
||||
copyright, or publishing this document in non-electronic form,
|
||||
please contact the Bugzilla Team.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="disclaimer">
|
||||
<title>Disclaimer</title>
|
||||
<para>
|
||||
No liability for the contents of this document can be accepted.
|
||||
Follow the instructions herein at your own risk.
|
||||
This document may contain errors
|
||||
and inaccuracies that may damage your system, cause your partner
|
||||
to leave you, your boss to fire you, your cats to
|
||||
pee on your furniture and clothing, and global thermonuclear
|
||||
war. Proceed with caution.
|
||||
</para>
|
||||
<para>
|
||||
Naming of particular products or brands should not be seen as
|
||||
endorsements, with the exception of the term "GNU/Linux". We
|
||||
wholeheartedly endorse the use of GNU/Linux; it is an extremely
|
||||
versatile, stable,
|
||||
and robust operating system that offers an ideal operating
|
||||
environment for Bugzilla.
|
||||
</para>
|
||||
<para>
|
||||
Although the Bugzilla development team has taken great care to
|
||||
ensure that all exploitable bugs have been fixed, security holes surely
|
||||
exist in any piece of code. Great care should be taken both in
|
||||
the installation and usage of this software. The Bugzilla development
|
||||
team members assume no liability for your use of Bugzilla. You have
|
||||
the source code, and are responsible for auditing it yourself to ensure
|
||||
your security needs are met.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<!-- Section 2: New Versions -->
|
||||
|
||||
<section id="newversions">
|
||||
<title>New Versions</title>
|
||||
<para>
|
||||
This is the &bz-ver; version of The Bugzilla Guide. It is so named
|
||||
to match the current version of Bugzilla.
|
||||
<!-- BZ-DEVEL --> This version of the guide, like its associated Bugzilla version, is a
|
||||
development version.<!-- /BZ-DEVEL -->
|
||||
</para>
|
||||
<para>
|
||||
The latest version of this guide can always be found at <ulink
|
||||
url="http://www.bugzilla.org"/>, or checked out via CVS by
|
||||
following the <ulink url="http://www.mozilla.org/cvs.html">Mozilla
|
||||
CVS</ulink> instructions and check out the
|
||||
<filename>mozilla/webtools/bugzilla/docs/</filename>
|
||||
subtree. However, you should read the version
|
||||
which came with the Bugzilla release you are using.
|
||||
</para>
|
||||
<para>
|
||||
The Bugzilla Guide, or a section of it, is also available in
|
||||
the following languages:
|
||||
<ulink url="http://www.traduc.org/docs/guides/lecture/bugzilla/">French</ulink>,
|
||||
<ulink url="http://bugzilla-de.sourceforge.net/docs/html/">German</ulink>,
|
||||
<ulink url="http://www.bugzilla.jp/docs/2.18/">Japanese</ulink>.
|
||||
Note that these may be outdated or not up to date.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In addition, there are Bugzilla template localization projects in
|
||||
the following languages. They may have translated documentation
|
||||
available:
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-ar/">Arabic</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-be/">Belarusian</ulink>,
|
||||
<ulink url="http://openfmi.net/projects/mozilla-bg/">Bulgarian</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-br/">Brazilian Portuguese</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-cn/">Chinese</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-fr/">French</ulink>,
|
||||
<ulink url="http://germzilla.ganderbay.net/">German</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-it/">Italian</ulink>,
|
||||
<ulink url="http://www.bugzilla.jp/about/jp.html">Japanese</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-kr/">Korean</ulink>,
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-ru/">Russian</ulink> and
|
||||
<ulink url="http://sourceforge.net/projects/bugzilla-es/">Spanish</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you would like to volunteer to translate the Guide into additional
|
||||
languages, please contact
|
||||
<ulink url="mailto:justdave@bugzilla.org">Dave Miller</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="credits">
|
||||
<title>Credits</title>
|
||||
<para>
|
||||
The people listed below have made enormous contributions to the
|
||||
creation of this Guide, through their writing, dedicated hacking efforts,
|
||||
numerous e-mail and IRC support sessions, and overall excellent
|
||||
contribution to the Bugzilla community:
|
||||
</para>
|
||||
|
||||
<!-- TODO: This is evil... there has to be a valid way to get this look -->
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Matthew P. Barnson <email>mbarnson@sisna.com</email></term>
|
||||
<listitem>
|
||||
<para>for the Herculean task of pulling together the Bugzilla Guide
|
||||
and shepherding it to 2.14.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Terry Weissman <email>terry@mozilla.org</email></term>
|
||||
<listitem>
|
||||
<para>for initially writing Bugzilla and creating the README upon
|
||||
which the UNIX installation documentation is largely based.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Tara Hernandez <email>tara@tequilarists.org</email></term>
|
||||
<listitem>
|
||||
<para>for keeping Bugzilla development going strong after Terry left
|
||||
mozilla.org and for running landfill.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Dave Lawrence <email>dkl@redhat.com</email></term>
|
||||
<listitem>
|
||||
<para>for providing insight into the key differences between Red
|
||||
Hat's customized Bugzilla.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Dawn Endico <email>endico@mozilla.org</email></term>
|
||||
<listitem>
|
||||
<para>for being a hacker extraordinaire and putting up with Matthew's
|
||||
incessant questions and arguments on irc.mozilla.org in #mozwebtools
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Jacob Steenhagen <email>jake@bugzilla.org</email></term>
|
||||
<listitem>
|
||||
<para>for taking over documentation during the 2.17 development
|
||||
period.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Dave Miller <email>justdave@bugzilla.org</email></term>
|
||||
<listitem>
|
||||
<para>for taking over as project lead when Tara stepped down and
|
||||
continually pushing for the documentation to be the best it can be.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
|
||||
<para>
|
||||
Thanks also go to the following people for significant contributions
|
||||
to this documentation:
|
||||
<simplelist type="inline">
|
||||
<member>Kevin Brannen</member>
|
||||
<member>Vlad Dascalu</member>
|
||||
<member>Ben FrantzDale</member>
|
||||
<member>Eric Hanson</member>
|
||||
<member>Zach Lipton</member>
|
||||
<member>Gervase Markham</member>
|
||||
<member>Andrew Pearson</member>
|
||||
<member>Joe Robins</member>
|
||||
<member>Spencer Smith</member>
|
||||
<member>Ron Teitelbaum</member>
|
||||
<member>Shane Travis</member>
|
||||
<member>Martin Wulffeld</member>
|
||||
</simplelist>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Also, thanks are due to the members of the
|
||||
<ulink url="news://news.mozilla.org/mozilla.support.bugzilla">
|
||||
mozilla.support.bugzilla</ulink>
|
||||
newsgroup (and its predecessor, netscape.public.mozilla.webtools).
|
||||
Without your discussions, insight, suggestions, and patches,
|
||||
this could never have happened.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<!-- conventions used here (didn't want to give it a chapter of its own) -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="conventions.xml" />
|
||||
</chapter>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End: -->
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,168 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<section id="conventions">
|
||||
<title>Document Conventions</title>
|
||||
|
||||
<indexterm zone="conventions">
|
||||
<primary>conventions</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>This document uses the following conventions:</para>
|
||||
|
||||
<informaltable frame="none">
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Descriptions</entry>
|
||||
|
||||
<entry>Appearance</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Caution</entry>
|
||||
|
||||
<entry>
|
||||
<caution>
|
||||
<para>Don't run with scissors!</para>
|
||||
</caution>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Hint or Tip</entry>
|
||||
|
||||
<entry>
|
||||
<tip>
|
||||
<para>For best results... </para>
|
||||
</tip>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Note</entry>
|
||||
|
||||
<entry>
|
||||
<note>
|
||||
<para>Dear John...</para>
|
||||
</note>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Warning</entry>
|
||||
|
||||
<entry>
|
||||
<warning>
|
||||
<para>Read this or the cat gets it.</para>
|
||||
</warning>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>File or directory name</entry>
|
||||
|
||||
<entry>
|
||||
<filename>filename</filename>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Command to be typed</entry>
|
||||
|
||||
<entry>
|
||||
<command>command</command>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Application name</entry>
|
||||
|
||||
<entry>
|
||||
<application>application</application>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
Normal user's prompt under bash shell</entry>
|
||||
|
||||
<entry>bash$</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
Root user's prompt under bash shell</entry>
|
||||
|
||||
<entry>bash#</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>
|
||||
Normal user's prompt under tcsh shell</entry>
|
||||
|
||||
<entry>tcsh$</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Environment variables</entry>
|
||||
|
||||
<entry>
|
||||
<envar>VARIABLE</envar>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Term found in the glossary</entry>
|
||||
|
||||
<entry>
|
||||
<glossterm linkend="gloss-bugzilla">Bugzilla</glossterm>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Code example</entry>
|
||||
|
||||
<entry>
|
||||
<programlisting><sgmltag class="starttag">para</sgmltag>
|
||||
Beginning and end of paragraph
|
||||
<sgmltag class="endtag">para</sgmltag></programlisting>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<para>
|
||||
This documentation is maintained in DocBook 4.1.2 XML format.
|
||||
Changes are best submitted as plain text or XML diffs, attached
|
||||
to a bug filed in the &bzg-bugs; component.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,821 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<chapter id="customization">
|
||||
<title>Customizing Bugzilla</title>
|
||||
|
||||
<section id="cust-skins">
|
||||
<title>Custom Skins</title>
|
||||
|
||||
<para>
|
||||
Bugzilla allows you to have multiple skins. These are custom CSS and possibly
|
||||
also custom images for Bugzilla. To create a new custom skin, you have two
|
||||
choices:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Make a single CSS file, and put it in the
|
||||
<filename>skins/contrib</filename> directory.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Make a directory that contains all the same CSS file
|
||||
names as <filename>skins/standard/</filename>, and put
|
||||
your directory in <filename>skins/contrib/</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
After you put the file or the directory there, make sure to run checksetup.pl
|
||||
so that it can reset the file permissions correctly.
|
||||
</para>
|
||||
<para>
|
||||
After you have installed the new skin, it will show up as an option in the
|
||||
user's General Preferences. If you would like to force a particular skin on all
|
||||
users, just select it in the Default Preferences and then uncheck "Enabled" on
|
||||
the preference.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="cust-templates">
|
||||
<title>Template Customization</title>
|
||||
|
||||
<para>
|
||||
Administrators can configure the look and feel of Bugzilla without
|
||||
having to edit Perl files or face the nightmare of massive merge
|
||||
conflicts when they upgrade to a newer version in the future.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Templatization also makes localized versions of Bugzilla possible,
|
||||
for the first time. It's possible to have Bugzilla's UI language
|
||||
determined by the user's browser. More information is available in
|
||||
<xref linkend="template-http-accept"/>.
|
||||
</para>
|
||||
|
||||
<section id="template-directory">
|
||||
<title>Template Directory Structure</title>
|
||||
<para>
|
||||
The template directory structure starts with top level directory
|
||||
named <filename>template</filename>, which contains a directory
|
||||
for each installed localization. The next level defines the
|
||||
language used in the templates. Bugzilla comes with English
|
||||
templates, so the directory name is <filename>en</filename>,
|
||||
and we will discuss <filename>template/en</filename> throughout
|
||||
the documentation. Below <filename>template/en</filename> is the
|
||||
<filename>default</filename> directory, which contains all the
|
||||
standard templates shipped with Bugzilla.
|
||||
</para>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
A directory <filename>data/templates</filename> also exists;
|
||||
this is where Template Toolkit puts the compiled versions of
|
||||
the templates from either the default or custom directories.
|
||||
<emphasis>Do not</emphasis> directly edit the files in this
|
||||
directory, or all your changes will be lost the next time
|
||||
Template Toolkit recompiles the templates.
|
||||
</para>
|
||||
</warning>
|
||||
</section>
|
||||
|
||||
<section id="template-method">
|
||||
<title>Choosing a Customization Method</title>
|
||||
<para>
|
||||
If you want to edit Bugzilla's templates, the first decision
|
||||
you must make is how you want to go about doing so. There are two
|
||||
choices, and which you use depends mainly on the scope of your
|
||||
modifications, and the method you plan to use to upgrade Bugzilla.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The first method of making customizations is to directly edit the
|
||||
templates found in <filename>template/en/default</filename>.
|
||||
This is probably the best way to go about it if you are going to
|
||||
be upgrading Bugzilla through CVS, because if you then execute
|
||||
a <command>cvs update</command>, any changes you have made will
|
||||
be merged automagically with the updated versions.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If you use this method, and CVS conflicts occur during an
|
||||
update, the conflicted templates (and possibly other parts
|
||||
of your installation) will not work until they are resolved.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The second method is to copy the templates to be modified
|
||||
into a mirrored directory structure under
|
||||
<filename>template/en/custom</filename>. Templates in this
|
||||
directory structure automatically override any identically-named
|
||||
and identically-located templates in the
|
||||
<filename>default</filename> directory.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
The <filename>custom</filename> directory does not exist
|
||||
at first and must be created if you want to use it.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The second method of customization should be used if you
|
||||
use the overwriting method of upgrade, because otherwise
|
||||
your changes will be lost. This method may also be better if
|
||||
you are using the CVS method of upgrading and are going to make major
|
||||
changes, because it is guaranteed that the contents of this directory
|
||||
will not be touched during an upgrade, and you can then decide whether
|
||||
to continue using your own templates, or make the effort to merge your
|
||||
changes into the new versions by hand.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Using this method, your installation may break if incompatible
|
||||
changes are made to the template interface. Such changes should
|
||||
be documented in the release notes, provided you are using a
|
||||
stable release of Bugzilla. If you use using unstable code, you will
|
||||
need to deal with this one yourself, although if possible the changes
|
||||
will be mentioned before they occur in the deprecations section of the
|
||||
previous stable release's release notes.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Regardless of which method you choose, it is recommended that
|
||||
you run <command>./checksetup.pl</command> after creating or
|
||||
editing any templates in the <filename>template/en/default</filename>
|
||||
directory, and after editing any templates in the
|
||||
<filename>custom</filename> directory.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
It is <emphasis>required</emphasis> that you run
|
||||
<command>./checksetup.pl</command> after creating a new
|
||||
template in the <filename>custom</filename> directory. Failure
|
||||
to do so will raise an incomprehensible error message.
|
||||
</para>
|
||||
</warning>
|
||||
</section>
|
||||
|
||||
<section id="template-edit">
|
||||
<title>How To Edit Templates</title>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
If you are making template changes that you intend on submitting back
|
||||
for inclusion in standard Bugzilla, you should read the relevant
|
||||
sections of the
|
||||
<ulink url="http://www.bugzilla.org/docs/developer.html">Developers'
|
||||
Guide</ulink>.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The syntax of the Template Toolkit language is beyond the scope of
|
||||
this guide. It's reasonably easy to pick up by looking at the current
|
||||
templates; or, you can read the manual, available on the
|
||||
<ulink url="http://www.template-toolkit.org">Template Toolkit home
|
||||
page</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
One thing you should take particular care about is the need
|
||||
to properly HTML filter data that has been passed into the template.
|
||||
This means that if the data can possibly contain special HTML characters
|
||||
such as <, and the data was not intended to be HTML, they need to be
|
||||
converted to entity form, i.e. &lt;. You use the 'html' filter in the
|
||||
Template Toolkit to do this. If you forget, you may open up
|
||||
your installation to cross-site scripting attacks.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Also note that Bugzilla adds a few filters of its own, that are not
|
||||
in standard Template Toolkit. In particular, the 'url_quote' filter
|
||||
can convert characters that are illegal or have special meaning in URLs,
|
||||
such as &, to the encoded form, i.e. %26. This actually encodes most
|
||||
characters (but not the common ones such as letters and numbers and so
|
||||
on), including the HTML-special characters, so there's never a need to
|
||||
HTML filter afterwards.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Editing templates is a good way of doing a <quote>poor man's custom
|
||||
fields</quote>.
|
||||
For example, if you don't use the Status Whiteboard, but want to have
|
||||
a free-form text entry box for <quote>Build Identifier</quote>,
|
||||
then you can just
|
||||
edit the templates to change the field labels. It's still be called
|
||||
status_whiteboard internally, but your users don't need to know that.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section id="template-formats">
|
||||
<title>Template Formats and Types</title>
|
||||
|
||||
<para>
|
||||
Some CGI's have the ability to use more than one template. For example,
|
||||
<filename>buglist.cgi</filename> can output itself as RDF, or as two
|
||||
formats of HTML (complex and simple). The mechanism that provides this
|
||||
feature is extensible.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Bugzilla can support different types of output, which again can have
|
||||
multiple formats. In order to request a certain type, you can append
|
||||
the &ctype=<contenttype> (such as rdf or html) to the
|
||||
<filename><cginame>.cgi</filename> URL. If you would like to
|
||||
retrieve a certain format, you can use the &format=<format>
|
||||
(such as simple or complex) in the URL.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To see if a CGI supports multiple output formats and types, grep the
|
||||
CGI for <quote>get_format</quote>. If it's not present, adding
|
||||
multiple format/type support isn't too hard - see how it's done in
|
||||
other CGIs, e.g. config.cgi.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To make a new format template for a CGI which supports this,
|
||||
open a current template for
|
||||
that CGI and take note of the INTERFACE comment (if present.) This
|
||||
comment defines what variables are passed into this template. If
|
||||
there isn't one, I'm afraid you'll have to read the template and
|
||||
the code to find out what information you get.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Write your template in whatever markup or text style is appropriate.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You now need to decide what content type you want your template
|
||||
served as. The content types are defined in the
|
||||
<filename>Bugzilla/Constants.pm</filename> file in the
|
||||
<filename>contenttypes</filename>
|
||||
constant. If your content type is not there, add it. Remember
|
||||
the three- or four-letter tag assigned to your content type.
|
||||
This tag will be part of the template filename.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
After adding or changing a content type, it's suitable to edit
|
||||
<filename>Bugzilla/Constants.pm</filename> in order to reflect
|
||||
the changes. Also, the file should be kept up to date after an
|
||||
upgrade if content types have been customized in the past.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
Save the template as <filename><stubname>-<formatname>.<contenttypetag>.tmpl</filename>.
|
||||
Try out the template by calling the CGI as
|
||||
<filename><cginame>.cgi?format=<formatname>&ctype=<type></filename> .
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="template-specific">
|
||||
<title>Particular Templates</title>
|
||||
|
||||
<para>
|
||||
There are a few templates you may be particularly interested in
|
||||
customizing for your installation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>index.html.tmpl</command>:
|
||||
This is the Bugzilla front page.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>global/header.html.tmpl</command>:
|
||||
This defines the header that goes on all Bugzilla pages.
|
||||
The header includes the banner, which is what appears to users
|
||||
and is probably what you want to edit instead. However the
|
||||
header also includes the HTML HEAD section, so you could for
|
||||
example add a stylesheet or META tag by editing the header.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>global/banner.html.tmpl</command>:
|
||||
This contains the <quote>banner</quote>, the part of the header
|
||||
that appears
|
||||
at the top of all Bugzilla pages. The default banner is reasonably
|
||||
barren, so you'll probably want to customize this to give your
|
||||
installation a distinctive look and feel. It is recommended you
|
||||
preserve the Bugzilla version number in some form so the version
|
||||
you are running can be determined, and users know what docs to read.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>global/footer.html.tmpl</command>:
|
||||
This defines the footer that goes on all Bugzilla pages. Editing
|
||||
this is another way to quickly get a distinctive look and feel for
|
||||
your Bugzilla installation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>global/variables.none.tmpl</command>:
|
||||
This defines a list of terms that may be changed in order to
|
||||
<quote>brand</quote> the Bugzilla instance In this way, terms
|
||||
like <quote>bugs</quote> can be replaced with <quote>issues</quote>
|
||||
across the whole Bugzilla installation. The name
|
||||
<quote>Bugzilla</quote> and other words can be customized as well.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>list/table.html.tmpl</command>:
|
||||
This template controls the appearance of the bug lists created
|
||||
by Bugzilla. Editing this template allows per-column control of
|
||||
the width and title of a column, the maximum display length of
|
||||
each entry, and the wrap behaviour of long entries.
|
||||
For long bug lists, Bugzilla inserts a 'break' every 100 bugs by
|
||||
default; this behaviour is also controlled by this template, and
|
||||
that value can be modified here.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>bug/create/user-message.html.tmpl</command>:
|
||||
This is a message that appears near the top of the bug reporting page.
|
||||
By modifying this, you can tell your users how they should report
|
||||
bugs.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>bug/process/midair.html.tmpl</command>:
|
||||
This is the page used if two people submit simultaneous changes to the
|
||||
same bug. The second person to submit their changes will get this page
|
||||
to tell them what the first person did, and ask if they wish to
|
||||
overwrite those changes or go back and revisit the bug. The default
|
||||
title and header on this page read "Mid-air collision detected!" If
|
||||
you work in the aviation industry, or other environment where this
|
||||
might be found offensive (yes, we have true stories of this happening)
|
||||
you'll want to change this to something more appropriate for your
|
||||
environment.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>bug/create/create.html.tmpl</command> and
|
||||
<command>bug/create/comment.txt.tmpl</command>:
|
||||
You may not wish to go to the effort of creating custom fields in
|
||||
Bugzilla, yet you want to make sure that each bug report contains
|
||||
a number of pieces of important information for which there is not
|
||||
a special field. The bug entry system has been designed in an
|
||||
extensible fashion to enable you to add arbitrary HTML widgets,
|
||||
such as drop-down lists or textboxes, to the bug entry page
|
||||
and have their values appear formatted in the initial comment.
|
||||
A hidden field that indicates the format should be added inside
|
||||
the form in order to make the template functional. Its value should
|
||||
be the suffix of the template filename. For example, if the file
|
||||
is called <filename>create-cust.html.tmpl</filename>, then
|
||||
<programlisting><input type="hidden" name="format" value="cust"></programlisting>
|
||||
should be used inside the form.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An example of this is the mozilla.org
|
||||
<ulink url="http://landfill.bugzilla.org/bugzilla-tip/enter_bug.cgi?product=WorldControl&format=guided">guided
|
||||
bug submission form</ulink>. The code for this comes with the Bugzilla
|
||||
distribution as an example for you to copy. It can be found in the
|
||||
files
|
||||
<filename>create-guided.html.tmpl</filename> and
|
||||
<filename>comment-guided.html.tmpl</filename>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
So to use this feature, create a custom template for
|
||||
<filename>enter_bug.cgi</filename>. The default template, on which you
|
||||
could base it, is
|
||||
<filename>custom/bug/create/create.html.tmpl</filename>.
|
||||
Call it <filename>create-<formatname>.html.tmpl</filename>, and
|
||||
in it, add widgets for each piece of information you'd like
|
||||
collected - such as a build number, or set of steps to reproduce.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Then, create a template like
|
||||
<filename>custom/bug/create/comment.txt.tmpl</filename>, and call it
|
||||
<filename>comment-<formatname>.txt.tmpl</filename>. This
|
||||
template should reference the form fields you have created using
|
||||
the syntax <filename>[% form.<fieldname> %]</filename>. When a
|
||||
bug report is
|
||||
submitted, the initial comment attached to the bug report will be
|
||||
formatted according to the layout of this template.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For example, if your custom enter_bug template had a field
|
||||
<programlisting><input type="text" name="buildid" size="30"></programlisting>
|
||||
and then your comment.txt.tmpl had
|
||||
<programlisting>BuildID: [% form.buildid %]</programlisting>
|
||||
then something like
|
||||
<programlisting>BuildID: 20020303</programlisting>
|
||||
would appear in the initial comment.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="template-http-accept">
|
||||
<title>Configuring Bugzilla to Detect the User's Language</title>
|
||||
|
||||
<para>Bugzilla honours the user's Accept: HTTP header. You can install
|
||||
templates in other languages, and Bugzilla will pick the most appropriate
|
||||
according to a priority order defined by you. Many
|
||||
language templates can be obtained from <ulink
|
||||
url="http://www.bugzilla.org/download.html#localizations"/>. Instructions
|
||||
for submitting new languages are also available from that location.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="cust-hooks">
|
||||
<title>The Bugzilla Extension Mechanism</title>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
Note that the below paths are inconsistent and confusing. They will
|
||||
likely be changed in Bugzilla 4.0.
|
||||
</para>
|
||||
</warning>
|
||||
|
||||
<para>
|
||||
Extensions are a way for extensions to Bugzilla to insert code
|
||||
into the standard Bugzilla templates and source files
|
||||
without modifying these files themselves. The extension mechanism
|
||||
defines a consistent API for extending the standard templates and source files
|
||||
in a way that cleanly separates standard code from extension code.
|
||||
Hooks reduce merge conflicts and make it easier to write extensions that work
|
||||
across multiple versions of Bugzilla, making upgrading a Bugzilla installation
|
||||
with installed extensions easier. Furthermore, they make it easy to install
|
||||
and remove extensions as each extension is nothing more than a
|
||||
simple directory structure.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are two main types of hooks: code hooks and template hooks. Code
|
||||
hooks allow extensions to invoke code at specific points in various
|
||||
source files, while template hooks allow extensions to add elements to
|
||||
the Bugzilla user interface.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A hook is just a named place in a standard source or template file
|
||||
where extension source code or template files for that hook get processed.
|
||||
Each extension has a corresponding directory in the Bugzilla directory
|
||||
tree (<filename>BUGZILLA_ROOT/extensions/extension_name</filename>). Hooking
|
||||
an extension source file or template to a hook is as simple as putting
|
||||
the extension file into extension's template or code directory.
|
||||
When Bugzilla processes the source file or template and reaches the hook,
|
||||
it will process all extension files in the hook's directory.
|
||||
The hooks themselves can be added into any source file or standard template
|
||||
upon request by extension authors.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To use hooks to extend Bugzilla, first make sure there is
|
||||
a hook at the appropriate place within the source file or template you
|
||||
want to extend. The exact appearance of a hook depends on if the hook
|
||||
is a code hook or a template hook.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Code hooks appear in Bugzilla source files as a single method call
|
||||
in the format <literal role="code">Bugzilla::Hook->process("<varname>name</varname>");</literal>.
|
||||
For instance, <filename>enter_bug.cgi</filename> may invoke the hook
|
||||
"<varname>enter_bug-entrydefaultvars</varname>". Thus, a source file at
|
||||
<filename>BUGZILLA_ROOT/extensions/EXTENSION_NAME/code/enter_bug-entrydefaultvars.pl</filename>
|
||||
will be automatically invoked when the code hook is reached.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Template hooks appear in the standard Bugzilla templates as a
|
||||
single directive in the format
|
||||
<literal role="code">[% Hook.process("<varname>name</varname>") %]</literal>,
|
||||
where <varname>name</varname> is the unique name of the hook.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you aren't sure what you want to extend or just want to browse the
|
||||
available hooks, either use your favorite multi-file search
|
||||
tool (e.g. <command>grep</command>) to search the standard templates
|
||||
for occurrences of <methodname>Hook.process</methodname> or the source
|
||||
files for occurrences of <methodname>Bugzilla::Hook::process</methodname>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If there is no hook at the appropriate place within the Bugzilla
|
||||
source file or template you want to extend,
|
||||
<ulink url="http://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&component=User%20Interface">file
|
||||
a bug requesting one</ulink>, specifying:
|
||||
</para>
|
||||
|
||||
<simplelist>
|
||||
<member>the source or template file for which you are
|
||||
requesting a hook;</member>
|
||||
<member>
|
||||
where in the file you would like the hook to be placed
|
||||
(line number/position for latest version of the file in CVS
|
||||
or description of location);
|
||||
</member>
|
||||
<member>the purpose of the hook;</member>
|
||||
<member>a link to information about your extension, if any.</member>
|
||||
</simplelist>
|
||||
|
||||
<para>
|
||||
The Bugzilla reviewers will promptly review each hook request,
|
||||
name the hook, add it to the template or source file, and check
|
||||
the new version of the template into CVS.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You may optionally attach a patch to the bug which implements the hook
|
||||
and check it in yourself after receiving approval from a Bugzilla
|
||||
reviewer. The developers may suggest changes to the location of the
|
||||
hook based on their analysis of your needs or so the hook can satisfy
|
||||
the needs of multiple extensions, but the process of getting hooks
|
||||
approved and checked in is not as stringent as the process for general
|
||||
changes to Bugzilla, and any extension, whether released or still in
|
||||
development, can have hooks added to meet their needs.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
After making sure the hook you need exists (or getting it added if not),
|
||||
add your extension to the directory within the Bugzilla
|
||||
extensions tree corresponding to the hook.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
That's it! Now, when the source file or template containing the hook
|
||||
is processed, your extension file will be processed at the point
|
||||
where the hook appears.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For example, let's say you have an extension named Projman that adds
|
||||
project management capabilities to Bugzilla. Projman has an
|
||||
administration interface <filename>edit-projects.cgi</filename>,
|
||||
and you want to add a link to it into the navigation bar at the bottom
|
||||
of every Bugzilla page for those users who are authorized
|
||||
to administer projects.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The navigation bar is generated by the template file
|
||||
<filename>useful-links.html.tmpl</filename>, which is located in
|
||||
the <filename>global/</filename> subdirectory on the standard Bugzilla
|
||||
template path
|
||||
<filename>BUGZILLA_ROOT/template/en/default/</filename>.
|
||||
Looking in <filename>useful-links.html.tmpl</filename>, you find
|
||||
the following hook at the end of the list of standard Bugzilla
|
||||
administration links:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[...
|
||||
[% ', <a href="editkeywords.cgi">keywords</a>'
|
||||
IF user.groups.editkeywords %]
|
||||
[% Hook.process("edit") %]
|
||||
...]]></programlisting>
|
||||
|
||||
<para>
|
||||
The corresponding extension file for this hook is
|
||||
<filename>BUGZILLA_ROOT/extensions/projman/template/en/global/useful-links-edit.html.tmpl</filename>.
|
||||
You then create that template file and add the following constant:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[...[% ', <a href="edit-projects.cgi">projects</a>' IF user.groups.projman_admins %]]]></programlisting>
|
||||
|
||||
<para>
|
||||
Voila! The link now appears after the other administration links in the
|
||||
navigation bar for users in the <literal>projman_admins</literal> group.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now, let us say your extension adds a custom "project_manager" field
|
||||
to enter_bug.cgi. You want to modify the CGI script to set the default
|
||||
project manager to be productname@company.com. Looking at
|
||||
<filename>enter_bug.cgi</filename>, you see the enter_bug-entrydefaultvars
|
||||
hook near the bottom of the file before the default form values are set.
|
||||
The corresponding extension source file for this hook is located at
|
||||
<filename>BUGZILLA_ROOT/extensions/projman/code/enter_bug-entrydefaultvars.pl</filename>.
|
||||
You then create that file and add the following:
|
||||
</para>
|
||||
|
||||
<programlisting>$default{'project_manager'} = $product.'@company.com';</programlisting>
|
||||
|
||||
<para>
|
||||
This code will be invoked whenever enter_bug.cgi is executed.
|
||||
Assuming that the rest of the customization was completed (e.g. the
|
||||
custom field was added to the enter_bug template and the required hooks
|
||||
were used in process_bug.cgi), the new field will now have this
|
||||
default value.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Notes:
|
||||
</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
If your extension includes entirely new templates in addition to
|
||||
extensions of standard templates, it should store those new
|
||||
templates in its
|
||||
<filename>BUGZILLA_ROOT/extensions/template/en/</filename>
|
||||
directory. Extension template directories, like the
|
||||
<filename>default/</filename> and <filename>custom/</filename>
|
||||
directories, are part of the template search path, so putting templates
|
||||
there enables them to be found by the template processor.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The template processor looks for templates first in the
|
||||
<filename>custom/</filename> directory (i.e. templates added by the
|
||||
specific installation), then in the <filename>extensions/</filename>
|
||||
directory (i.e. templates added by extensions), and finally in the
|
||||
<filename>default/</filename> directory (i.e. the standard Bugzilla
|
||||
templates). Thus, installation-specific templates override both
|
||||
default and extension templates.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
If you are looking to customize Bugzilla, you can also take advantage
|
||||
of template hooks. To do so, create a directory in
|
||||
<filename>BUGZILLA_ROOT/template/en/custom/hook/</filename>
|
||||
that corresponds to the hook you wish to use, then place your
|
||||
customization templates into those directories. For example,
|
||||
if you wanted to use the hook "end" in
|
||||
<filename>global/useful-links.html.tmpl</filename>, you would
|
||||
create the directory <filename>BUGZILLA_ROOT/template/en/custom/hook/
|
||||
global/useful-links.html.tmpl/end/</filename> and add your customization
|
||||
template to this directory.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Obviously this method of customizing Bugzilla only lets you add code
|
||||
to the standard source files and templates; you cannot change the
|
||||
existing code. Nevertheless, for those customizations that only add
|
||||
code, this method can reduce conflicts when merging changes,
|
||||
making upgrading your customized Bugzilla installation easier.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section id="cust-change-permissions">
|
||||
<title>Customizing Who Can Change What</title>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
This feature should be considered experimental; the Bugzilla code you
|
||||
will be changing is not stable, and could change or move between
|
||||
versions. Be aware that if you make modifications as outlined here,
|
||||
you may have
|
||||
to re-make them or port them if Bugzilla changes internally between
|
||||
versions, and you upgrade.
|
||||
</para>
|
||||
</warning>
|
||||
|
||||
<para>
|
||||
Companies often have rules about which employees, or classes of employees,
|
||||
are allowed to change certain things in the bug system. For example,
|
||||
only the bug's designated QA Contact may be allowed to VERIFY the bug.
|
||||
Bugzilla has been
|
||||
designed to make it easy for you to write your own custom rules to define
|
||||
who is allowed to make what sorts of value transition.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
By default, assignees, QA owners and users
|
||||
with <emphasis>editbugs</emphasis> privileges can edit all fields of bugs,
|
||||
except group restrictions (unless they are members of the groups they
|
||||
are trying to change). Bug reporters also have the ability to edit some
|
||||
fields, but in a more restrictive manner. Other users, without
|
||||
<emphasis>editbugs</emphasis> privileges, can not edit
|
||||
bugs, except to comment and add themselves to the CC list.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For maximum flexibility, customizing this means editing Bugzilla's Perl
|
||||
code. This gives the administrator complete control over exactly who is
|
||||
allowed to do what. The relevant method is called
|
||||
<filename>check_can_change_field()</filename>,
|
||||
and is found in <filename>Bug.pm</filename> in your
|
||||
Bugzilla/ directory. If you open that file and search for
|
||||
<quote>sub check_can_change_field</quote>, you'll find it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This function has been carefully commented to allow you to see exactly
|
||||
how it works, and give you an idea of how to make changes to it.
|
||||
Certain marked sections should not be changed - these are
|
||||
the <quote>plumbing</quote> which makes the rest of the function work.
|
||||
In between those sections, you'll find snippets of code like:
|
||||
<programlisting> # Allow the assignee to change anything.
|
||||
if ($ownerid eq $whoid) {
|
||||
return 1;
|
||||
}</programlisting>
|
||||
It's fairly obvious what this piece of code does.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
So, how does one go about changing this function? Well, simple changes
|
||||
can be made just by removing pieces - for example, if you wanted to
|
||||
prevent any user adding a comment to a bug, just remove the lines marked
|
||||
<quote>Allow anyone to change comments.</quote> If you don't want the
|
||||
Reporter to have any special rights on bugs they have filed, just
|
||||
remove the entire section that deals with the Reporter.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
More complex customizations are not much harder. Basically, you add
|
||||
a check in the right place in the function, i.e. after all the variables
|
||||
you are using have been set up. So, don't look at $ownerid before
|
||||
$ownerid has been obtained from the database. You can either add a
|
||||
positive check, which returns 1 (allow) if certain conditions are true,
|
||||
or a negative check, which returns 0 (deny.) E.g.:
|
||||
<programlisting> if ($field eq "qacontact") {
|
||||
if (Bugzilla->user->groups("quality_assurance")) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}</programlisting>
|
||||
This says that only users in the group "quality_assurance" can change
|
||||
the QA Contact field of a bug.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Getting more weird:
|
||||
<programlisting><![CDATA[ if (($field eq "priority") &&
|
||||
(Bugzilla->user->email =~ /.*\@example\.com$/))
|
||||
{
|
||||
if ($oldvalue eq "P1") {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}]]></programlisting>
|
||||
This says that if the user is trying to change the priority field,
|
||||
and their email address is @example.com, they can only do so if the
|
||||
old value of the field was "P1". Not very useful, but illustrative.
|
||||
</para>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
If you are modifying <filename>process_bug.cgi</filename> in any
|
||||
way, do not change the code that is bounded by DO_NOT_CHANGE blocks.
|
||||
Doing so could compromise security, or cause your installation to
|
||||
stop working entirely.
|
||||
</para>
|
||||
</warning>
|
||||
|
||||
<para>
|
||||
For a list of possible field names, look at the bugs table in the
|
||||
database. If you need help writing custom rules for your organization,
|
||||
ask in the newsgroup.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<!-- Integrating Bugzilla with Third-Party Tools -->
|
||||
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="integration.xml" />
|
||||
</chapter>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,449 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<appendix id="gfdl">
|
||||
<title>GNU Free Documentation License</title>
|
||||
|
||||
<!-- - GNU Project - Free Software Foundation (FSF) -->
|
||||
<!-- LINK REV="made" HREF="mailto:webmasters@gnu.org" -->
|
||||
<!-- section>
|
||||
<title>GNU Free Documentation License</title -->
|
||||
<para>Version 1.1, March 2000</para>
|
||||
|
||||
<blockquote>
|
||||
<para>Copyright (C) 2000 Free Software Foundation, Inc. 59 Temple Place,
|
||||
Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and
|
||||
distribute verbatim copies of this license document, but changing it is
|
||||
not allowed.</para>
|
||||
</blockquote>
|
||||
|
||||
<section label="0" id="gfdl-0">
|
||||
<title>Preamble</title>
|
||||
|
||||
<para>The purpose of this License is to make a manual, textbook, or other
|
||||
written document "free" in the sense of freedom: to assure everyone the
|
||||
effective freedom to copy and redistribute it, with or without modifying
|
||||
it, either commercially or noncommercially. Secondarily, this License
|
||||
preserves for the author and publisher a way to get credit for their
|
||||
work, while not being considered responsible for modifications made by
|
||||
others.</para>
|
||||
|
||||
<para>This License is a kind of "copyleft", which means that derivative
|
||||
works of the document must themselves be free in the same sense. It
|
||||
complements the GNU General Public License, which is a copyleft license
|
||||
designed for free software.</para>
|
||||
|
||||
<para>We have designed this License in order to use it for manuals for
|
||||
free software, because free software needs free documentation: a free
|
||||
program should come with manuals providing the same freedoms that the
|
||||
software does. But this License is not limited to software manuals; it
|
||||
can be used for any textual work, regardless of subject matter or whether
|
||||
it is published as a printed book. We recommend this License principally
|
||||
for works whose purpose is instruction or reference.</para>
|
||||
</section>
|
||||
|
||||
<section label="1" id="gfdl-1">
|
||||
<title>Applicability and Definition</title>
|
||||
|
||||
<para>This License applies to any manual or other work that contains a
|
||||
notice placed by the copyright holder saying it can be distributed under
|
||||
the terms of this License. The "Document", below, refers to any such
|
||||
manual or work. Any member of the public is a licensee, and is addressed
|
||||
as "you".</para>
|
||||
|
||||
<para>A "Modified Version" of the Document means any work containing the
|
||||
Document or a portion of it, either copied verbatim, or with
|
||||
modifications and/or translated into another language.</para>
|
||||
|
||||
<para>A "Secondary Section" is a named appendix or a front-matter section
|
||||
of the Document that deals exclusively with the relationship of the
|
||||
publishers or authors of the Document to the Document's overall subject
|
||||
(or to related matters) and contains nothing that could fall directly
|
||||
within that overall subject. (For example, if the Document is in part a
|
||||
textbook of mathematics, a Secondary Section may not explain any
|
||||
mathematics.) The relationship could be a matter of historical connection
|
||||
with the subject or with related matters, or of legal, commercial,
|
||||
philosophical, ethical or political position regarding them.</para>
|
||||
|
||||
<para>The "Invariant Sections" are certain Secondary Sections whose
|
||||
titles are designated, as being those of Invariant Sections, in the
|
||||
notice that says that the Document is released under this License.</para>
|
||||
|
||||
<para>The "Cover Texts" are certain short passages of text that are
|
||||
listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says
|
||||
that the Document is released under this License.</para>
|
||||
|
||||
<para>A "Transparent" copy of the Document means a machine-readable copy,
|
||||
represented in a format whose specification is available to the general
|
||||
public, whose contents can be viewed and edited directly and
|
||||
straightforwardly with generic text editors or (for images composed of
|
||||
pixels) generic paint programs or (for drawings) some widely available
|
||||
drawing editor, and that is suitable for input to text formatters or for
|
||||
automatic translation to a variety of formats suitable for input to text
|
||||
formatters. A copy made in an otherwise Transparent file format whose
|
||||
markup has been designed to thwart or discourage subsequent modification
|
||||
by readers is not Transparent. A copy that is not "Transparent" is called
|
||||
"Opaque".</para>
|
||||
|
||||
<para>Examples of suitable formats for Transparent copies include plain
|
||||
ASCII without markup, Texinfo input format, LaTeX input format, SGML or
|
||||
XML using a publicly available DTD, and standard-conforming simple HTML
|
||||
designed for human modification. Opaque formats include PostScript, PDF,
|
||||
proprietary formats that can be read and edited only by proprietary word
|
||||
processors, SGML or XML for which the DTD and/or processing tools are not
|
||||
generally available, and the machine-generated HTML produced by some word
|
||||
processors for output purposes only.</para>
|
||||
|
||||
<para>The "Title Page" means, for a printed book, the title page itself,
|
||||
plus such following pages as are needed to hold, legibly, the material
|
||||
this License requires to appear in the title page. For works in formats
|
||||
which do not have any title page as such, "Title Page" means the text
|
||||
near the most prominent appearance of the work's title, preceding the
|
||||
beginning of the body of the text.</para>
|
||||
</section>
|
||||
|
||||
<section label="2" id="gfdl-2">
|
||||
<title>Verbatim Copying</title>
|
||||
|
||||
<para>You may copy and distribute the Document in any medium, either
|
||||
commercially or noncommercially, provided that this License, the
|
||||
copyright notices, and the license notice saying this License applies to
|
||||
the Document are reproduced in all copies, and that you add no other
|
||||
conditions whatsoever to those of this License. You may not use technical
|
||||
measures to obstruct or control the reading or further copying of the
|
||||
copies you make or distribute. However, you may accept compensation in
|
||||
exchange for copies. If you distribute a large enough number of copies
|
||||
you must also follow the conditions in section 3.</para>
|
||||
|
||||
<para>You may also lend copies, under the same conditions stated above,
|
||||
and you may publicly display copies.</para>
|
||||
</section>
|
||||
|
||||
<section label="3" id="gfdl-3">
|
||||
<title>Copying in Quantity</title>
|
||||
|
||||
<para>If you publish printed copies of the Document numbering more than
|
||||
100, and the Document's license notice requires Cover Texts, you must
|
||||
enclose the copies in covers that carry, clearly and legibly, all these
|
||||
Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts
|
||||
on the back cover. Both covers must also clearly and legibly identify you
|
||||
as the publisher of these copies. The front cover must present the full
|
||||
title with all words of the title equally prominent and visible. You may
|
||||
add other material on the covers in addition. Copying with changes
|
||||
limited to the covers, as long as they preserve the title of the Document
|
||||
and satisfy these conditions, can be treated as verbatim copying in other
|
||||
respects.</para>
|
||||
|
||||
<para>If the required texts for either cover are too voluminous to fit
|
||||
legibly, you should put the first ones listed (as many as fit reasonably)
|
||||
on the actual cover, and continue the rest onto adjacent pages.</para>
|
||||
|
||||
<para>If you publish or distribute Opaque copies of the Document
|
||||
numbering more than 100, you must either include a machine-readable
|
||||
Transparent copy along with each Opaque copy, or state in or with each
|
||||
Opaque copy a publicly-accessible computer-network location containing a
|
||||
complete Transparent copy of the Document, free of added material, which
|
||||
the general network-using public has access to download anonymously at no
|
||||
charge using public-standard network protocols. If you use the latter
|
||||
option, you must take reasonably prudent steps, when you begin
|
||||
distribution of Opaque copies in quantity, to ensure that this
|
||||
Transparent copy will remain thus accessible at the stated location until
|
||||
at least one year after the last time you distribute an Opaque copy
|
||||
(directly or through your agents or retailers) of that edition to the
|
||||
public.</para>
|
||||
|
||||
<para>It is requested, but not required, that you contact the authors of
|
||||
the Document well before redistributing any large number of copies, to
|
||||
give them a chance to provide you with an updated version of the
|
||||
Document.</para>
|
||||
</section>
|
||||
|
||||
<section label="4" id="gfdl-4">
|
||||
<title>Modifications</title>
|
||||
|
||||
<para>You may copy and distribute a Modified Version of the Document
|
||||
under the conditions of sections 2 and 3 above, provided that you release
|
||||
the Modified Version under precisely this License, with the Modified
|
||||
Version filling the role of the Document, thus licensing distribution and
|
||||
modification of the Modified Version to whoever possesses a copy of it.
|
||||
In addition, you must do these things in the Modified Version:</para>
|
||||
|
||||
<orderedlist numeration="upperalpha">
|
||||
<listitem>
|
||||
<para>Use in the Title Page (and on the covers, if any) a title
|
||||
distinct from that of the Document, and from those of previous
|
||||
versions (which should, if there were any, be listed in the History
|
||||
section of the Document). You may use the same title as a previous
|
||||
version if the original publisher of that version gives
|
||||
permission.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>List on the Title Page, as authors, one or more persons or
|
||||
entities responsible for authorship of the modifications in the
|
||||
Modified Version, together with at least five of the principal
|
||||
authors of the Document (all of its principal authors, if it has less
|
||||
than five).</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>State on the Title page the name of the publisher of the
|
||||
Modified Version, as the publisher.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Preserve all the copyright notices of the Document.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Add an appropriate copyright notice for your modifications
|
||||
adjacent to the other copyright notices.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Include, immediately after the copyright notices, a license
|
||||
notice giving the public permission to use the Modified Version under
|
||||
the terms of this License, in the form shown in the Addendum
|
||||
below.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Preserve in that license notice the full lists of Invariant
|
||||
Sections and required Cover Texts given in the Document's license
|
||||
notice.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Include an unaltered copy of this License.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Preserve the section entitled "History", and its title, and add
|
||||
to it an item stating at least the title, year, new authors, and
|
||||
publisher of the Modified Version as given on the Title Page. If
|
||||
there is no section entitled "History" in the Document, create one
|
||||
stating the title, year, authors, and publisher of the Document as
|
||||
given on its Title Page, then add an item describing the Modified
|
||||
Version as stated in the previous sentence.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Preserve the network location, if any, given in the Document
|
||||
for public access to a Transparent copy of the Document, and likewise
|
||||
the network locations given in the Document for previous versions it
|
||||
was based on. These may be placed in the "History" section. You may
|
||||
omit a network location for a work that was published at least four
|
||||
years before the Document itself, or if the original publisher of the
|
||||
version it refers to gives permission.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>In any section entitled "Acknowledgements" or "Dedications",
|
||||
preserve the section's title, and preserve in the section all the
|
||||
substance and tone of each of the contributor acknowledgements and/or
|
||||
dedications given therein.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Preserve all the Invariant Sections of the Document, unaltered
|
||||
in their text and in their titles. Section numbers or the equivalent
|
||||
are not considered part of the section titles.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Delete any section entitled "Endorsements". Such a section may
|
||||
not be included in the Modified Version.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Do not retitle any existing section as "Endorsements" or to
|
||||
conflict in title with any Invariant Section.</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>If the Modified Version includes new front-matter sections or
|
||||
appendices that qualify as Secondary Sections and contain no material
|
||||
copied from the Document, you may at your option designate some or all of
|
||||
these sections as invariant. To do this, add their titles to the list of
|
||||
Invariant Sections in the Modified Version's license notice. These titles
|
||||
must be distinct from any other section titles.</para>
|
||||
|
||||
<para>You may add a section entitled "Endorsements", provided it contains
|
||||
nothing but endorsements of your Modified Version by various parties--for
|
||||
example, statements of peer review or that the text has been approved by
|
||||
an organization as the authoritative definition of a standard.</para>
|
||||
|
||||
<para>You may add a passage of up to five words as a Front-Cover Text,
|
||||
and a passage of up to 25 words as a Back-Cover Text, to the end of the
|
||||
list of Cover Texts in the Modified Version. Only one passage of
|
||||
Front-Cover Text and one of Back-Cover Text may be added by (or through
|
||||
arrangements made by) any one entity. If the Document already includes a
|
||||
cover text for the same cover, previously added by you or by arrangement
|
||||
made by the same entity you are acting on behalf of, you may not add
|
||||
another; but you may replace the old one, on explicit permission from the
|
||||
previous publisher that added the old one.</para>
|
||||
|
||||
<para>The author(s) and publisher(s) of the Document do not by this
|
||||
License give permission to use their names for publicity for or to assert
|
||||
or imply endorsement of any Modified Version.</para>
|
||||
</section>
|
||||
|
||||
<section label="5" id="gfdl-5">
|
||||
<title>Combining Documents</title>
|
||||
|
||||
<para>You may combine the Document with other documents released under
|
||||
this License, under the terms defined in section 4 above for modified
|
||||
versions, provided that you include in the combination all of the
|
||||
Invariant Sections of all of the original documents, unmodified, and list
|
||||
them all as Invariant Sections of your combined work in its license
|
||||
notice.</para>
|
||||
|
||||
<para>The combined work need only contain one copy of this License, and
|
||||
multiple identical Invariant Sections may be replaced with a single copy.
|
||||
If there are multiple Invariant Sections with the same name but different
|
||||
contents, make the title of each such section unique by adding at the end
|
||||
of it, in parentheses, the name of the original author or publisher of
|
||||
that section if known, or else a unique number. Make the same adjustment
|
||||
to the section titles in the list of Invariant Sections in the license
|
||||
notice of the combined work.</para>
|
||||
|
||||
<para>In the combination, you must combine any sections entitled
|
||||
"History" in the various original documents, forming one section entitled
|
||||
"History"; likewise combine any sections entitled "Acknowledgements", and
|
||||
any sections entitled "Dedications". You must delete all sections
|
||||
entitled "Endorsements."</para>
|
||||
</section>
|
||||
|
||||
<section label="6" id="gfdl-6">
|
||||
<title>Collections of Documents</title>
|
||||
|
||||
<para>You may make a collection consisting of the Document and other
|
||||
documents released under this License, and replace the individual copies
|
||||
of this License in the various documents with a single copy that is
|
||||
included in the collection, provided that you follow the rules of this
|
||||
License for verbatim copying of each of the documents in all other
|
||||
respects.</para>
|
||||
|
||||
<para>You may extract a single document from such a collection, and
|
||||
distribute it individually under this License, provided you insert a copy
|
||||
of this License into the extracted document, and follow this License in
|
||||
all other respects regarding verbatim copying of that document.</para>
|
||||
</section>
|
||||
|
||||
<section label="7" id="gfdl-7">
|
||||
<title>Aggregation with Independent Works</title>
|
||||
|
||||
<para>A compilation of the Document or its derivatives with other
|
||||
separate and independent documents or works, in or on a volume of a
|
||||
storage or distribution medium, does not as a whole count as a Modified
|
||||
Version of the Document, provided no compilation copyright is claimed for
|
||||
the compilation. Such a compilation is called an "aggregate", and this
|
||||
License does not apply to the other self-contained works thus compiled
|
||||
with the Document, on account of their being thus compiled, if they are
|
||||
not themselves derivative works of the Document.</para>
|
||||
|
||||
<para>If the Cover Text requirement of section 3 is applicable to these
|
||||
copies of the Document, then if the Document is less than one quarter of
|
||||
the entire aggregate, the Document's Cover Texts may be placed on covers
|
||||
that surround only the Document within the aggregate. Otherwise they must
|
||||
appear on covers around the whole aggregate.</para>
|
||||
</section>
|
||||
|
||||
<section label="8" id="gfdl-8">
|
||||
<title>Translation</title>
|
||||
|
||||
<para>Translation is considered a kind of modification, so you may
|
||||
distribute translations of the Document under the terms of section 4.
|
||||
Replacing Invariant Sections with translations requires special
|
||||
permission from their copyright holders, but you may include translations
|
||||
of some or all Invariant Sections in addition to the original versions of
|
||||
these Invariant Sections. You may include a translation of this License
|
||||
provided that you also include the original English version of this
|
||||
License. In case of a disagreement between the translation and the
|
||||
original English version of this License, the original English version
|
||||
will prevail.</para>
|
||||
</section>
|
||||
|
||||
<section label="9" id="gfdl-9">
|
||||
<title>Termination</title>
|
||||
|
||||
<para>You may not copy, modify, sublicense, or distribute the Document
|
||||
except as expressly provided for under this License. Any other attempt to
|
||||
copy, modify, sublicense or distribute the Document is void, and will
|
||||
automatically terminate your rights under this License. However, parties
|
||||
who have received copies, or rights, from you under this License will not
|
||||
have their licenses terminated so long as such parties remain in full
|
||||
compliance.</para>
|
||||
</section>
|
||||
|
||||
<section label="10" id="gfdl-10">
|
||||
<title>Future Revisions of this License</title>
|
||||
|
||||
<para>The Free Software Foundation may publish new, revised versions of
|
||||
the GNU Free Documentation License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in
|
||||
detail to address new problems or concerns. See
|
||||
<ulink url="http://www.gnu.org/copyleft/"/>.</para>
|
||||
|
||||
<para>Each version of the License is given a distinguishing version
|
||||
number. If the Document specifies that a particular numbered version of
|
||||
this License "or any later version" applies to it, you have the option of
|
||||
following the terms and conditions either of that specified version or of
|
||||
any later version that has been published (not as a draft) by the Free
|
||||
Software Foundation. If the Document does not specify a version number of
|
||||
this License, you may choose any version ever published (not as a draft)
|
||||
by the Free Software Foundation.</para>
|
||||
</section>
|
||||
|
||||
<section label="" id="gfdl-howto">
|
||||
<title>How to use this License for your documents</title>
|
||||
|
||||
<para>To use this License in a document you have written, include a copy
|
||||
of the License in the document and put the following copyright and
|
||||
license notices just after the title page:</para>
|
||||
|
||||
<blockquote>
|
||||
<para>Copyright (c) YEAR YOUR NAME. Permission is granted to copy,
|
||||
distribute and/or modify this document under the terms of the GNU Free
|
||||
Documentation License, Version 1.1 or any later version published by
|
||||
the Free Software Foundation; with the Invariant Sections being LIST
|
||||
THEIR TITLES, with the Front-Cover Texts being LIST, and with the
|
||||
Back-Cover Texts being LIST. A copy of the license is included in the
|
||||
section entitled "GNU Free Documentation License".</para>
|
||||
</blockquote>
|
||||
|
||||
<para>If you have no Invariant Sections, write "with no Invariant
|
||||
Sections" instead of saying which ones are invariant. If you have no
|
||||
Front-Cover Texts, write "no Front-Cover Texts" instead of "Front-Cover
|
||||
Texts being LIST"; likewise for Back-Cover Texts.</para>
|
||||
|
||||
<para>If your document contains nontrivial examples of program code, we
|
||||
recommend releasing these examples in parallel under your choice of free
|
||||
software license, such as the GNU General Public License, to permit their
|
||||
use in free software.</para>
|
||||
</section>
|
||||
</appendix>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,555 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<glossary id="glossary">
|
||||
<glossdiv>
|
||||
<title>0-9, high ascii</title>
|
||||
|
||||
<glossentry id="gloss-htaccess">
|
||||
<glossterm>.htaccess</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Apache web server, and other NCSA-compliant web servers,
|
||||
observe the convention of using files in directories called
|
||||
<filename>.htaccess</filename>
|
||||
|
||||
to restrict access to certain files. In Bugzilla, they are used
|
||||
to keep secret files which would otherwise
|
||||
compromise your installation - e.g. the
|
||||
<filename>localconfig</filename>
|
||||
file contains the password to your database.
|
||||
curious.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-a">
|
||||
<title>A</title>
|
||||
|
||||
<glossentry id="gloss-apache">
|
||||
<glossterm>Apache</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>In this context, Apache is the web server most commonly used
|
||||
for serving up Bugzilla
|
||||
pages. Contrary to popular belief, the apache web server has nothing
|
||||
to do with the ancient and noble Native American tribe, but instead
|
||||
derived its name from the fact that it was
|
||||
<quote>a patchy</quote>
|
||||
version of the original
|
||||
<acronym>NCSA</acronym>
|
||||
world-wide-web server.</para>
|
||||
|
||||
<variablelist>
|
||||
<title>Useful Directives when configuring Bugzilla</title>
|
||||
|
||||
<varlistentry>
|
||||
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#addhandler">AddHandler</ulink></computeroutput></term>
|
||||
<listitem>
|
||||
<para>Tell Apache that it's OK to run CGI scripts.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#allowoverride">AllowOverride</ulink></computeroutput></term>
|
||||
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#options">Options</ulink></computeroutput></term>
|
||||
<listitem>
|
||||
<para>These directives are used to tell Apache many things about
|
||||
the directory they apply to. For Bugzilla's purposes, we need
|
||||
them to allow script execution and <filename>.htaccess</filename>
|
||||
overrides.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/mod_dir.html#directoryindex">DirectoryIndex</ulink></computeroutput></term>
|
||||
<listitem>
|
||||
<para>Used to tell Apache what files are indexes. If you can
|
||||
not add <filename>index.cgi</filename> to the list of valid files,
|
||||
you'll need to set <computeroutput>$index_html</computeroutput> to
|
||||
1 in <filename>localconfig</filename> so
|
||||
<command>./checksetup.pl</command> will create an
|
||||
<filename>index.html</filename> that redirects to
|
||||
<filename>index.cgi</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><computeroutput><ulink url="http://httpd.apache.org/docs-2.0/mod/core.html#scriptinterpretersource">ScriptInterpreterSource</ulink></computeroutput></term>
|
||||
<listitem>
|
||||
<para>Used when running Apache on windows so the shebang line
|
||||
doesn't have to be changed in every Bugzilla script.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>For more information about how to configure Apache for Bugzilla,
|
||||
see <xref linkend="http-apache"/>.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-b">
|
||||
<title>B</title>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>Bug</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A
|
||||
<quote>bug</quote>
|
||||
|
||||
in Bugzilla refers to an issue entered into the database which has an
|
||||
associated number, assignments, comments, etc. Some also refer to a
|
||||
<quote>tickets</quote>
|
||||
or
|
||||
<quote>issues</quote>;
|
||||
in the context of Bugzilla, they are synonymous.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>Bug Number</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Each Bugzilla bug is assigned a number that uniquely identifies
|
||||
that bug. The bug associated with a bug number can be pulled up via a
|
||||
query, or easily from the very front page by typing the number in the
|
||||
"Find" box.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-bugzilla">
|
||||
<glossterm>Bugzilla</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Bugzilla is the world-leading free software bug tracking system.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-c">
|
||||
<title>C</title>
|
||||
|
||||
<glossentry id="gloss-cgi">
|
||||
<glossterm>Common Gateway Interface</glossterm>
|
||||
<acronym>CGI</acronym>
|
||||
<glossdef>
|
||||
<para><acronym>CGI</acronym> is an acronym for Common Gateway Interface. This is
|
||||
a standard for interfacing an external application with a web server. Bugzilla
|
||||
is an example of a <acronym>CGI</acronym> application.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-component">
|
||||
<glossterm>Component</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A Component is a subsection of a Product. It should be a narrow
|
||||
category, tailored to your organization. All Products must contain at
|
||||
least one Component (and, as a matter of fact, creating a Product
|
||||
with no Components will create an error in Bugzilla).</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-cpan">
|
||||
<glossterm>Comprehensive Perl Archive Network</glossterm>
|
||||
<acronym>CPAN</acronym>
|
||||
|
||||
<!-- TODO: Rewrite def for CPAN -->
|
||||
<glossdef>
|
||||
<para>
|
||||
<acronym>CPAN</acronym>
|
||||
|
||||
stands for the
|
||||
<quote>Comprehensive Perl Archive Network</quote>.
|
||||
CPAN maintains a large number of extremely useful
|
||||
<glossterm>Perl</glossterm>
|
||||
modules - encapsulated chunks of code for performing a
|
||||
particular task.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-contrib">
|
||||
<glossterm><filename class="directory">contrib</filename></glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>The <filename class="directory">contrib</filename> directory is
|
||||
a location to put scripts that have been contributed to Bugzilla but
|
||||
are not a part of the official distribution. These scripts are written
|
||||
by third parties and may be in languages other than perl. For those
|
||||
that are in perl, there may be additional modules or other requirements
|
||||
than those of the official distribution.
|
||||
<note>
|
||||
<para>Scripts in the <filename class="directory">contrib</filename>
|
||||
directory are not officially supported by the Bugzilla team and may
|
||||
break in between versions.
|
||||
</para>
|
||||
</note>
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-d">
|
||||
<title>D</title>
|
||||
|
||||
<glossentry id="gloss-daemon">
|
||||
<glossterm>daemon</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A daemon is a computer program which runs in the background. In
|
||||
general, most daemons are started at boot time via System V init
|
||||
scripts, or through RC scripts on BSD-based systems.
|
||||
<glossterm>mysqld</glossterm>,
|
||||
the MySQL server, and
|
||||
<glossterm>apache</glossterm>,
|
||||
a web server, are generally run as daemons.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-dos">
|
||||
<glossterm>DOS Attack</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A DOS, or Denial of Service attack, is when a user attempts to
|
||||
deny access to a web server by repeatedly accessing a page or sending
|
||||
malformed requests to a webserver. A D-DOS, or
|
||||
Distributed Denial of Service attack, is when these requests come
|
||||
from multiple sources at the same time. Unfortunately, these are much
|
||||
more difficult to defend against.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-g">
|
||||
<title>G</title>
|
||||
|
||||
<glossentry id="gloss-groups">
|
||||
<glossterm>Groups</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>The word
|
||||
<quote>Groups</quote>
|
||||
|
||||
has a very special meaning to Bugzilla. Bugzilla's main security
|
||||
mechanism comes by placing users in groups, and assigning those
|
||||
groups certain privileges to view bugs in particular
|
||||
<glossterm>Products</glossterm>
|
||||
in the
|
||||
<glossterm>Bugzilla</glossterm>
|
||||
database.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-j">
|
||||
<title>J</title>
|
||||
|
||||
<glossentry id="gloss-javascript">
|
||||
<glossterm>JavaScript</glossterm>
|
||||
<glossdef>
|
||||
<para>JavaScript is cool, we should talk about it.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-m">
|
||||
<title>M</title>
|
||||
|
||||
<glossentry id="gloss-mta">
|
||||
<glossterm>Message Transport Agent</glossterm>
|
||||
<acronym>MTA</acronym>
|
||||
|
||||
<glossdef>
|
||||
<para>A Message Transport Agent is used to control the flow of email on a system.
|
||||
The <ulink url="http://search.cpan.org/dist/Email-Send/lib/Email/Send.pm">Email::Send</ulink>
|
||||
Perl module, which Bugzilla uses to send email, can be configured to
|
||||
use many different underlying implementations for actually sending the
|
||||
mail using the <option>mail_delivery_method</option> parameter.
|
||||
Implementations other than <literal>sendmail</literal> require that the
|
||||
<option>sendmailnow</option> param be set to <literal>on</literal>.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-mysql">
|
||||
<glossterm>MySQL</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>MySQL is currently the required
|
||||
<glossterm linkend="gloss-rdbms">RDBMS</glossterm> for Bugzilla. MySQL
|
||||
can be downloaded from <ulink url="http://www.mysql.com"/>. While you
|
||||
should familiarize yourself with all of the documentation, some high
|
||||
points are:
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><ulink url="http://www.mysql.com/doc/en/Backup.html">Backup</ulink></term>
|
||||
<listitem>
|
||||
<para>Methods for backing up your Bugzilla database.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><ulink url="http://www.mysql.com/doc/en/Option_files.html">Option Files</ulink></term>
|
||||
<listitem>
|
||||
<para>Information about how to configure MySQL using
|
||||
<filename>my.cnf</filename>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><ulink url="http://www.mysql.com/doc/en/Privilege_system.html">Privilege System</ulink></term>
|
||||
<listitem>
|
||||
<para>Much more detailed information about the suggestions in
|
||||
<xref linkend="security-mysql"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-p">
|
||||
<title>P</title>
|
||||
|
||||
<glossentry id="gloss-ppm">
|
||||
<glossterm>Perl Package Manager</glossterm>
|
||||
<acronym>PPM</acronym>
|
||||
|
||||
<glossdef>
|
||||
<para><ulink url="http://aspn.activestate.com/ASPN/Downloads/ActivePerl/PPM/"/>
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm id="gloss-product">Product</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>A Product is a broad category of types of bugs, normally
|
||||
representing a single piece of software or entity. In general,
|
||||
there are several Components to a Product. A Product may define a
|
||||
group (used for security) for all bugs entered into
|
||||
its Components.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>Perl</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>First written by Larry Wall, Perl is a remarkable program
|
||||
language. It has the benefits of the flexibility of an interpreted
|
||||
scripting language (such as shell script), combined with the speed
|
||||
and power of a compiled language, such as C.
|
||||
<glossterm>Bugzilla</glossterm>
|
||||
|
||||
is maintained in Perl.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-q">
|
||||
<title>Q</title>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>QA</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>
|
||||
<quote>QA</quote>,
|
||||
<quote>Q/A</quote>, and
|
||||
<quote>Q.A.</quote>
|
||||
are short for
|
||||
<quote>Quality Assurance</quote>.
|
||||
In most large software development organizations, there is a team
|
||||
devoted to ensuring the product meets minimum standards before
|
||||
shipping. This team will also generally want to track the progress of
|
||||
bugs over their life cycle, thus the need for the
|
||||
<quote>QA Contact</quote>
|
||||
|
||||
field in a bug.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-r">
|
||||
<title>R</title>
|
||||
|
||||
<glossentry id="gloss-rdbms">
|
||||
<glossterm>Relational DataBase Management System</glossterm>
|
||||
<acronym>RDBMS</acronym>
|
||||
|
||||
<glossdef>
|
||||
<para>A relational database management system is a database system
|
||||
that stores information in tables that are related to each other.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-regexp">
|
||||
<glossterm>Regular Expression</glossterm>
|
||||
<acronym>regexp</acronym>
|
||||
|
||||
<glossdef>
|
||||
<para>A regular expression is an expression used for pattern matching.
|
||||
<ulink url="http://perldoc.com/perl5.6/pod/perlre.html#Regular-Expressions">Documentation</ulink>
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-s">
|
||||
<title>S</title>
|
||||
|
||||
<glossentry id="gloss-service">
|
||||
<glossterm>Service</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>In Windows NT environment, a boot-time background application
|
||||
is referred to as a service. These are generally managed through the
|
||||
control panel while logged in as an account with
|
||||
<quote>Administrator</quote> level capabilities. For more
|
||||
information, consult your Windows manual or the MSKB.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry>
|
||||
<glossterm>
|
||||
<acronym>SGML</acronym>
|
||||
</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>
|
||||
<acronym>SGML</acronym>
|
||||
|
||||
stands for
|
||||
<quote>Standard Generalized Markup Language</quote>.
|
||||
Created in the 1980's to provide an extensible means to maintain
|
||||
documentation based upon content instead of presentation,
|
||||
<acronym>SGML</acronym>
|
||||
|
||||
has withstood the test of time as a robust, powerful language.
|
||||
<glossterm>
|
||||
<acronym>XML</acronym>
|
||||
</glossterm>
|
||||
|
||||
is the
|
||||
<quote>baby brother</quote>
|
||||
|
||||
of SGML; any valid
|
||||
<acronym>XML</acronym>
|
||||
|
||||
document it, by definition, a valid
|
||||
<acronym>SGML</acronym>
|
||||
|
||||
document. The document you are reading is written and maintained in
|
||||
<acronym>SGML</acronym>,
|
||||
and is also valid
|
||||
<acronym>XML</acronym>
|
||||
|
||||
if you modify the Document Type Definition.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-t">
|
||||
<title>T</title>
|
||||
|
||||
<glossentry id="gloss-target-milestone" xreflabel="Target Milestone">
|
||||
<glossterm>Target Milestone</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>Target Milestones are Product goals. They are configurable on a
|
||||
per-Product basis. Most software development houses have a concept of
|
||||
|
||||
<quote>milestones</quote>
|
||||
|
||||
where the people funding a project expect certain functionality on
|
||||
certain dates. Bugzilla facilitates meeting these milestones by
|
||||
giving you the ability to declare by which milestone a bug will be
|
||||
fixed, or an enhancement will be implemented.</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
|
||||
<glossentry id="gloss-tcl">
|
||||
<glossterm>Tool Command Language</glossterm>
|
||||
<acronym>TCL</acronym>
|
||||
<glossdef>
|
||||
<para>TCL is an open source scripting language available for Windows,
|
||||
Macintosh, and Unix based systems. Bugzilla 1.0 was written in TCL but
|
||||
never released. The first release of Bugzilla was 2.0, which was when
|
||||
it was ported to perl.
|
||||
</para>
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
|
||||
<glossdiv id="gloss-z">
|
||||
<title>Z</title>
|
||||
|
||||
<glossentry id="gloss-zarro">
|
||||
<glossterm>Zarro Boogs Found</glossterm>
|
||||
|
||||
<glossdef>
|
||||
<para>This is just a goofy way of saying that there were no bugs
|
||||
found matching your query. When asked to explain this message,
|
||||
Terry had the following to say:
|
||||
</para>
|
||||
|
||||
<blockquote>
|
||||
<attribution>Terry Weissman</attribution>
|
||||
<para>I've been asked to explain this ... way back when, when
|
||||
Netscape released version 4.0 of its browser, we had a release
|
||||
party. Naturally, there had been a big push to try and fix every
|
||||
known bug before the release. Naturally, that hadn't actually
|
||||
happened. (This is not unique to Netscape or to 4.0; the same thing
|
||||
has happened with every software project I've ever seen.) Anyway,
|
||||
at the release party, T-shirts were handed out that said something
|
||||
like "Netscape 4.0: Zarro Boogs". Just like the software, the
|
||||
T-shirt had no known bugs. Uh-huh.
|
||||
</para>
|
||||
|
||||
<para>So, when you query for a list of bugs, and it gets no results,
|
||||
you can think of this as a friendly reminder. Of *course* there are
|
||||
bugs matching your query, they just aren't in the bugsystem yet...
|
||||
</para>
|
||||
</blockquote>
|
||||
|
||||
</glossdef>
|
||||
</glossentry>
|
||||
</glossdiv>
|
||||
</glossary>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
@@ -1,21 +0,0 @@
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,124 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<!-- Keep these tools listings in alphabetical order please. -MPB -->
|
||||
<section id="integration">
|
||||
<title>Integrating Bugzilla with Third-Party Tools</title>
|
||||
|
||||
<section id="bonsai"
|
||||
xreflabel="Bonsai, the Mozilla automated CVS management system">
|
||||
<title>Bonsai</title>
|
||||
|
||||
<para>Bonsai is a web-based tool for managing
|
||||
<xref linkend="cvs" />
|
||||
|
||||
. Using Bonsai, administrators can control open/closed status of trees,
|
||||
query a fast relational database back-end for change, branch, and comment
|
||||
information, and view changes made since the last time the tree was
|
||||
closed. Bonsai
|
||||
also integrates with
|
||||
<xref linkend="tinderbox" />.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="cvs" xreflabel="CVS, the Concurrent Versioning System">
|
||||
<title>CVS</title>
|
||||
|
||||
<para>CVS integration is best accomplished, at this point, using the
|
||||
Bugzilla Email Gateway.</para>
|
||||
|
||||
<para>Follow the instructions in this Guide for enabling Bugzilla e-mail
|
||||
integration. Ensure that your check-in script sends an email to your
|
||||
Bugzilla e-mail gateway with the subject of
|
||||
<quote>[Bug XXXX]</quote>,
|
||||
and you can have CVS check-in comments append to your Bugzilla bug. If
|
||||
you want to have the bug be closed automatically, you'll have to modify
|
||||
the <filename>contrib/bugzilla_email_append.pl</filename> script.
|
||||
</para>
|
||||
|
||||
<para>There is also a CVSZilla project, based upon somewhat dated
|
||||
Bugzilla code, to integrate CVS and Bugzilla through CVS' ability to
|
||||
email. Check it out at: <ulink url="http://www.cvszilla.org/"/>.
|
||||
</para>
|
||||
|
||||
<para>Another system capable of CVS integration with Bugzilla is
|
||||
Scmbug. This system provides generic integration of Source code
|
||||
Configuration Management with Bugtracking. Check it out at: <ulink
|
||||
url="http://freshmeat.net/projects/scmbug/"/>.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="scm"
|
||||
xreflabel="Perforce SCM (Fast Software Configuration Management System, a powerful commercial alternative to CVS">
|
||||
|
||||
<title>Perforce SCM</title>
|
||||
|
||||
<para>You can find the project page for Bugzilla and Teamtrack Perforce
|
||||
integration (p4dti) at:
|
||||
<ulink url="http://www.ravenbrook.com/project/p4dti/"/>
|
||||
|
||||
.
|
||||
<quote>p4dti</quote>
|
||||
|
||||
is now an officially supported product from Perforce, and you can find
|
||||
the "Perforce Public Depot" p4dti page at
|
||||
<ulink url="http://public.perforce.com/public/perforce/p4dti/index.html"/>
|
||||
|
||||
.</para>
|
||||
|
||||
<para>Integration of Perforce with Bugzilla, once patches are applied, is
|
||||
seamless. Perforce replication information will appear below the comments
|
||||
of each bug. Be certain you have a matching set of patches for the
|
||||
Bugzilla version you are installing. p4dti is designed to support
|
||||
multiple defect trackers, and maintains its own documentation for it.
|
||||
Please consult the pages linked above for further information.</para>
|
||||
</section>
|
||||
|
||||
<section id="svn"
|
||||
xreflabel="Subversion, a compelling replacement for CVS">
|
||||
<title>Subversion</title>
|
||||
<para>Subversion is a free/open-source version control system,
|
||||
designed to overcome various limitations of CVS. Integration of
|
||||
Subversion with Bugzilla is possible using Scmbug, a system
|
||||
providing generic integration of Source Code Configuration
|
||||
Management with Bugtracking. Scmbug is available at <ulink
|
||||
url="http://freshmeat.net/projects/scmbug/"/>.</para>
|
||||
</section>
|
||||
|
||||
<section id="tinderbox"
|
||||
xreflabel="Tinderbox, the Mozilla automated build management system">
|
||||
<title>Tinderbox/Tinderbox2</title>
|
||||
|
||||
<para>Tinderbox is a continuous-build system which can integrate with
|
||||
Bugzilla - see
|
||||
<ulink url="http://www.mozilla.org/projects/tinderbox"/> for details
|
||||
of Tinderbox, and
|
||||
<ulink url="http://tinderbox.mozilla.org/showbuilds.cgi"/> to see it
|
||||
in action.</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<section id="what-is-bugzilla">
|
||||
<title>What is Bugzilla?</title>
|
||||
|
||||
<para>
|
||||
Bugzilla is a bug- or issue-tracking system. Bug-tracking
|
||||
systems allow individual or groups of developers effectively to keep track
|
||||
of outstanding problems with their products.
|
||||
</para>
|
||||
|
||||
<para><emphasis>Do we need more here?</emphasis></para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="why-tracking">
|
||||
<title>Why use a bug-tracking system?</title>
|
||||
|
||||
<para>Those who do not use a bug-tracking system tend to rely on
|
||||
shared lists, email, spreadsheets and/or Post-It notes to monitor the
|
||||
status of defects. This procedure
|
||||
is usually error-prone and tends to cause those bugs judged least
|
||||
significant by developers to be dropped or ignored.</para>
|
||||
|
||||
<para>Integrated defect-tracking systems make sure that nothing gets
|
||||
swept under the carpet; they provide a method of creating, storing,
|
||||
arranging and processing defect reports and enhancement requests.</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="why-bugzilla">
|
||||
<title>Why use Bugzilla?</title>
|
||||
|
||||
<para>Bugzilla is the leading open-source/free software bug tracking
|
||||
system. It boasts many advanced features, including:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Powerful searching</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>User-configurable email notifications of bug changes</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Full change history</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Inter-bug dependency tracking and graphing</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Excellent attachment management</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Integrated, product-based, granular security schema</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Fully security-audited, and runs under Perl's taint mode</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>A robust, stable RDBMS back-end</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Completely customizable and/or localizable web user
|
||||
interface</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Additional XML, email and console interfaces</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Extensive configurability</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Smooth upgrade pathway between versions</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Bugzilla is very adaptable to various situations. Known uses
|
||||
currently include IT support queues, Systems Administration deployment
|
||||
management, chip design and development problem tracking (both
|
||||
pre-and-post fabrication), and software and hardware bug tracking for
|
||||
luminaries such as Redhat, NASA, Linux-Mandrake, and VA Systems.
|
||||
Combined with systems such as
|
||||
<ulink url="http://www.cvshome.org">CVS</ulink>,
|
||||
<ulink url="http://www.mozilla.org/bonsai.html">Bonsai</ulink>, or
|
||||
<ulink url="http://www.perforce.com">Perforce SCM</ulink>, Bugzilla
|
||||
provides a powerful, easy-to-use configuration management solution.</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
@@ -1,197 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<appendix id="install-perlmodules-manual">
|
||||
<title>Manual Installation of Perl Modules</title>
|
||||
|
||||
<section id="modules-manual-instructions">
|
||||
<title>Instructions</title>
|
||||
<para>
|
||||
If you need to install Perl modules manually, here's how it's done.
|
||||
Download the module using the link given in the next section, and then
|
||||
apply this magic incantation, as root:
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<screen><prompt>bash#</prompt> tar -xzvf <module>.tar.gz
|
||||
<prompt>bash#</prompt> cd <module>
|
||||
<prompt>bash#</prompt> perl Makefile.PL
|
||||
<prompt>bash#</prompt> make
|
||||
<prompt>bash#</prompt> make test
|
||||
<prompt>bash#</prompt> make install</screen>
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
In order to compile source code under Windows you will need to obtain
|
||||
a 'make' utility. The <command>nmake</command> utility provided with
|
||||
Microsoft Visual C++ may be used. As an alternative, there is a
|
||||
utility called <command>dmake</command> available from CPAN which is
|
||||
written entirely in Perl.
|
||||
</para>
|
||||
<para>
|
||||
As described in <xref linkend="modules-manual-download" />, however, most
|
||||
packages already exist and are available from ActiveState or theory58S.
|
||||
We highly recommend that you install them using the ppm GUI available with
|
||||
ActiveState and to add the theory58S repository to your list of repositories.
|
||||
</para>
|
||||
</note>
|
||||
</section>
|
||||
|
||||
<section id="modules-manual-download">
|
||||
<title>Download Locations</title>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
Running Bugzilla on Windows requires the use of ActiveState
|
||||
Perl 5.8.1 or higher. Many modules already exist in the core
|
||||
distribution of ActiveState Perl. Additional modules can be downloaded
|
||||
from <ulink url="http://theoryx5.uwinnipeg.ca/ppms/" /> if you use
|
||||
Perl 5.8.x or from <ulink url="http://cpan.uwinnipeg.ca/PPMPackages/10xx/" />
|
||||
if you use Perl 5.10.x.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
CGI:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/CGI.pm/"/>
|
||||
Documentation: <ulink url="http://perldoc.perl.org/CGI.html"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Data-Dumper:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Data-Dumper/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/Data-Dumper/Dumper.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Date::Format (part of TimeDate):
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/TimeDate/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/TimeDate/lib/Date/Format.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
DBI:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/DBI/"/>
|
||||
Documentation: <ulink url="http://dbi.perl.org/docs/"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
DBD::mysql:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/DBD-mysql/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
DBD::Pg:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/DBD-Pg/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/DBD-Pg/Pg.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
File::Spec:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/File-Spec/"/>
|
||||
Documentation: <ulink url="http://perldoc.perl.org/File/Spec.html"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Template-Toolkit:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Template-Toolkit/"/>
|
||||
Documentation: <ulink url="http://www.template-toolkit.org/docs.html"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
GD:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/GD/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/GD/GD.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Template::Plugin::GD:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Template-GD/" />
|
||||
Documentation: <ulink url="http://www.template-toolkit.org/docs/aqua/Modules/index.html" />
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
MIME::Parser (part of MIME-tools):
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/MIME-tools/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/MIME-tools/lib/MIME/Parser.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="modules-manual-optional">
|
||||
<title>Optional Modules</title>
|
||||
|
||||
<para>
|
||||
Chart::Base:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/Chart/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/Chart/Chart.pod"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
GD::Graph:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/GDGraph/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/GDGraph/Graph.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
GD::Text::Align (part of GD::Text::Util):
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/GDTextUtil/"/>
|
||||
Documentation: <ulink url="http://search.cpan.org/dist/GDTextUtil/Text/Align.pm"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
XML::Twig:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/XML-Twig/"/>
|
||||
Documentation: <ulink url="http://standards.ieee.org/resources/spasystem/twig/twig_stable.html"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
PatchReader:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/author/JKEISER/PatchReader/"/>
|
||||
Documentation: <ulink url="http://www.johnkeiser.com/mozilla/Patch_Viewer.html"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Image::Magick:
|
||||
<literallayout>
|
||||
CPAN Download Page: <ulink url="http://search.cpan.org/dist/PerlMagick/"/>
|
||||
Documentation: <ulink url="http://www.imagemagick.org/script/resources.php"/>
|
||||
</literallayout>
|
||||
</para>
|
||||
</section>
|
||||
</appendix>
|
||||
@@ -1,135 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<appendix id="patches" xreflabel="Useful Patches and Utilities for Bugzilla">
|
||||
<title>Contrib</title>
|
||||
|
||||
<para>
|
||||
There are a number of unofficial Bugzilla add-ons in the
|
||||
<filename class="directory">$BUGZILLA_ROOT/contrib/</filename>
|
||||
directory. This section documents them.
|
||||
</para>
|
||||
|
||||
<section id="cmdline">
|
||||
<title>Command-line Search Interface</title>
|
||||
|
||||
<para>
|
||||
There are a suite of Unix utilities for searching Bugzilla from the
|
||||
command line. They live in the
|
||||
<filename class="directory">contrib/cmdline</filename> directory.
|
||||
There are three files - <filename>query.conf</filename>,
|
||||
<filename>buglist</filename> and <filename>bugs</filename>.
|
||||
</para>
|
||||
|
||||
<warning>
|
||||
<para>
|
||||
These files pre-date the templatization work done as part of the
|
||||
2.16 release, and have not been updated.
|
||||
</para>
|
||||
</warning>
|
||||
|
||||
<para>
|
||||
<filename>query.conf</filename> contains the mapping from
|
||||
options to field names and comparison types. Quoted option names
|
||||
are <quote>grepped</quote> for, so it should be easy to edit this
|
||||
file. Comments (#) have no effect; you must make sure these lines
|
||||
do not contain any quoted <quote>option</quote>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<filename>buglist</filename> is a shell script that submits a
|
||||
Bugzilla query and writes the resulting HTML page to stdout.
|
||||
It supports both short options, (such as <quote>-Afoo</quote>
|
||||
or <quote>-Rbar</quote>) and long options (such
|
||||
as <quote>--assignedto=foo</quote> or <quote>--reporter=bar</quote>).
|
||||
If the first character of an option is not <quote>-</quote>, it is
|
||||
treated as if it were prefixed with <quote>--default=</quote>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The column list is taken from the COLUMNLIST environment variable.
|
||||
This is equivalent to the <quote>Change Columns</quote> option
|
||||
that is available when you list bugs in buglist.cgi. If you have
|
||||
already used Bugzilla, grep for COLUMNLIST in your cookies file
|
||||
to see your current COLUMNLIST setting.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<filename>bugs</filename> is a simple shell script which calls
|
||||
<filename>buglist</filename> and extracts the
|
||||
bug numbers from the output. Adding the prefix
|
||||
<quote>http://bugzilla.mozilla.org/buglist.cgi?bug_id=</quote>
|
||||
turns the bug list into a working link if any bugs are found.
|
||||
Counting bugs is easy. Pipe the results through
|
||||
<command>sed -e 's/,/ /g' | wc | awk '{printf $2 "\n"}'</command>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Akkana Peck says she has good results piping
|
||||
<filename>buglist</filename> output through
|
||||
<command>w3m -T text/html -dump</command>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="cmdline-bugmail">
|
||||
<title>Command-line 'Send Unsent Bug-mail' tool</title>
|
||||
|
||||
<para>
|
||||
Within the <filename class="directory">contrib</filename> directory
|
||||
exists a utility with the descriptive (if compact) name
|
||||
of <filename>sendunsentbugmail.pl</filename>. The purpose of this
|
||||
script is, simply, to send out any bug-related mail that should
|
||||
have been sent by now, but for one reason or another has not.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To accomplish this task, <filename>sendunsentbugmail.pl</filename> uses
|
||||
the same mechanism as the <filename>sanitycheck.cgi</filename> script;
|
||||
it scans through the entire database looking for bugs with changes that
|
||||
were made more than 30 minutes ago, but where there is no record of
|
||||
anyone related to that bug having been sent mail. Having compiled a list,
|
||||
it then uses the standard rules to determine who gets mail, and sends it
|
||||
out.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As the script runs, it indicates the bug for which it is currently
|
||||
sending mail; when it has finished, it gives a numerical count of how
|
||||
many mails were sent and how many people were excluded. (Individual
|
||||
user names are not recorded or displayed.) If the script produces
|
||||
no output, that means no unsent mail was detected.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Usage</emphasis>: move the sendunsentbugmail.pl script
|
||||
up into the main directory, ensure it has execute permission, and run it
|
||||
from the command line (or from a cron job) with no parameters.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</appendix>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<!-- <!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook V4.1//EN"> -->
|
||||
<appendix id="downloadlinks">
|
||||
<title>Software Download Links</title>
|
||||
|
||||
<para>All of these sites are current as of April, 2001. Hopefully they'll
|
||||
stay current for a while.</para>
|
||||
|
||||
<para>Apache Web Server:
|
||||
<ulink url="http://www.apache.org/"/>
|
||||
|
||||
Optional web server for Bugzilla, but recommended because of broad user
|
||||
base and support.</para>
|
||||
|
||||
<para>Bugzilla:
|
||||
<ulink url="http://www.bugzilla.org/"/>
|
||||
</para>
|
||||
|
||||
<para>MySQL:
|
||||
<ulink url="http://www.mysql.com/"/>
|
||||
</para>
|
||||
|
||||
<para>Perl:
|
||||
<ulink url="http://www.perl.org/"/>
|
||||
</para>
|
||||
|
||||
<para>CPAN:
|
||||
<ulink url="http://www.cpan.org/"/>
|
||||
</para>
|
||||
|
||||
<para>DBI Perl module:
|
||||
<ulink url="http://www.cpan.org/modules/by-module/DBI/"/>
|
||||
</para>
|
||||
|
||||
<para>MySQL related Perl modules:
|
||||
<ulink url="http://www.cpan.org/modules/by-module/Mysql/"/>
|
||||
</para>
|
||||
|
||||
<para>TimeDate Perl module collection:
|
||||
<ulink url="http://www.cpan.org/modules/by-module/Date/"/>
|
||||
</para>
|
||||
|
||||
<para>GD Perl module:
|
||||
<ulink url="http://www.cpan.org/modules/by-module/GD/"/>
|
||||
|
||||
Alternately, you should be able to find the latest version of GD at
|
||||
<ulink url="http://www.boutell.com/gd/"/>
|
||||
</para>
|
||||
|
||||
<para>Chart::Base module:
|
||||
<ulink url="http://www.cpan.org/modules/by-module/Chart/"/>
|
||||
</para>
|
||||
|
||||
<para>(But remember, Bundle::Bugzilla will install all the modules for you.)
|
||||
</para>
|
||||
</appendix>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,364 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<!-- $Id: security.xml,v 1.19.2.1 2008-07-13 16:44:28 mozilla%colinogilvie.co.uk Exp $ -->
|
||||
|
||||
<chapter id="security">
|
||||
<title>Bugzilla Security</title>
|
||||
|
||||
<para>While some of the items in this chapter are related to the operating
|
||||
system Bugzilla is running on or some of the support software required to
|
||||
run Bugzilla, it is all related to protecting your data. This is not
|
||||
intended to be a comprehensive guide to securing Linux, Apache, MySQL, or
|
||||
any other piece of software mentioned. There is no substitute for active
|
||||
administration and monitoring of a machine. The key to good security is
|
||||
actually right in the middle of the word: <emphasis>U R It</emphasis>.
|
||||
</para>
|
||||
|
||||
<para>While programmers in general always strive to write secure code,
|
||||
accidents can and do happen. The best approach to security is to always
|
||||
assume that the program you are working with isn't 100% secure and restrict
|
||||
its access to other parts of your machine as much as possible.
|
||||
</para>
|
||||
|
||||
<section id="security-os">
|
||||
<title>Operating System</title>
|
||||
|
||||
<section id="security-os-ports">
|
||||
<title>TCP/IP Ports</title>
|
||||
|
||||
<!-- TODO: Get exact number of ports -->
|
||||
<para>The TCP/IP standard defines more than 65,000 ports for sending
|
||||
and receiving traffic. Of those, Bugzilla needs exactly one to operate
|
||||
(different configurations and options may require up to 3). You should
|
||||
audit your server and make sure that you aren't listening on any ports
|
||||
you don't need to be. It's also highly recommended that the server
|
||||
Bugzilla resides on, along with any other machines you administer, be
|
||||
placed behind some kind of firewall.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="security-os-accounts">
|
||||
<title>System User Accounts</title>
|
||||
|
||||
<para>Many <glossterm linkend="gloss-daemon">daemons</glossterm>, such
|
||||
as Apache's <filename>httpd</filename> or MySQL's
|
||||
<filename>mysqld</filename>, run as either <quote>root</quote> or
|
||||
<quote>nobody</quote>. This is even worse on Windows machines where the
|
||||
majority of <glossterm linkend="gloss-service">services</glossterm>
|
||||
run as <quote>SYSTEM</quote>. While running as <quote>root</quote> or
|
||||
<quote>SYSTEM</quote> introduces obvious security concerns, the
|
||||
problems introduced by running everything as <quote>nobody</quote> may
|
||||
not be so obvious. Basically, if you run every daemon as
|
||||
<quote>nobody</quote> and one of them gets compromised it can
|
||||
compromise every other daemon running as <quote>nobody</quote> on your
|
||||
machine. For this reason, it is recommended that you create a user
|
||||
account for each daemon.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>You will need to set the <option>webservergroup</option> option
|
||||
in <filename>localconfig</filename> to the group your web server runs
|
||||
as. This will allow <filename>./checksetup.pl</filename> to set file
|
||||
permissions on Unix systems so that nothing is world-writable.
|
||||
</para>
|
||||
</note>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="security-os-chroot">
|
||||
<title>The <filename>chroot</filename> Jail</title>
|
||||
|
||||
<para>
|
||||
If your system supports it, you may wish to consider running
|
||||
Bugzilla inside of a <filename>chroot</filename> jail. This option
|
||||
provides unprecedented security by restricting anything running
|
||||
inside the jail from accessing any information outside of it. If you
|
||||
wish to use this option, please consult the documentation that came
|
||||
with your system.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="security-mysql">
|
||||
<title>MySQL</title>
|
||||
|
||||
<section id="security-mysql-account">
|
||||
<title>The MySQL System Account</title>
|
||||
|
||||
<para>As mentioned in <xref linkend="security-os-accounts"/>, the MySQL
|
||||
daemon should run as a non-privileged, unique user. Be sure to consult
|
||||
the MySQL documentation or the documentation that came with your system
|
||||
for instructions.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="security-mysql-root">
|
||||
<title>The MySQL <quote>root</quote> and <quote>anonymous</quote> Users</title>
|
||||
|
||||
<para>By default, MySQL comes with a <quote>root</quote> user with a
|
||||
blank password and an <quote>anonymous</quote> user, also with a blank
|
||||
password. In order to protect your data, the <quote>root</quote> user
|
||||
should be given a password and the anonymous user should be disabled.
|
||||
</para>
|
||||
|
||||
<example id="security-mysql-account-root">
|
||||
<title>Assigning the MySQL <quote>root</quote> User a Password</title>
|
||||
|
||||
<screen>
|
||||
<prompt>bash$</prompt> mysql mysql
|
||||
<prompt>mysql></prompt> UPDATE user SET password = password('<replaceable>new_password</replaceable>') WHERE user = 'root';
|
||||
<prompt>mysql></prompt> FLUSH PRIVILEGES;
|
||||
</screen>
|
||||
</example>
|
||||
|
||||
<example id="security-mysql-account-anonymous">
|
||||
<title>Disabling the MySQL <quote>anonymous</quote> User</title>
|
||||
<screen>
|
||||
<prompt>bash$</prompt> mysql -u root -p mysql <co id="security-mysql-account-anonymous-mysql"/>
|
||||
<prompt>Enter Password:</prompt> <replaceable>new_password</replaceable>
|
||||
<prompt>mysql></prompt> DELETE FROM user WHERE user = '';
|
||||
<prompt>mysql></prompt> FLUSH PRIVILEGES;
|
||||
</screen>
|
||||
<calloutlist>
|
||||
<callout arearefs="security-mysql-account-anonymous-mysql">
|
||||
<para>This command assumes that you have already completed
|
||||
<xref linkend="security-mysql-account-root"/>.
|
||||
</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
</example>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="security-mysql-network">
|
||||
<title>Network Access</title>
|
||||
|
||||
<para>If MySQL and your web server both run on the same machine and you
|
||||
have no other reason to access MySQL remotely, then you should disable
|
||||
the network access. This, along with the suggestion in
|
||||
<xref linkend="security-os-ports"/>, will help protect your system from
|
||||
any remote vulnerabilities in MySQL.
|
||||
</para>
|
||||
|
||||
<example id="security-mysql-network-ex">
|
||||
<title>Disabling Networking in MySQL</title>
|
||||
|
||||
<para>Simply enter the following in <filename>/etc/my.cnf</filename>:
|
||||
<screen>
|
||||
[mysqld]
|
||||
# Prevent network access to MySQL.
|
||||
skip-networking
|
||||
</screen>
|
||||
</para>
|
||||
</example>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!-- For possible addition in the future: How to better control the bugs user
|
||||
<section id="security-mysql-bugs">
|
||||
<title>The bugs User</title>
|
||||
|
||||
</section>
|
||||
-->
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section id="security-webserver">
|
||||
<title>Web server</title>
|
||||
|
||||
<section id="security-webserver-access">
|
||||
<title>Disabling Remote Access to Bugzilla Configuration Files</title>
|
||||
|
||||
<para>
|
||||
There are many files that are placed in the Bugzilla directory
|
||||
area that should not be accessible from the web server. Because of the way
|
||||
Bugzilla is currently layed out, the list of what should and should not
|
||||
be accessible is rather complicated. A quick way is to run
|
||||
<filename>testserver.pl</filename> to check if your web server serves
|
||||
Bugzilla files as expected. If not, you may want to follow the few
|
||||
steps below.
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<para>Bugzilla ships with the ability to create
|
||||
<glossterm linkend="gloss-htaccess"><filename>.htaccess</filename></glossterm>
|
||||
files that enforce these rules. Instructions for enabling these
|
||||
directives in Apache can be found in <xref linkend="http-apache"/>
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>In the main Bugzilla directory, you should:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block:
|
||||
<simplelist type="inline">
|
||||
<member><filename>*.pl</filename></member>
|
||||
<member><filename>*localconfig*</filename></member>
|
||||
</simplelist>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>In <filename class="directory">data</filename>:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block everything</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>In <filename class="directory">data/webdot</filename>:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>If you use a remote webdot server:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block everything</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>But allow
|
||||
<simplelist type="inline">
|
||||
<member><filename>*.dot</filename></member>
|
||||
</simplelist>
|
||||
only for the remote webdot server</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Otherwise, if you use a local GraphViz:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block everything</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>But allow:
|
||||
<simplelist type="inline">
|
||||
<member><filename>*.png</filename></member>
|
||||
<member><filename>*.gif</filename></member>
|
||||
<member><filename>*.jpg</filename></member>
|
||||
<member><filename>*.map</filename></member>
|
||||
</simplelist>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>And if you don't use any dot:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block everything</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>In <filename class="directory">Bugzilla</filename>:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block everything</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>In <filename class="directory">template</filename>:</para>
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>Block everything</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Be sure to test that data that should not be accessed remotely is
|
||||
properly blocked. Of particular interest is the localconfig file which
|
||||
contains your database password. Also, be aware that many editors
|
||||
create temporary and backup files in the working directory and that
|
||||
those should also not be accessible. For more information, see
|
||||
<ulink url="http://bugzilla.mozilla.org/show_bug.cgi?id=186383">bug 186383</ulink>
|
||||
or
|
||||
<ulink url="http://online.securityfocus.com/bid/6501">Bugtraq ID 6501</ulink>.
|
||||
To test, simply run <filename>testserver.pl</filename>, as said above.
|
||||
</para>
|
||||
|
||||
<tip>
|
||||
<para>Be sure to check <xref linkend="http"/> for instructions
|
||||
specific to the web server you use.
|
||||
</para>
|
||||
</tip>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section id="security-bugzilla">
|
||||
<title>Bugzilla</title>
|
||||
|
||||
<section id="security-bugzilla-charset">
|
||||
<title>Prevent users injecting malicious Javascript</title>
|
||||
|
||||
<para>If you installed Bugzilla version 2.22 or later from scratch,
|
||||
then the <emphasis>utf8</emphasis> parameter is switched on by default.
|
||||
This makes Bugzilla explicitly set the character encoding, following
|
||||
<ulink
|
||||
url="http://www.cert.org/tech_tips/malicious_code_mitigation.html#3">a
|
||||
CERT advisory</ulink> recommending exactly this.
|
||||
The following therefore does not apply to you; just keep
|
||||
<emphasis>utf8</emphasis> turned on.
|
||||
</para>
|
||||
|
||||
<para>If you've upgraded from an older version, then it may be possible
|
||||
for a Bugzilla user to take advantage of character set encoding
|
||||
ambiguities to inject HTML into Bugzilla comments.
|
||||
This could include malicious scripts.
|
||||
This is because due to internationalization concerns, we are unable to
|
||||
turn the <emphasis>utf8</emphasis> parameter on by default for upgraded
|
||||
installations.
|
||||
Turning it on manually will prevent this problem.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End: -->
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
||||
<!ENTITY % myents SYSTEM "bugzilla.ent">
|
||||
%myents;
|
||||
]>
|
||||
<!-- $Id: troubleshooting.xml,v 1.13.4.1 2008-07-13 16:44:28 mozilla%colinogilvie.co.uk Exp $ -->
|
||||
|
||||
<appendix id="troubleshooting">
|
||||
<title>Troubleshooting</title>
|
||||
|
||||
<para>This section gives solutions to common Bugzilla installation
|
||||
problems. If none of the section headings seems to match your
|
||||
problem, read the general advice.
|
||||
</para>
|
||||
|
||||
<section id="general-advice">
|
||||
<title>General Advice</title>
|
||||
<para>If you can't get <filename>checksetup.pl</filename> to run to
|
||||
completion, it normally explains what's wrong and how to fix it.
|
||||
If you can't work it out, or if it's being uncommunicative, post
|
||||
the errors in the
|
||||
<ulink url="news://news.mozilla.org/mozilla.support.bugzilla">mozilla.support.bugzilla</ulink>
|
||||
newsgroup.
|
||||
</para>
|
||||
|
||||
<para>If you have made it all the way through
|
||||
<xref linkend="installation"/> (Installation) and
|
||||
<xref linkend="configuration"/> (Configuration) but accessing the Bugzilla
|
||||
URL doesn't work, the first thing to do is to check your web server error
|
||||
log. For Apache, this is often located at
|
||||
<filename>/etc/logs/httpd/error_log</filename>. The error messages
|
||||
you see may be self-explanatory enough to enable you to diagnose and
|
||||
fix the problem. If not, see below for some commonly-encountered
|
||||
errors. If that doesn't help, post the errors to the newsgroup.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Bugzilla can also log all user-based errors (and many code-based errors)
|
||||
that occur, without polluting the web server's error log. To enable
|
||||
Bugzilla error logging, create a file that Bugzilla can write to, named
|
||||
<filename>errorlog</filename>, in the Bugzilla <filename>data</filename>
|
||||
directory. Errors will be logged as they occur, and will include the type
|
||||
of the error, the IP address and username (if available) of the user who
|
||||
triggered the error, and the values of all environment variables; if a
|
||||
form was being submitted, the data in the form will also be included.
|
||||
To disable error logging, delete or rename the
|
||||
<filename>errorlog</filename> file.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="trbl-testserver">
|
||||
<title>The Apache web server is not serving Bugzilla pages</title>
|
||||
<para>After you have run <command>checksetup.pl</command> twice,
|
||||
run <command>testserver.pl http://yoursite.yourdomain/yoururl</command>
|
||||
to confirm that your web server is configured properly for
|
||||
Bugzilla.
|
||||
</para>
|
||||
<programlisting>
|
||||
<prompt>bash$</prompt> ./testserver.pl http://landfill.bugzilla.org/bugzilla-tip
|
||||
TEST-OK Webserver is running under group id in $webservergroup.
|
||||
TEST-OK Got ant picture.
|
||||
TEST-OK Webserver is executing CGIs.
|
||||
TEST-OK Webserver is preventing fetch of http://landfill.bugzilla.org/bugzilla-tip/localconfig.
|
||||
</programlisting>
|
||||
</section>
|
||||
|
||||
<section id="trbl-perlmodule">
|
||||
<title>I installed a Perl module, but
|
||||
<filename>checksetup.pl</filename> claims it's not installed!</title>
|
||||
|
||||
<para>This could be caused by one of two things:</para>
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>You have two versions of Perl on your machine. You are installing
|
||||
modules into one, and Bugzilla is using the other. Rerun the CPAN
|
||||
commands (or manual compile) using the full path to Perl from the
|
||||
top of <filename>checksetup.pl</filename>. This will make sure you
|
||||
are installing the modules in the right place.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The permissions on your library directories are set incorrectly.
|
||||
They must, at the very least, be readable by the web server user or
|
||||
group. It is recommended that they be world readable.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</section>
|
||||
|
||||
<section id="trbl-dbdSponge">
|
||||
<title>DBD::Sponge::db prepare failed</title>
|
||||
|
||||
<para>The following error message may appear due to a bug in DBD::mysql
|
||||
(over which the Bugzilla team have no control):
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[ DBD::Sponge::db prepare failed: Cannot determine NUM_OF_FIELDS at D:/Perl/site/lib/DBD/mysql.pm line 248.
|
||||
SV = NULL(0x0) at 0x20fc444
|
||||
REFCNT = 1
|
||||
FLAGS = (PADBUSY,PADMY)
|
||||
]]></programlisting>
|
||||
|
||||
<para>To fix this, go to
|
||||
<filename><path-to-perl>/lib/DBD/sponge.pm</filename>
|
||||
in your Perl installation and replace
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[ my $numFields;
|
||||
if ($attribs->{'NUM_OF_FIELDS'}) {
|
||||
$numFields = $attribs->{'NUM_OF_FIELDS'};
|
||||
} elsif ($attribs->{'NAME'}) {
|
||||
$numFields = @{$attribs->{NAME}};
|
||||
]]></programlisting>
|
||||
|
||||
<para>with</para>
|
||||
|
||||
<programlisting><![CDATA[ my $numFields;
|
||||
if ($attribs->{'NUM_OF_FIELDS'}) {
|
||||
$numFields = $attribs->{'NUM_OF_FIELDS'};
|
||||
} elsif ($attribs->{'NAMES'}) {
|
||||
$numFields = @{$attribs->{NAMES}};
|
||||
]]></programlisting>
|
||||
|
||||
<para>(note the S added to NAME.)</para>
|
||||
</section>
|
||||
|
||||
<section id="paranoid-security">
|
||||
<title>cannot chdir(/var/spool/mqueue)</title>
|
||||
|
||||
<para>If you are installing Bugzilla on SuSE Linux, or some other
|
||||
distributions with <quote>paranoid</quote> security options, it is
|
||||
possible that the checksetup.pl script may fail with the error:
|
||||
<programlisting><![CDATA[cannot chdir(/var/spool/mqueue): Permission denied
|
||||
]]></programlisting>
|
||||
</para>
|
||||
|
||||
<para>This is because your <filename>/var/spool/mqueue</filename>
|
||||
directory has a mode of <computeroutput>drwx------</computeroutput>.
|
||||
Type <command>chmod 755 <filename>/var/spool/mqueue</filename></command>
|
||||
as root to fix this problem. This will allow any process running on your
|
||||
machine the ability to <emphasis>read</emphasis> the
|
||||
<filename>/var/spool/mqueue</filename> directory.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="trbl-relogin-everyone">
|
||||
<title>Everybody is constantly being forced to relogin</title>
|
||||
|
||||
<para>The most-likely cause is that the <quote>cookiepath</quote> parameter
|
||||
is not set correctly in the Bugzilla configuration. You can change this (if
|
||||
you're a Bugzilla administrator) from the editparams.cgi page via the web interface.
|
||||
</para>
|
||||
|
||||
<para>The value of the cookiepath parameter should be the actual directory
|
||||
containing your Bugzilla installation, <emphasis>as seen by the end-user's
|
||||
web browser</emphasis>. Leading and trailing slashes are mandatory. You can
|
||||
also set the cookiepath to any directory which is a parent of the Bugzilla
|
||||
directory (such as '/', the root directory). But you can't put something
|
||||
that isn't at least a partial match or it won't work. What you're actually
|
||||
doing is restricting the end-user's browser to sending the cookies back only
|
||||
to that directory.
|
||||
</para>
|
||||
|
||||
<para>How do you know if you want your specific Bugzilla directory or the
|
||||
whole site?
|
||||
</para>
|
||||
|
||||
<para>If you have only one Bugzilla running on the server, and you don't
|
||||
mind having other applications on the same server with it being able to see
|
||||
the cookies (you might be doing this on purpose if you have other things on
|
||||
your site that share authentication with Bugzilla), then you'll want to have
|
||||
the cookiepath set to "/", or to a sufficiently-high enough directory that
|
||||
all of the involved apps can see the cookies.
|
||||
</para>
|
||||
|
||||
<example id="trbl-relogin-everyone-share">
|
||||
<title>Examples of urlbase/cookiepath pairs for sharing login cookies</title>
|
||||
|
||||
<blockquote>
|
||||
<literallayout>
|
||||
urlbase is <ulink url="http://bugzilla.mozilla.org/"/>
|
||||
cookiepath is /
|
||||
|
||||
urlbase is <ulink url="http://tools.mysite.tld/bugzilla/"/>
|
||||
but you have http://tools.mysite.tld/someotherapp/ which shares
|
||||
authentication with your Bugzilla
|
||||
cookiepath is /
|
||||
</literallayout>
|
||||
</blockquote>
|
||||
</example>
|
||||
|
||||
<para>On the other hand, if you have more than one Bugzilla running on the
|
||||
server (some people do - we do on landfill) then you need to have the
|
||||
cookiepath restricted enough so that the different Bugzillas don't
|
||||
confuse their cookies with one another.
|
||||
</para>
|
||||
|
||||
|
||||
<example id="trbl-relogin-everyone-restrict">
|
||||
<title>Examples of urlbase/cookiepath pairs to restrict the login cookie</title>
|
||||
<blockquote>
|
||||
<literallayout>
|
||||
urlbase is <ulink url="http://landfill.bugzilla.org/bugzilla-tip/"/>
|
||||
cookiepath is /bugzilla-tip/
|
||||
|
||||
urlbase is <ulink url="http://landfill.bugzilla.org/bugzilla-2.16-branch/"/>
|
||||
cookiepath is /bugzilla-2.16-branch/
|
||||
</literallayout>
|
||||
</blockquote>
|
||||
</example>
|
||||
|
||||
<para>If you had cookiepath set to <quote>/</quote> at any point in the
|
||||
past and need to set it to something more restrictive
|
||||
(i.e. <quote>/bugzilla/</quote>), you can safely do this without
|
||||
requiring users to delete their Bugzilla-related cookies in their
|
||||
browser (this is true starting with Bugzilla 2.18 and Bugzilla 2.16.5).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="trbl-relogin-some">
|
||||
<title>Some users are constantly being forced to relogin</title>
|
||||
|
||||
<para>First, make sure cookies are enabled in the user's browser.
|
||||
</para>
|
||||
|
||||
<para>If that doesn't fix the problem, it may be that the user's ISP
|
||||
implements a rotating proxy server. This causes the user's effective IP
|
||||
address (the address which the Bugzilla server perceives him coming from)
|
||||
to change periodically. Since Bugzilla cookies are tied to a specific IP
|
||||
address, each time the effective address changes, the user will have to
|
||||
log in again.
|
||||
</para>
|
||||
|
||||
<para>If you are using 2.18 (or later), there is a
|
||||
parameter called <quote>loginnetmask</quote>, which you can use to set
|
||||
the number of bits of the user's IP address to require to be matched when
|
||||
authenticating the cookies. If you set this to something less than 32,
|
||||
then the user will be given a checkbox for <quote>Restrict this login to
|
||||
my IP address</quote> on the login screen, which defaults to checked. If
|
||||
they leave the box checked, Bugzilla will behave the same as it did
|
||||
before, requiring an exact match on their IP address to remain logged in.
|
||||
If they uncheck the box, then only the left side of their IP address (up
|
||||
to the number of bits you specified in the parameter) has to match to
|
||||
remain logged in.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="trbl-index">
|
||||
<title><filename>index.cgi</filename> doesn't show up unless specified in the URL</title>
|
||||
<para>
|
||||
You probably need to set up your web server in such a way that it
|
||||
will serve the index.cgi page as an index page.
|
||||
</para>
|
||||
<para>
|
||||
If you are using Apache, you can do this by adding
|
||||
<filename>index.cgi</filename> to the end of the
|
||||
<computeroutput>DirectoryIndex</computeroutput> line
|
||||
as mentioned in <xref linkend="http-apache"/>.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="trbl-passwd-encryption">
|
||||
<title>
|
||||
checksetup.pl reports "Client does not support authentication protocol
|
||||
requested by server..."
|
||||
</title>
|
||||
|
||||
<para>
|
||||
This error is occurring because you are using the new password
|
||||
encryption that comes with MySQL 4.1, while your
|
||||
<filename>DBD::mysql</filename> module was compiled against an
|
||||
older version of MySQL. If you recompile <filename>DBD::mysql</filename>
|
||||
against the current MySQL libraries (or just obtain a newer version
|
||||
of this module) then the error may go away.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If that does not fix the problem, or if you cannot recompile the
|
||||
existing module (e.g. you're running Windows) and/or don't want to
|
||||
replace it (e.g. you want to keep using a packaged version), then a
|
||||
workaround is available from the MySQL docs:
|
||||
<ulink url="http://dev.mysql.com/doc/mysql/en/Old_client.html"/>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</appendix>
|
||||
|
||||
<!-- Keep this comment at the end of the file
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-always-quote-attributes:t
|
||||
sgml-auto-insert-required-elements:t
|
||||
sgml-balanced-tag-edit:t
|
||||
sgml-exposed-tags:nil
|
||||
sgml-general-insert-case:lower
|
||||
sgml-indent-data:t
|
||||
sgml-indent-step:2
|
||||
sgml-local-catalogs:nil
|
||||
sgml-local-ecat-files:nil
|
||||
sgml-minimize-attributes:nil
|
||||
sgml-namecase-general:t
|
||||
sgml-omittag:t
|
||||
sgml-parent-document:("Bugzilla-Guide.xml" "book" "chapter")
|
||||
sgml-shorttag:t
|
||||
sgml-tag-region-if-active:t
|
||||
End: -->
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,217 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public
|
||||
# License Version 1.1 (the "License"); you may not use this file
|
||||
# except in compliance with the License. You may obtain a copy of
|
||||
# the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS
|
||||
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is the Bugzilla Bug Tracking System.
|
||||
#
|
||||
# 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): Matthew Tuck <matty@chariot.net.au>
|
||||
# Jacob Steenhagen <jake@bugzilla.org>
|
||||
# Colin Ogilvie <colin.ogilvie@gmail.com>
|
||||
# Max Kanat-Alexander <mkanat@bugzilla.org>
|
||||
|
||||
# This script compiles all the documentation.
|
||||
|
||||
use strict;
|
||||
use Cwd;
|
||||
|
||||
# We need to be in this directory to use our libraries.
|
||||
BEGIN {
|
||||
require File::Basename;
|
||||
import File::Basename qw(dirname);
|
||||
chdir dirname($0);
|
||||
}
|
||||
|
||||
use lib qw(.. ../lib lib);
|
||||
|
||||
# We only compile our POD if Pod::Simple is installed. We do the checks
|
||||
# this way so that if there's a compile error in Pod::Simple::HTML::Bugzilla,
|
||||
# makedocs doesn't just silently fail, but instead actually tells us there's
|
||||
# a compile error.
|
||||
my $pod_simple;
|
||||
if (eval { require Pod::Simple }) {
|
||||
require Pod::Simple::HTMLBatch::Bugzilla;
|
||||
require Pod::Simple::HTML::Bugzilla;
|
||||
$pod_simple = 1;
|
||||
};
|
||||
|
||||
use Bugzilla::Install::Requirements
|
||||
qw(REQUIRED_MODULES OPTIONAL_MODULES);
|
||||
use Bugzilla::Constants qw(DB_MODULE BUGZILLA_VERSION);
|
||||
|
||||
###############################################################################
|
||||
# Generate minimum version list
|
||||
###############################################################################
|
||||
|
||||
my $modules = REQUIRED_MODULES;
|
||||
my $opt_modules = OPTIONAL_MODULES;
|
||||
|
||||
open(ENTITIES, '>', 'bugzilla.ent') or die('Could not open bugzilla.ent: ' . $!);
|
||||
print ENTITIES <<END_ENTITIES;
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!ENTITY bz-ver "3.3">
|
||||
<!ENTITY bz-nextver "4.0">
|
||||
<!ENTITY bz-date "2008-05-20">
|
||||
<!ENTITY current-year "2008">
|
||||
|
||||
<!ENTITY landfillbase "http://landfill.bugzilla.org/bugzilla-tip/">
|
||||
<!ENTITY bz "http://www.bugzilla.org/">
|
||||
<!ENTITY bzg-bugs "<ulink url='https://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&component=Documentation'>Bugzilla Documentation</ulink>">
|
||||
<!ENTITY mysql "http://www.mysql.com/">
|
||||
|
||||
<!ENTITY min-perl-ver "5.8.1">
|
||||
|
||||
|
||||
<!-- Module Versions -->
|
||||
END_ENTITIES
|
||||
foreach my $module (@$modules, @$opt_modules)
|
||||
{
|
||||
my $name = $module->{'module'};
|
||||
$name =~ s/::/-/g;
|
||||
$name = lc($name);
|
||||
#This needs to be a string comparison, due to the modules having
|
||||
#version numbers like 0.9.4
|
||||
my $version = $module->{'version'} eq 0 ? 'any' : $module->{'version'};
|
||||
print ENTITIES '<!ENTITY min-' . $name . '-ver "'.$version.'">' . "\n";
|
||||
}
|
||||
|
||||
# CGI is a special case, because for Perl versions below 5.10, it has an
|
||||
# optional version *and* a required version.
|
||||
# We check @opt_modules first, then @modules, and pick the first we get.
|
||||
# We'll get the optional one then, if it is given, otherwise the required one.
|
||||
my ($cgi_opt) = grep($_->{module} eq 'CGI', @$opt_modules, @$modules);
|
||||
print ENTITIES '<!ENTITY min-mp-cgi-ver "' . $cgi_opt->{version} . '">' . "\n";
|
||||
|
||||
print ENTITIES "\n <!-- Database Versions --> \n";
|
||||
|
||||
my $db_modules = DB_MODULE;
|
||||
foreach my $db (keys %$db_modules) {
|
||||
my $dbd = $db_modules->{$db}->{dbd};
|
||||
my $name = $dbd->{module};
|
||||
$name =~ s/::/-/g;
|
||||
$name = lc($name);
|
||||
my $version = $dbd->{version} || 'any';
|
||||
my $db_version = $db_modules->{$db}->{'db_version'};
|
||||
print ENTITIES '<!ENTITY min-' . $name . '-ver "'.$version.'">' . "\n";
|
||||
print ENTITIES '<!ENTITY min-' . lc($db) . '-ver "'.$db_version.'">' . "\n";
|
||||
}
|
||||
close(ENTITIES);
|
||||
|
||||
###############################################################################
|
||||
# Subs
|
||||
###############################################################################
|
||||
|
||||
sub MakeDocs {
|
||||
|
||||
my ($name, $cmdline) = @_;
|
||||
|
||||
print "Creating $name documentation ...\n" if defined $name;
|
||||
print "$cmdline\n\n";
|
||||
system $cmdline;
|
||||
print "\n";
|
||||
|
||||
}
|
||||
|
||||
sub make_pod {
|
||||
|
||||
print "Creating API documentation...\n";
|
||||
|
||||
my $converter = Pod::Simple::HTMLBatch::Bugzilla->new;
|
||||
# Don't output progress information.
|
||||
$converter->verbose(0);
|
||||
$converter->html_render_class('Pod::Simple::HTML::Bugzilla');
|
||||
|
||||
my $doctype = Pod::Simple::HTML::Bugzilla->DOCTYPE;
|
||||
my $content_type = Pod::Simple::HTML::Bugzilla->META_CT;
|
||||
my $bz_version = BUGZILLA_VERSION;
|
||||
|
||||
my $contents_start = <<END_HTML;
|
||||
$doctype
|
||||
<html>
|
||||
<head>
|
||||
$content_type
|
||||
<title>Bugzilla $bz_version API Documentation</title>
|
||||
</head>
|
||||
<body class="contentspage">
|
||||
<h1>Bugzilla $bz_version API Documentation</h1>
|
||||
END_HTML
|
||||
|
||||
$converter->contents_page_start($contents_start);
|
||||
$converter->contents_page_end("</body></html>");
|
||||
$converter->add_css('./../../../style.css');
|
||||
$converter->javascript_flurry(0);
|
||||
$converter->css_flurry(0);
|
||||
$converter->batch_convert(['../../'], 'html/api/');
|
||||
|
||||
print "\n";
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
# Make the docs ...
|
||||
###############################################################################
|
||||
|
||||
my @langs;
|
||||
# search for sub directories which have a 'xml' sub-directory
|
||||
opendir(LANGS, './');
|
||||
foreach my $dir (readdir(LANGS)) {
|
||||
next if (($dir eq '.') || ($dir eq '..') || (! -d $dir));
|
||||
if (-d "$dir/xml") {
|
||||
push(@langs, $dir);
|
||||
}
|
||||
}
|
||||
closedir(LANGS);
|
||||
|
||||
my $docparent = getcwd();
|
||||
foreach my $lang (@langs) {
|
||||
chdir "$docparent/$lang";
|
||||
MakeDocs(undef, 'cp ../bugzilla.ent ./xml/');
|
||||
|
||||
if (!-d 'txt') {
|
||||
unlink 'txt';
|
||||
mkdir 'txt', 0755;
|
||||
}
|
||||
if (!-d 'pdf') {
|
||||
unlink 'pdf';
|
||||
mkdir 'pdf', 0755;
|
||||
}
|
||||
if (!-d 'html') {
|
||||
unlink 'html';
|
||||
mkdir 'html', 0755;
|
||||
}
|
||||
if (!-d 'html/api') {
|
||||
unlink 'html/api';
|
||||
mkdir 'html/api', 0755;
|
||||
}
|
||||
|
||||
MakeDocs(undef, 'cp ../style.css html/api/');
|
||||
|
||||
make_pod() if $pod_simple;
|
||||
|
||||
MakeDocs('separate HTML', 'xmlto -m ../xsl/chunks.xsl -o html html ' .
|
||||
'xml/Bugzilla-Guide.xml');
|
||||
MakeDocs('big HTML', 'xmlto -m ../xsl/nochunks.xsl -o html html-nochunks ' .
|
||||
'xml/Bugzilla-Guide.xml');
|
||||
MakeDocs('big text', "lynx -dump -justify=off -nolist html/Bugzilla-Guide.html " .
|
||||
"> txt/Bugzilla-Guide.txt");
|
||||
|
||||
if (! grep($_ eq "--with-pdf", @ARGV)) {
|
||||
next;
|
||||
}
|
||||
|
||||
MakeDocs('PDF', 'xmlto -m ../xsl/pdf.xsl -o pdf pdf xml/Bugzilla-Guide.xml');
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Bugzilla Bug Tracking System.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Everything Solved.
|
||||
* Portions created by Everything Solved are Copyright (C) 2006
|
||||
* Everything Solved. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Max Kanat-Alexander <mkanat@bugzilla.org>
|
||||
*/
|
||||
|
||||
body {
|
||||
background: white;
|
||||
color: #111;
|
||||
padding: 0 1em;
|
||||
margin: 0;
|
||||
font-family: Verdana, Arial, sans-serif;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
td, th {
|
||||
font-family: Verdana, Arial, sans-serif;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
a:link, a:active { color: #36415c; }
|
||||
a:visited { color: #666; }
|
||||
a:hover { color: #888; }
|
||||
|
||||
h1 {
|
||||
font-size: 150%;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid #ccc;
|
||||
}
|
||||
h2 {
|
||||
font-size: 125%;
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 115%;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
/* This makes Description/Params/Returns look nice. */
|
||||
dd { margin-top: .2em; }
|
||||
dd p { margin-top: 0; }
|
||||
dl { margin-bottom: 1em; }
|
||||
|
||||
/* This makes the names of functions slightly larger, in Gecko. */
|
||||
body > dl > dt code { font-size: 1.35em; }
|
||||
|
||||
#pod h1 a, #pod h2 a, #pod h3 a {
|
||||
color: #36415c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre, code, tt, kbd, samp {
|
||||
/* Unfortunately, the default monospace fonts on most browsers
|
||||
look odd with relative sizing. */
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.code {
|
||||
background: #eed;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
pre.code {
|
||||
margin-left: 10px;
|
||||
width: 90%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Special styles for the Contents page */
|
||||
|
||||
.contentspage dt {
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pod_desc_table {
|
||||
border-collapse: collapse;
|
||||
table-layout: auto;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.pod_desc_table th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pod_desc_table td, .pod_desc_table th {
|
||||
padding: .25em;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.pod_desc_table .odd th, .pod_desc_table .odd td {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.pod_desc_table
|
||||
@@ -1,102 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
|
||||
<!-- Nicer Filenames -->
|
||||
<xsl:param name="use.id.as.filename" select="1"/>
|
||||
|
||||
<!-- Label sections if they aren't automatically labeled -->
|
||||
<xsl:param name="section.autolabel" select="1"/>
|
||||
|
||||
<!-- Table of Contents Depth -->
|
||||
<xsl:param name="toc.section.depth">1</xsl:param>
|
||||
|
||||
<!-- Set chunk parameters -->
|
||||
<xsl:param name="chunk.section.depth" select="1"/>
|
||||
<xsl:param name="chunk.first.sections" select="1"/>
|
||||
<xsl:param name="chunker.output.encoding" select="UTF-8"/>
|
||||
|
||||
<!-- Show titles of next/previous page -->
|
||||
<xsl:param name="navig.showtitles">1</xsl:param>
|
||||
|
||||
<!-- Tidy up the HTML a bit... -->
|
||||
<xsl:param name="html.cleanup" select="1"/>
|
||||
<xsl:param name="make.valid.html" select="1"/>
|
||||
<xsl:param name="html.stylesheet">api/style.css</xsl:param>
|
||||
<!-- make links nicer... -->
|
||||
<xsl:param name="refentry.generate.title" select="1"/>
|
||||
<xsl:param name="refentry.generate.name" select="0"/>
|
||||
|
||||
<!-- Use Graphics, specify their Path and Extension -->
|
||||
<xsl:param name="admon.graphics" select="1"/>
|
||||
<xsl:param name="admon.graphics.path">../images/</xsl:param>
|
||||
<xsl:param name="admon.graphics.extension">.gif</xsl:param>
|
||||
|
||||
<xsl:param name="qanda.inherit.numeration" select="0" />
|
||||
|
||||
<!--
|
||||
****
|
||||
CODE BELOW HERE IS EXTRACTED AND EDITED FROM THE DOCBOOK XSL SOURCES
|
||||
****
|
||||
-->
|
||||
|
||||
<xsl:template match="simplelist[@type='inline']/member">
|
||||
<xsl:apply-templates/>
|
||||
</xsl:template>
|
||||
|
||||
<!--
|
||||
To generate valid HTML, we need to redefine this section... Code extracted from
|
||||
http://cvs.sourceforge.net/viewcvs.py/docbook/xsl/html/qandaset.xsl?rev=1.19&view=log
|
||||
|
||||
and modified below. Basic change: Remove the colspan attribute of the tr tags - no
|
||||
other changes have been made to the document.
|
||||
-->
|
||||
|
||||
<xsl:template match="qandadiv">
|
||||
<xsl:variable name="preamble" select="*[name(.) != 'title'
|
||||
and name(.) != 'titleabbrev'
|
||||
and name(.) != 'qandadiv'
|
||||
and name(.) != 'qandaentry']"/>
|
||||
|
||||
<xsl:if test="blockinfo/title|title">
|
||||
<tr class="qandadiv">
|
||||
<td align="left" valign="top" colspan="2">
|
||||
<xsl:call-template name="anchor">
|
||||
<xsl:with-param name="conditional" select="0"/>
|
||||
</xsl:call-template>
|
||||
<xsl:apply-templates select="(blockinfo/title|title)[1]"/>
|
||||
</td>
|
||||
</tr>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:variable name="toc">
|
||||
<xsl:call-template name="dbhtml-attribute">
|
||||
<xsl:with-param name="pis"
|
||||
select="processing-instruction('dbhtml')"/>
|
||||
<xsl:with-param name="attribute" select="'toc'"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:variable name="toc.params">
|
||||
<xsl:call-template name="find.path.params">
|
||||
<xsl:with-param name="table" select="normalize-space($generate.toc)"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:if test="(contains($toc.params, 'toc') and $toc != '0') or $toc = '1'">
|
||||
<tr class="toc">
|
||||
<td align="left" valign="top" colspan="2">
|
||||
<xsl:call-template name="process.qanda.toc"/>
|
||||
</td>
|
||||
</tr>
|
||||
</xsl:if>
|
||||
<xsl:if test="$preamble">
|
||||
<tr class="toc" >
|
||||
<td align="left" valign="top" colspan="2">
|
||||
<xsl:apply-templates select="$preamble"/>
|
||||
</td>
|
||||
</tr>
|
||||
</xsl:if>
|
||||
<xsl:apply-templates select="qandadiv|qandaentry"/>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<!-- Include default bugzilla XSL -->
|
||||
<xsl:include href="bugzilla-docs.xsl"/>
|
||||
<!-- Set Chunk Specific XSL Params -->
|
||||
<xsl:param name="chunker.output.doctype-public">-//W3C//DTD HTML 4.01 Transitional//EN</xsl:param>
|
||||
<xsl:param name="chunker.output.doctype-system">http://www.w3.org/TR/html4/loose.dtd</xsl:param>
|
||||
<xsl:param name="chunk.section.depth" select="1"/>
|
||||
<xsl:param name="chunk.first.sections" select="1"/>
|
||||
<!-- Don't output filename list - mimic old behaviour-->
|
||||
<xsl:param name="chunk.quietly" select="0" />
|
||||
</xsl:stylesheet>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
||||
<!-- Include default bugzilla XSL -->
|
||||
<xsl:include href="bugzilla-docs.xsl"/>
|
||||
<!-- No other params necessary -->
|
||||
</xsl:stylesheet>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
|
||||
<!-- Enable passivetex extensions -->
|
||||
<xsl:param name="passivetex.extensions" select="1"/>
|
||||
<xsl:param name="tablecolumns.extensions" select="1"/>
|
||||
|
||||
<!-- Show <ulink>s as footnotes -->
|
||||
<xsl:param name="ulink.footnotes" select="1" />
|
||||
<xsl:param name="ulink.show" select="1" />
|
||||
|
||||
<!-- Don't use Graphics -->
|
||||
<xsl:param name="admon.graphics" select="0"/>
|
||||
<xsl:param name="callout.graphics" select="'0'"/>
|
||||
|
||||
<xsl:template match="simplelist[@type='inline']/member">
|
||||
<xsl:apply-templates/>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
Reference in New Issue
Block a user