Compare commits
24 Commits
regalloc_c
...
LIBREG9902
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd7437a096 | ||
|
|
a6041e3d9e | ||
|
|
467456baed | ||
|
|
07adb3fa4c | ||
|
|
9f7a44c3e2 | ||
|
|
99153e23c5 | ||
|
|
509501efbf | ||
|
|
249c9a91cc | ||
|
|
6100d0195f | ||
|
|
2b0897f6b5 | ||
|
|
9b7b41f2e2 | ||
|
|
acaf468169 | ||
|
|
37c847e5d4 | ||
|
|
4397f139f4 | ||
|
|
07af9a116d | ||
|
|
601c209b84 | ||
|
|
70f44c60cd | ||
|
|
8d0d948e0a | ||
|
|
bdc8aa3c5c | ||
|
|
ffccab09a0 | ||
|
|
fc3851269e | ||
|
|
66a57a8d4a | ||
|
|
faddf412e6 | ||
|
|
d95ce0280d |
@@ -1,134 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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
|
||||
@@ -1,195 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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
|
||||
@@ -1,159 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,283 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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
|
||||
@@ -1,284 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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));
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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
|
||||
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,97 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,213 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,258 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,87 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,163 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,301 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,40 +0,0 @@
|
||||
#! 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)
|
||||
@@ -1,392 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,155 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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;
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
|
||||
@@ -1,355 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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
|
||||
@@ -1,117 +0,0 @@
|
||||
// -*- 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_
|
||||
@@ -1,104 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,168 +0,0 @@
|
||||
// -*- 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_
|
||||
@@ -1,270 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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
|
||||
@@ -1,269 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,239 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
@@ -1,186 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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();
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_ */
|
||||
@@ -1,116 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.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_
|
||||
28
mozilla/modules/libreg/Makefile.in
Normal file
28
mozilla/modules/libreg/Makefile.in
Normal file
@@ -0,0 +1,28 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = include src
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
6
mozilla/modules/libreg/include/MANIFEST
Normal file
6
mozilla/modules/libreg/include/MANIFEST
Normal file
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# This is a list of local files which get copied to the mozilla:dist directory
|
||||
#
|
||||
|
||||
VerReg.h
|
||||
NSReg.h
|
||||
30
mozilla/modules/libreg/include/Makefile.in
Normal file
30
mozilla/modules/libreg/include/Makefile.in
Normal file
@@ -0,0 +1,30 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = libreg
|
||||
|
||||
EXPORTS = VerReg.h NSReg.h
|
||||
EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
249
mozilla/modules/libreg/include/NSReg.h
Normal file
249
mozilla/modules/libreg/include/NSReg.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/* NSReg.h
|
||||
*/
|
||||
#ifndef _NSREG_H_
|
||||
#define _NSREG_H_
|
||||
|
||||
#include "xp_core.h"
|
||||
|
||||
typedef void (*nr_RegPackCallbackFunc) (void *userData, int32 bytes, int32 totalBytes);
|
||||
|
||||
typedef int32 REGERR;
|
||||
typedef int32 RKEY;
|
||||
typedef uint32 REGENUM;
|
||||
typedef void * HREG;
|
||||
|
||||
typedef struct _reginfo
|
||||
{
|
||||
uint16 size; /* must be initialized to sizeof(REGINFO) */
|
||||
uint16 entryType;
|
||||
uint32 entryLength;
|
||||
} REGINFO;
|
||||
|
||||
#define REGERR_OK (0)
|
||||
#define REGERR_FAIL (1)
|
||||
#define REGERR_NOMORE (2)
|
||||
#define REGERR_NOFIND (3)
|
||||
#define REGERR_BADREAD (4)
|
||||
#define REGERR_BADLOCN (5)
|
||||
#define REGERR_PARAM (6)
|
||||
#define REGERR_BADMAGIC (7)
|
||||
#define REGERR_BADCHECK (8)
|
||||
#define REGERR_NOFILE (9)
|
||||
#define REGERR_MEMORY (10)
|
||||
#define REGERR_BUFTOOSMALL (11)
|
||||
#define REGERR_NAMETOOLONG (12)
|
||||
#define REGERR_REGVERSION (13)
|
||||
#define REGERR_DELETED (14)
|
||||
#define REGERR_BADTYPE (15)
|
||||
#define REGERR_NOPATH (16)
|
||||
#define REGERR_BADNAME (17)
|
||||
#define REGERR_READONLY (18)
|
||||
#define REGERR_BADUTF8 (19)
|
||||
|
||||
|
||||
/* Total path length */
|
||||
#define MAXREGPATHLEN (2048)
|
||||
/* Name on the path (including null terminator) */
|
||||
#define MAXREGNAMELEN (512)
|
||||
/* Value of an entry */
|
||||
#define MAXREGVALUELEN (0x7FFF)
|
||||
|
||||
/* Standard keys */
|
||||
#define ROOTKEY_USERS (0x01)
|
||||
#define ROOTKEY_COMMON (0x02)
|
||||
#define ROOTKEY_CURRENT_USER (0x03)
|
||||
#define ROOTKEY_PRIVATE (0x04)
|
||||
|
||||
/* enumeration styles */
|
||||
#define REGENUM_NORMAL (0x00)
|
||||
#define REGENUM_CHILDREN REGENUM_NORMAL
|
||||
#define REGENUM_DESCEND (0x01)
|
||||
#define REGENUM_DEPTH_FIRST (0x02)
|
||||
|
||||
/* entry data types */
|
||||
#define REGTYPE_ENTRY (0x0010)
|
||||
#define REGTYPE_ENTRY_STRING_UTF (REGTYPE_ENTRY + 1)
|
||||
#define REGTYPE_ENTRY_INT32_ARRAY (REGTYPE_ENTRY + 2)
|
||||
#define REGTYPE_ENTRY_BYTES (REGTYPE_ENTRY + 3)
|
||||
#define REGTYPE_ENTRY_FILE (REGTYPE_ENTRY + 4)
|
||||
|
||||
#define REG_DELETE_LIST_KEY "Netscape/Communicator/SoftwareUpdate/Delete List"
|
||||
#define REG_REPLACE_LIST_KEY "Netscape/Communicator/SoftwareUpdate/Replace List"
|
||||
#define REG_UNINSTALL_DIR "Netscape/Communicator/SoftwareUpdate/Uninstall/"
|
||||
|
||||
#define UNINSTALL_NAV_STR "_"
|
||||
|
||||
|
||||
#define UNIX_GLOBAL_FLAG "MOZILLA_SHARED_REGISTRY"
|
||||
|
||||
/* Platform-dependent declspec for library interface */
|
||||
#if defined(XP_PC)
|
||||
#if defined(WIN32)
|
||||
|
||||
#if defined (STANDALONE_REGISTRY)
|
||||
#define VR_INTERFACE(type) __declspec(dllexport) type __cdecl
|
||||
#else
|
||||
#define VR_INTERFACE(type) __declspec(dllexport) type __stdcall
|
||||
#endif
|
||||
|
||||
#elif defined(XP_OS2)
|
||||
#define VR_INTERFACE(type) type _Optlink
|
||||
#else
|
||||
#define VR_INTERFACE(type) type _far _pascal _export
|
||||
#endif
|
||||
#elif defined XP_MAC
|
||||
#define VR_INTERFACE(__x) __declspec(export) __x
|
||||
#else
|
||||
#define VR_INTERFACE(type) type
|
||||
#endif
|
||||
|
||||
XP_BEGIN_PROTOS
|
||||
/* ---------------------------------------------------------------------
|
||||
* Registry API -- General
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegOpen(
|
||||
char *filename, /* reg. file to open (NULL == standard registry) */
|
||||
HREG *hReg /* OUT: handle to opened registry */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegClose(
|
||||
HREG hReg /* handle of open registry to close */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegPack(
|
||||
HREG hReg, /* handle of open registry to pack */
|
||||
void *userData,
|
||||
nr_RegPackCallbackFunc fn
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegGetUsername(
|
||||
char **name /* on return, an alloc'ed copy of the current user name */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegSetUsername(
|
||||
const char *name /* name of current user */
|
||||
);
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Registry API -- Key Management functions
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegAddKey(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* root key */
|
||||
char *path, /* relative path of subkey to add */
|
||||
RKEY *newKey /* if not null returns newly created key */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegDeleteKey(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* root key */
|
||||
char *path /* relative path of subkey to delete */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegGetKey(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* root key */
|
||||
char *path, /* relative path of subkey to find */
|
||||
RKEY *result /* returns RKEY of specified sub-key */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegEnumSubkeys(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
REGENUM *state, /* enum state, must be NULL to start */
|
||||
char *buffer, /* buffer for entry names */
|
||||
uint32 bufsize, /* size of buffer */
|
||||
uint32 style /* 0: children only; REGENUM_DESCEND: sub-tree */
|
||||
);
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* Registry API -- Entry Management functions
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegGetEntryInfo(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
char *name, /* entry name */
|
||||
REGINFO *info /* returned entry info */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegGetEntryString(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
char *name, /* entry name */
|
||||
char *buffer, /* buffer to hold value (UTF String) */
|
||||
uint32 bufsize /* length of buffer */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegGetEntry(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
char *name, /* entry name */
|
||||
void *buffer, /* buffer to hold value */
|
||||
uint32 *size /* in:length of buffer */
|
||||
); /* out: data length, >>includes<< null terminator*/
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegSetEntryString(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
char *name, /* entry name */
|
||||
char *buffer /* UTF String value */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegSetEntry(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
char *name, /* entry name */
|
||||
uint16 type, /* type of value data */
|
||||
void *buffer, /* data buffer */
|
||||
uint32 size /* data length in bytes; incl. null term for strings */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegDeleteEntry(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
char *name /* value name */
|
||||
);
|
||||
|
||||
VR_INTERFACE(REGERR) NR_RegEnumEntries(
|
||||
HREG hReg, /* handle of open registry */
|
||||
RKEY key, /* containing key */
|
||||
REGENUM *state, /* enum state, must be NULL to start */
|
||||
char *buffer, /* buffer for entry names */
|
||||
uint32 bufsize, /* size of buffer */
|
||||
REGINFO *info /* optional; returns info about entry */
|
||||
);
|
||||
|
||||
|
||||
VR_INTERFACE(void) NR_ShutdownRegistry(void);
|
||||
VR_INTERFACE(void) NR_StartupRegistry(void);
|
||||
|
||||
|
||||
XP_END_PROTOS
|
||||
|
||||
#endif /* _NSREG_H_ */
|
||||
|
||||
/* EOF: NSReg.h */
|
||||
|
||||
82
mozilla/modules/libreg/include/VerReg.h
Normal file
82
mozilla/modules/libreg/include/VerReg.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/* VerReg.h
|
||||
* XP Version Registry functions
|
||||
*/
|
||||
#ifndef _VERREG_H_
|
||||
#define _VERREG_H_
|
||||
|
||||
#include "NSReg.h"
|
||||
|
||||
typedef struct _version
|
||||
{
|
||||
int32 major;
|
||||
int32 minor;
|
||||
int32 release;
|
||||
int32 build;
|
||||
int32 check;
|
||||
} VERSION;
|
||||
|
||||
|
||||
/* CreateRegistry flags */
|
||||
#define CR_NEWREGISTRY 1
|
||||
|
||||
XP_BEGIN_PROTOS
|
||||
/* ---------------------------------------------------------------------
|
||||
* Version Registry Operations
|
||||
* ---------------------------------------------------------------------
|
||||
*/
|
||||
/* global registry operations */
|
||||
VR_INTERFACE(REGERR) VR_SetRegDirectory(const char *path);
|
||||
VR_INTERFACE(REGERR) VR_CreateRegistry(char *installation, char *programPath, char *versionStr);
|
||||
VR_INTERFACE(REGERR) VR_PackRegistry(void *userData, nr_RegPackCallbackFunc pdCallbackFunction);
|
||||
VR_INTERFACE(REGERR) VR_Close(void);
|
||||
|
||||
/* component-level functions */
|
||||
VR_INTERFACE(REGERR) VR_Install(char *component_path, char *filepath, char *version, int bDirectory);
|
||||
VR_INTERFACE(REGERR) VR_Remove(char *component_path);
|
||||
VR_INTERFACE(REGERR) VR_InRegistry(char *path);
|
||||
VR_INTERFACE(REGERR) VR_ValidateComponent(char *path);
|
||||
VR_INTERFACE(REGERR) VR_Enum(char *component_path, REGENUM *state, char *buffer, uint32 buflen);
|
||||
|
||||
/* dealing with parts of individual components */
|
||||
VR_INTERFACE(REGERR) VR_GetVersion(char *component_path, VERSION *result);
|
||||
VR_INTERFACE(REGERR) VR_GetPath(char *component_path, uint32 sizebuf, char *buf);
|
||||
VR_INTERFACE(REGERR) VR_SetRefCount(char *component_path, int refcount);
|
||||
VR_INTERFACE(REGERR) VR_GetRefCount(char *component_path, int *result);
|
||||
VR_INTERFACE(REGERR) VR_GetDefaultDirectory(char *component_path, uint32 sizebuf, char *buf);
|
||||
VR_INTERFACE(REGERR) VR_SetDefaultDirectory(char *component_path, char *directory);
|
||||
|
||||
/* uninstall functions */
|
||||
VR_INTERFACE(REGERR) VR_UninstallCreateNode(char *regPackageName, char *userPackageName);
|
||||
VR_INTERFACE(REGERR) VR_UninstallAddFileToList(char *regPackageName, char *vrName);
|
||||
VR_INTERFACE(REGERR) VR_UninstallFileExistsInList(char *regPackageName, char *vrName);
|
||||
VR_INTERFACE(REGERR) VR_UninstallEnumSharedFiles(char *component_path, REGENUM *state, char *buffer, uint32 buflen);
|
||||
VR_INTERFACE(REGERR) VR_UninstallDeleteFileFromList(char *component_path, char *vrName);
|
||||
VR_INTERFACE(REGERR) VR_UninstallDeleteSharedFilesKey(char *regPackageName);
|
||||
VR_INTERFACE(REGERR) VR_UninstallDestroy(char *regPackageName);
|
||||
VR_INTERFACE(REGERR) VR_EnumUninstall(REGENUM *state, char* userPackageName,
|
||||
int32 len1, char*regPackageName, int32 len2, Bool bSharedList);
|
||||
VR_INTERFACE(REGERR) VR_GetUninstallUserName(char *regPackageName, char *outbuf, uint32 buflen);
|
||||
|
||||
XP_END_PROTOS
|
||||
|
||||
#endif /* _VERREG_H_ */
|
||||
|
||||
/* EOF: VerReg.h */
|
||||
|
||||
34
mozilla/modules/libreg/include/makefile.win
Normal file
34
mozilla/modules/libreg/include/makefile.win
Normal file
@@ -0,0 +1,34 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
|
||||
IGNORE_MANIFEST=1
|
||||
|
||||
#
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to install MODULES/LIBREG/INCLUDE header files into the distribution
|
||||
#// directory.
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
MODULE=libreg
|
||||
DEPTH=..\..\..
|
||||
EXPORTS=VerReg.h NSReg.h
|
||||
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
3
mozilla/modules/libreg/macbuild/StandalonePrefix.h
Normal file
3
mozilla/modules/libreg/macbuild/StandalonePrefix.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "MacPrefix.h"
|
||||
|
||||
#define STANDALONE_REGISTRY 1
|
||||
BIN
mozilla/modules/libreg/macbuild/libreg.mcp
Normal file
BIN
mozilla/modules/libreg/macbuild/libreg.mcp
Normal file
Binary file not shown.
26
mozilla/modules/libreg/macbuild/libreg.mcp.exp
Normal file
26
mozilla/modules/libreg/macbuild/libreg.mcp.exp
Normal file
@@ -0,0 +1,26 @@
|
||||
globalRegName
|
||||
NR_ShutdownRegistry
|
||||
NR_StartupRegistry
|
||||
NR_RegEnumEntries
|
||||
NR_RegEnumSubkeys
|
||||
NR_RegDeleteEntry
|
||||
NR_RegSetEntry
|
||||
NR_RegSetEntryString
|
||||
NR_RegGetEntry
|
||||
NR_RegGetEntryString
|
||||
NR_RegGetEntryInfo
|
||||
NR_RegGetKey
|
||||
NR_RegDeleteKey
|
||||
NR_RegAddKey
|
||||
NR_RegPack
|
||||
NR_RegClose
|
||||
NR_RegOpen
|
||||
NR_RegSetUsername
|
||||
NR_RegGetUsername
|
||||
nr_PathFromMacAlias
|
||||
nr_MacAliasFromPath
|
||||
vr_findGlobalRegName
|
||||
#__ptmf_null
|
||||
#longjmp
|
||||
#__terminate
|
||||
#__initialize
|
||||
48
mozilla/modules/libreg/makefile.win
Normal file
48
mozilla/modules/libreg/makefile.win
Normal file
@@ -0,0 +1,48 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build the MODULES\LIBREG tree
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Specify the depth of the current directory relative to the
|
||||
#// root of NS
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DEPTH=..\..
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Specify any "command" targets. (ie. DIRS, INSTALL_FILES, ...)
|
||||
#// (these must come before the common makefiles are included)
|
||||
#//
|
||||
#// DIRS - There are subdirectories to process
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
DIRS=include src standalone
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Include the common makefile rules
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)\config\rules.mak>
|
||||
82
mozilla/modules/libreg/src/Makefile.in
Normal file
82
mozilla/modules/libreg/src/Makefile.in
Normal file
@@ -0,0 +1,82 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = libreg
|
||||
LIBRARY_NAME = reg
|
||||
|
||||
REQUIRES = libreg pref js
|
||||
|
||||
CSRCS = reg.c VerReg.c vr_stubs.c
|
||||
|
||||
BIN_SRCS = VerReg.c reg.c vr_stubs.c
|
||||
BIN_OBJS = $(addprefix $(OBJDIR)/R_,$(BIN_SRCS:.c=.o))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
# Override gtscc when building vreg on IRIX 5.3.
|
||||
ifeq ($(OS_ARCH)$(OS_RELEASE),IRIX5)
|
||||
CC = cc
|
||||
endif
|
||||
|
||||
INCLUDES += -I$(topsrcdir)/include
|
||||
GARBAGE += $(PROGRAM)
|
||||
|
||||
PROGRAM = $(OBJDIR)/vreg$(BIN_SUFFIX)
|
||||
|
||||
$(PROGRAM): $(BIN_OBJS)
|
||||
@$(MAKE_OBJDIR)
|
||||
ifeq ($(OS_ARCH), OS2)
|
||||
$(LINK_EXE) -OUT:$@ $(BIN_OBJS) $(LDFLAGS) $(OS_LIBS)
|
||||
else
|
||||
$(CCF) -o $@ $(BIN_OBJS) $(LDFLAGS)
|
||||
endif
|
||||
|
||||
$(OBJDIR)/R_VerReg.o: VerReg.c
|
||||
@$(MAKE_OBJDIR)
|
||||
ifeq ($(OS_ARCH), OS2)
|
||||
$(CC) -Fo$@ -c $(CFLAGS) -DSTANDALONE_REGISTRY $<
|
||||
else
|
||||
$(CC) -o $@ -c $(CFLAGS) -DSTANDALONE_REGISTRY $<
|
||||
endif
|
||||
|
||||
$(OBJDIR)/R_reg.o: reg.c
|
||||
@$(MAKE_OBJDIR)
|
||||
ifeq ($(OS_ARCH), OS2)
|
||||
$(CC) -Fo$@ -c $(CFLAGS) -DSTANDALONE_REGISTRY $<
|
||||
else
|
||||
$(CC) -o $@ -c $(CFLAGS) -DSTANDALONE_REGISTRY $<
|
||||
endif
|
||||
|
||||
$(OBJDIR)/R_vr_stubs.o: vr_stubs.c
|
||||
@$(MAKE_OBJDIR)
|
||||
ifeq ($(OS_ARCH), OS2)
|
||||
$(CC) -Fo$@ -c $(CFLAGS) -DSTANDALONE_REGISTRY $<
|
||||
else
|
||||
$(CC) -o $@ -c $(CFLAGS) -DSTANDALONE_REGISTRY $<
|
||||
endif
|
||||
|
||||
$(BIN_OBJS): $(BIN_SRCS)
|
||||
|
||||
install:: $(PROGRAM)
|
||||
$(INSTALL) -m 444 $(PROGRAM) $(DIST)/bin
|
||||
1871
mozilla/modules/libreg/src/VerReg.c
Normal file
1871
mozilla/modules/libreg/src/VerReg.c
Normal file
File diff suppressed because it is too large
Load Diff
102
mozilla/modules/libreg/src/makefile.win
Normal file
102
mozilla/modules/libreg/src/makefile.win
Normal file
@@ -0,0 +1,102 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
IGNORE_MANIFEST=1
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Specify the depth of the current directory relative to the
|
||||
#// root of NS
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DEPTH= ..\..\..
|
||||
|
||||
!ifndef MAKE_OBJ_TYPE
|
||||
MAKE_OBJ_TYPE=DLL
|
||||
!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define the files necessary to build the target (ie. OBJS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
OBJS= \
|
||||
.\$(OBJDIR)\reg.obj \
|
||||
.\$(OBJDIR)\VerReg.obj \
|
||||
.\$(OBJDIR)\vr_stubs.obj \
|
||||
$(NULL)
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...)
|
||||
#// (these must be defined before the common makefiles are included)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
LIBNAME=libreg$(MOZ_BITS)
|
||||
|
||||
DLL=$(OBJDIR)\$(LIBNAME).dll
|
||||
LIBRARY= .\$(OBJDIR)\$(LIBNAME).lib
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any local options for the make tools
|
||||
#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
LCFLAGS = $(LCFLAGS)
|
||||
LLIBS = $(LLIBS) $(LIBNSPR) $(DIST)\lib\libplc21.lib
|
||||
|
||||
!if "$(MOZ_BITS)"=="32" && defined(MOZ_DEBUG) && defined(GLOWCODE)
|
||||
LLIBS=$(LLIBS) $(GLOWDIR)\glowcode.lib
|
||||
!endif
|
||||
|
||||
#//
|
||||
#// Win16 places ALL public header files in $(PUBLIC)/win16
|
||||
#//
|
||||
!if "$(MOZ_BITS)" != "16"
|
||||
LINCS= $(LINCS) -I$(PUBLIC)/libreg \
|
||||
$(NULL)
|
||||
!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Include the common makefile rules
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
export:: $(DLL)
|
||||
$(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib
|
||||
$(MAKE_INSTALL) $(DLL) $(DIST)\bin
|
||||
|
||||
clobber::
|
||||
$(RM) $(DIST)\bin\$(DLL)
|
||||
$(RM) $(DIST)\lib\$(LIBRARY)
|
||||
3631
mozilla/modules/libreg/src/reg.c
Normal file
3631
mozilla/modules/libreg/src/reg.c
Normal file
File diff suppressed because it is too large
Load Diff
175
mozilla/modules/libreg/src/reg.h
Normal file
175
mozilla/modules/libreg/src/reg.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/* reg.h
|
||||
* XP Registry functions (prototype)
|
||||
*/
|
||||
|
||||
#ifndef _REG_H_
|
||||
#define _REG_H_
|
||||
|
||||
#include "vr_stubs.h"
|
||||
|
||||
#ifndef STANDALONE_REGISTRY
|
||||
#include "prmon.h"
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Miscellaneous Definitions
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
#define MAGIC_NUMBER 0x76644441L
|
||||
#define MAJOR_VERSION 1 /* major version for incompatible changes */
|
||||
#define MINOR_VERSION 2 /* minor ver for new (compatible) features */
|
||||
#define PATHDEL '/'
|
||||
#define EQU '='
|
||||
#define QUOTE '"'
|
||||
#define HDRRESERVE 128 /* number of bytes reserved for hdr */
|
||||
#define INTSIZE 4
|
||||
#define DOUBLESIZE 8
|
||||
|
||||
#define PACKBUFFERSIZE 2048
|
||||
|
||||
|
||||
/* Node types */
|
||||
#define REGTYPE_KEY (1)
|
||||
#define REGTYPE_DELETED (0x0080)
|
||||
|
||||
/* Private standard keys */
|
||||
#define ROOTKEY (0x20)
|
||||
#define ROOTKEY_VERSIONS (0x21)
|
||||
|
||||
/* strings for standard keys */
|
||||
#define ROOTKEY_STR "/"
|
||||
#define ROOTKEY_VERSIONS_STR "Version Registry"
|
||||
#define ROOTKEY_USERS_STR "Users"
|
||||
#define ROOTKEY_COMMON_STR "Common"
|
||||
#define ROOTKEY_PRIVATE_STR "Private Arenas"
|
||||
|
||||
#define OLD_VERSIONS_STR "ROOTKEY_VERSIONS"
|
||||
#define OLD_USERS_STR "ROOTKEY_USERS"
|
||||
#define OLD_COMMON_STR "ROOTKEY_COMMON"
|
||||
|
||||
/* needs to be kept in sync with PE. see ns/cmd/winfe/profile.h */
|
||||
/* and ns/cmd/macfe/central/profile.cp */
|
||||
#define ASW_MAGIC_PROFILE_NAME "User1"
|
||||
|
||||
/* macros */
|
||||
#define COPYDESC(dest,src) memcpy((dest),(src),sizeof(REGDESC))
|
||||
|
||||
#define VALID_FILEHANDLE(fh) ((fh) != NULL)
|
||||
|
||||
#define INVALID_NAME_CHAR(p) ( ((unsigned char)(p) < 0x20) || ((p) == '=') )
|
||||
|
||||
#define TYPE_IS_ENTRY(type) ( (type) & REGTYPE_ENTRY )
|
||||
#define TYPE_IS_KEY(type) ( !((type) & REGTYPE_ENTRY) )
|
||||
|
||||
#define VERIFY_HREG(h)\
|
||||
( ((h) == NULL) ? REGERR_PARAM : \
|
||||
( (((REGHANDLE*)(h))->magic == MAGIC_NUMBER) ? REGERR_OK : REGERR_BADMAGIC ) )
|
||||
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Types and Objects
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
#undef REGOFF
|
||||
typedef int32 REGOFF; /* offset into registry file */
|
||||
|
||||
typedef struct _desc
|
||||
{
|
||||
REGOFF location; /* this object's offset (for verification) */
|
||||
REGOFF name; /* name string */
|
||||
uint16 namelen; /* length of name string (including terminator) */
|
||||
uint16 type; /* node type (key, or entry style) */
|
||||
REGOFF left; /* next object at this level (0 if none) */
|
||||
REGOFF down; /* KEY: first subkey VALUE: 0 */
|
||||
REGOFF value; /* KEY: first entry object VALUE: value string */
|
||||
uint32 valuelen; /* KEY: 0 VALUE: length of value data */
|
||||
uint32 valuebuf; /* KEY: 0 VALUE: length available */
|
||||
REGOFF parent; /* the node on the immediate level above */
|
||||
} REGDESC;
|
||||
|
||||
/* offsets into structure on disk */
|
||||
#define DESC_LOCATION 0
|
||||
#define DESC_NAME 4
|
||||
#define DESC_NAMELEN 8
|
||||
#define DESC_TYPE 10
|
||||
#define DESC_LEFT 12
|
||||
#define DESC_DOWN 16
|
||||
#define DESC_VALUE 20
|
||||
#define DESC_VALUELEN 24
|
||||
#define DESC_VALUEBUF 16 /* stored in place of "down" for entries */
|
||||
#define DESC_PARENT 28
|
||||
|
||||
#define DESC_SIZE 32 /* size of desc on disk */
|
||||
|
||||
typedef struct _hdr
|
||||
{
|
||||
uint32 magic; /* must equal MAGIC_NUMBER */
|
||||
uint16 verMajor; /* major version number */
|
||||
uint16 verMinor; /* minor version number */
|
||||
REGOFF avail; /* next available offset */
|
||||
REGOFF root; /* root object */
|
||||
} REGHDR;
|
||||
|
||||
/* offsets into structure on disk*/
|
||||
#define HDR_MAGIC 0
|
||||
#define HDR_VERMAJOR 4
|
||||
#define HDR_VERMINOR 6
|
||||
#define HDR_AVAIL 8
|
||||
#define HDR_ROOT 12
|
||||
|
||||
typedef XP_File FILEHANDLE; /* platform-specific file reference */
|
||||
|
||||
typedef struct _stdnodes {
|
||||
REGOFF versions;
|
||||
REGOFF users;
|
||||
REGOFF common;
|
||||
REGOFF current_user;
|
||||
REGOFF privarea;
|
||||
} STDNODES;
|
||||
|
||||
typedef struct _regfile
|
||||
{
|
||||
FILEHANDLE fh;
|
||||
REGHDR hdr;
|
||||
int refCount;
|
||||
int hdrDirty;
|
||||
int inInit;
|
||||
int readOnly;
|
||||
char * filename;
|
||||
STDNODES rkeys;
|
||||
struct _regfile *next;
|
||||
struct _regfile *prev;
|
||||
#ifndef STANDALONE_REGISTRY
|
||||
PRMonitor *monitor;
|
||||
#endif
|
||||
} REGFILE;
|
||||
|
||||
typedef struct _reghandle
|
||||
{
|
||||
uint32 magic; /* for validating reg handles */
|
||||
REGFILE *pReg; /* the real registry file object */
|
||||
} REGHANDLE;
|
||||
|
||||
|
||||
#endif /* _REG_H_ */
|
||||
|
||||
/* EOF: reg.h */
|
||||
|
||||
554
mozilla/modules/libreg/src/vr_stubs.c
Normal file
554
mozilla/modules/libreg/src/vr_stubs.c
Normal file
@@ -0,0 +1,554 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* this file contains stubs needed to build the registry routines
|
||||
* into a stand-alone library for use with our installers
|
||||
*/
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#else
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
#include "vr_stubs.h"
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include <Folders.h>
|
||||
#include <Script.h>
|
||||
#include <stdlib.h>
|
||||
#include <Errors.h>
|
||||
#include "MoreFiles.h"
|
||||
#include "FullPath.h" /* For FSpLocationFromFullPath() */
|
||||
#endif
|
||||
|
||||
extern char* globalRegName;
|
||||
/* ------------------------------------------------------------------
|
||||
* OS/2 STUBS
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef XP_OS2
|
||||
#define INCL_DOS
|
||||
#include <os2.h>
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
extern XP_File vr_fileOpen (const char *name, const char * mode)
|
||||
{
|
||||
XP_File fh = NULL;
|
||||
struct stat st;
|
||||
|
||||
if ( name != NULL ) {
|
||||
if ( stat( name, &st ) == 0 )
|
||||
fh = fopen( name, XP_FILE_UPDATE_BIN );
|
||||
else
|
||||
fh = fopen( name, XP_FILE_WRITE_BIN );
|
||||
}
|
||||
|
||||
return fh;
|
||||
}
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
extern void vr_findGlobalRegName ()
|
||||
{
|
||||
char path[ CCHMAXPATH ];
|
||||
int pathlen;
|
||||
XP_File fh = NULL;
|
||||
struct stat st;
|
||||
|
||||
#ifdef XP_OS2_HACK
|
||||
/*DSR050197 - at this point, I need some front-end call to get the install directory of*/
|
||||
/*communicator... for now I will let it default to the current directory...*/
|
||||
#endif
|
||||
XP_STRCPY(path, ".");
|
||||
pathlen = strlen(path);
|
||||
|
||||
if ( pathlen > 0 ) {
|
||||
XP_STRCPY( path+pathlen, "\\nsreg.dat" );
|
||||
globalRegName = XP_STRDUP(path);
|
||||
}
|
||||
}
|
||||
#endif /* XP_OS2 */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* WINDOWS STUBS
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
#ifdef XP_PC
|
||||
#include "windows.h"
|
||||
#define PATHLEN 260
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
extern XP_File vr_fileOpen (const char *name, const char * mode)
|
||||
{
|
||||
XP_File fh = NULL;
|
||||
struct stat st;
|
||||
|
||||
if ( name != NULL ) {
|
||||
if ( stat( name, &st ) == 0 )
|
||||
fh = fopen( name, XP_FILE_UPDATE_BIN );
|
||||
else
|
||||
fh = fopen( name, XP_FILE_WRITE_BIN );
|
||||
}
|
||||
|
||||
return fh;
|
||||
}
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
extern void vr_findGlobalRegName ()
|
||||
{
|
||||
char path[ PATHLEN ];
|
||||
int pathlen;
|
||||
|
||||
pathlen = GetWindowsDirectory(path, PATHLEN);
|
||||
if ( pathlen > 0 ) {
|
||||
XP_STRCPY( path+pathlen, "\\nsreg.dat" );
|
||||
globalRegName = XP_STRDUP(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !defined(WIN32) && !defined(__BORLANDC__)
|
||||
int FAR PASCAL _export WEP(int);
|
||||
|
||||
int FAR PASCAL LibMain(HANDLE hInst, WORD wDataSeg, WORD wHeapSize, LPSTR lpszCmdLine)
|
||||
{
|
||||
if ( wHeapSize > 0 )
|
||||
UnlockData(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int FAR PASCAL _export WEP(int nParam)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif /* not WIN32 */
|
||||
|
||||
#endif /* XP_PC */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* MACINTOSH STUBS
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include <Files.h>
|
||||
#include "FullPath.h"
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
extern XP_File vr_fileOpen(const char *name, const char * mode)
|
||||
{
|
||||
XP_File fh = NULL;
|
||||
struct stat st;
|
||||
OSErr anErr;
|
||||
FSSpec newFSSpec;
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
errno = 0; // reset errno (only if we're using stdio)
|
||||
#endif
|
||||
|
||||
anErr = FSpLocationFromFullPath(strlen(name), name, &newFSSpec);
|
||||
|
||||
if (anErr == -43)
|
||||
{
|
||||
/* if file doesn't exist */
|
||||
anErr = FSpCreate(&newFSSpec, 'MOSS', 'REGS', smSystemScript);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* there is not much to do here. if we got noErr, the file exists. If we did not get
|
||||
noErr or -43, we are pretty hosed.
|
||||
*/
|
||||
}
|
||||
|
||||
if ( name != NULL ) {
|
||||
if ( stat( name, &st ) == 0 )
|
||||
fh = fopen( name, XP_FILE_UPDATE_BIN ); /* If/when we switch to MSL C Lib (gromit uses this), we might have to take out the Macro per bug #62382 */
|
||||
else
|
||||
{
|
||||
/* should never get here! */
|
||||
fh = fopen( name, XP_FILE_WRITE_BIN );
|
||||
}
|
||||
}
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
if (anErr != noErr)
|
||||
errno = anErr;
|
||||
#endif
|
||||
return fh;
|
||||
}
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
extern void vr_findGlobalRegName()
|
||||
{
|
||||
FSSpec regSpec;
|
||||
OSErr err;
|
||||
short foundVRefNum;
|
||||
long foundDirID;
|
||||
int bCreate = 0;
|
||||
|
||||
err = FindFolder(kOnSystemDisk,'pref', false, &foundVRefNum, &foundDirID);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
err = FSMakeFSSpec(foundVRefNum, foundDirID, "\pNetscape Registry", ®Spec);
|
||||
|
||||
if (err == -43) /* if file doesn't exist */
|
||||
{
|
||||
err = FSpCreate(®Spec, 'MOSS', 'REGS', smSystemScript);
|
||||
bCreate = 1;
|
||||
}
|
||||
|
||||
if (err == noErr)
|
||||
{
|
||||
Handle thePath;
|
||||
short pathLen;
|
||||
err = FSpGetFullPath(®Spec, &pathLen, &thePath);
|
||||
if (err == noErr && thePath)
|
||||
{
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
globalRegName = XP_STRDUP(*(char**)thePath);
|
||||
#else
|
||||
/* Since we're now using NSPR, this HAS to be a unix path! */
|
||||
const char* src;
|
||||
char* dst;
|
||||
globalRegName = (char*)XP_ALLOC(pathLen + 2);
|
||||
src = *(char**)thePath;
|
||||
dst = globalRegName;
|
||||
*dst++ = '/';
|
||||
while (pathLen--)
|
||||
{
|
||||
char c = *src++;
|
||||
*dst++ = (c == ':') ? '/' : c;
|
||||
}
|
||||
*dst = '\0';
|
||||
#endif
|
||||
}
|
||||
DisposeHandle(thePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Moves and renames a file or directory.
|
||||
Returns 0 on success, -1 on failure (errno contains mac error code).
|
||||
*/
|
||||
extern int nr_RenameFile(char *from, char *to)
|
||||
{
|
||||
OSErr err = -1;
|
||||
FSSpec fromSpec;
|
||||
FSSpec toSpec;
|
||||
FSSpec destDirSpec;
|
||||
FSSpec beforeRenameSpec;
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
errno = 0; // reset errno (only if we're using stdio)
|
||||
#endif
|
||||
|
||||
if (from && to) {
|
||||
err = FSpLocationFromFullPath(XP_STRLEN(from), from, &fromSpec);
|
||||
if (err != noErr) goto exit;
|
||||
|
||||
err = FSpLocationFromFullPath(XP_STRLEN(to), to, &toSpec);
|
||||
if (err != noErr && err != fnfErr) goto exit;
|
||||
|
||||
// make an FSSpec for the destination directory
|
||||
err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, nil, &destDirSpec);
|
||||
if (err != noErr) goto exit; // parent directory must exist
|
||||
|
||||
// move it to the directory specified
|
||||
err = FSpCatMove(&fromSpec, &destDirSpec);
|
||||
if (err != noErr) goto exit;
|
||||
|
||||
// make a new FSSpec for the file or directory in its new location
|
||||
err = FSMakeFSSpec(toSpec.vRefNum, toSpec.parID, fromSpec.name, &beforeRenameSpec);
|
||||
if (err != noErr) goto exit;
|
||||
|
||||
// rename the file or directory
|
||||
err = FSpRename(&beforeRenameSpec, toSpec.name);
|
||||
}
|
||||
|
||||
exit:
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
if (err != noErr)
|
||||
errno = err;
|
||||
#endif
|
||||
return (err == noErr ? 0 : -1);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* Uncomment the following for older Mac build environments
|
||||
* that don't support these functions
|
||||
*/
|
||||
char *strdup(const char *source)
|
||||
{
|
||||
char *newAllocation;
|
||||
size_t stringLength;
|
||||
|
||||
stringLength = strlen(source) + 1;
|
||||
|
||||
newAllocation = (char *)XP_ALLOC(stringLength);
|
||||
if (newAllocation == NULL)
|
||||
return NULL;
|
||||
BlockMoveData(source, newAllocation, stringLength);
|
||||
return newAllocation;
|
||||
}
|
||||
|
||||
int strcasecmp(const char *str1, const char *str2)
|
||||
{
|
||||
char currentChar1, currentChar2;
|
||||
|
||||
while (1) {
|
||||
|
||||
currentChar1 = *str1;
|
||||
currentChar2 = *str2;
|
||||
|
||||
if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
|
||||
currentChar1 += ('A' - 'a');
|
||||
|
||||
if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
|
||||
currentChar2 += ('A' - 'a');
|
||||
|
||||
if (currentChar1 == '\0')
|
||||
break;
|
||||
|
||||
if (currentChar1 != currentChar2)
|
||||
return currentChar1 - currentChar2;
|
||||
|
||||
str1++;
|
||||
str2++;
|
||||
|
||||
}
|
||||
|
||||
return currentChar1 - currentChar2;
|
||||
}
|
||||
|
||||
int strncasecmp(const char *str1, const char *str2, int length)
|
||||
{
|
||||
char currentChar1, currentChar2;
|
||||
|
||||
while (length > 0) {
|
||||
|
||||
currentChar1 = *str1;
|
||||
currentChar2 = *str2;
|
||||
|
||||
if ((currentChar1 >= 'a') && (currentChar1 <= 'z'))
|
||||
currentChar1 += ('A' - 'a');
|
||||
|
||||
if ((currentChar2 >= 'a') && (currentChar2 <= 'z'))
|
||||
currentChar2 += ('A' - 'a');
|
||||
|
||||
if (currentChar1 == '\0')
|
||||
break;
|
||||
|
||||
if (currentChar1 != currentChar2)
|
||||
return currentChar1 - currentChar2;
|
||||
|
||||
str1++;
|
||||
str2++;
|
||||
|
||||
length--;
|
||||
}
|
||||
|
||||
return currentChar1 - currentChar2;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
#endif /* XP_MAC */
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* UNIX STUBS
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*allow OS/2 and Macintosh to use this main to test...*/
|
||||
#if (defined(STANDALONE_REGISTRY) && defined(XP_MAC)) || defined(XP_UNIX) || defined(XP_OS2)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef XP_OS2
|
||||
#include <io.h>
|
||||
#define W_OK 0x02 /*evil hack from the docs...*/
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "NSReg.h"
|
||||
#include "VerReg.h"
|
||||
|
||||
char *TheRegistry = "registry";
|
||||
char *Flist;
|
||||
|
||||
/* WARNING: build hackery */
|
||||
#if defined(STANDALONE_REGISTRY) && !defined(XP_MAC)
|
||||
long BUILDNUM =
|
||||
#include "../../../build/build_number"
|
||||
;
|
||||
#endif
|
||||
|
||||
|
||||
REGERR vr_ParseVersion(char *verstr, VERSION *result);
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
#ifdef XP_UNIX
|
||||
|
||||
#define DEF_REG "/.netscape/registry"
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
extern XP_File vr_fileOpen (const char *name, const char * mode)
|
||||
{
|
||||
XP_File fh = NULL;
|
||||
struct stat st;
|
||||
|
||||
if ( name != NULL ) {
|
||||
if ( stat( name, &st ) == 0 )
|
||||
fh = fopen( name, XP_FILE_UPDATE_BIN );
|
||||
else
|
||||
fh = fopen( name, XP_FILE_WRITE_BIN );
|
||||
}
|
||||
|
||||
return fh;
|
||||
}
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
extern void vr_findGlobalRegName ()
|
||||
{
|
||||
#ifndef STANDALONE_REGISTRY
|
||||
char *def = NULL;
|
||||
char *home = getenv("HOME");
|
||||
if (home != NULL) {
|
||||
def = (char *) XP_ALLOC(XP_STRLEN(home) + XP_STRLEN(DEF_REG)+1);
|
||||
if (def != NULL) {
|
||||
XP_STRCPY(def, home);
|
||||
XP_STRCAT(def, DEF_REG);
|
||||
}
|
||||
}
|
||||
if (def != NULL) {
|
||||
globalRegName = XP_STRDUP(def);
|
||||
} else {
|
||||
globalRegName = TheRegistry;
|
||||
}
|
||||
XP_FREEIF(def);
|
||||
#else
|
||||
globalRegName = TheRegistry;
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
}
|
||||
|
||||
#endif /*XP_UNIX*/
|
||||
|
||||
#if defined(STANDALONE_REGISTRY) && (defined(XP_UNIX) || defined(XP_OS2) || defined(XP_MAC))
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
XP_File fh;
|
||||
char *entry;
|
||||
char *p;
|
||||
char *v;
|
||||
char buff[1024];
|
||||
char name[MAXREGPATHLEN+1];
|
||||
char path[MAXREGPATHLEN+1];
|
||||
char ver[MAXREGPATHLEN+1];
|
||||
|
||||
if ( argc >= 3 )
|
||||
{
|
||||
TheRegistry = argv[1];
|
||||
Flist = argv[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Usage: %s RegistryName FileList\n", argv[0]);
|
||||
fprintf(stderr, " The FileList file contains lines with comma-separated fields:\n");
|
||||
fprintf(stderr, " <regItemName>,<version>,<full filepath>\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
/* tmp use of buff to get the registry directory, which must be
|
||||
* the navigator home directory. Preserve the slash to match
|
||||
* FE_GetDirectoryPath() called during navigator set-up
|
||||
*/
|
||||
|
||||
|
||||
strcpy(buff, TheRegistry);
|
||||
p = strrchr( buff, '/' );
|
||||
if ( p )
|
||||
{
|
||||
char pwd[1024];
|
||||
|
||||
*(p+1) = '\0';
|
||||
getcwd(pwd, sizeof(pwd));
|
||||
chdir(buff); getcwd(buff, sizeof(buff));
|
||||
chdir(pwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
getcwd(buff, sizeof(buff));
|
||||
}
|
||||
strcat(buff, "/");
|
||||
|
||||
|
||||
NR_StartupRegistry();
|
||||
VR_SetRegDirectory(buff);
|
||||
|
||||
|
||||
#ifndef XP_MAC
|
||||
if ( -1 == (access( TheRegistry, W_OK )) ) {
|
||||
sprintf(ver,"4.50.0.%ld",BUILDNUM);
|
||||
VR_CreateRegistry("Communicator", buff, ver);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( !(fh = fopen( Flist, "r" )) )
|
||||
{
|
||||
fprintf(stderr, "%s: Cannot open \"%s\"\n", argv[0], Flist);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
while ( fgets ( buff, 1024, fh ) )
|
||||
{
|
||||
if ( *(entry = &buff[strlen(buff)-1]) == '\n' )
|
||||
*entry = '\0';
|
||||
|
||||
entry = strchr(buff, ',');
|
||||
strcpy(name, strtok(buff, ","));
|
||||
strcpy(ver, strtok( NULL, ","));
|
||||
strcpy(path, strtok( NULL, ","));
|
||||
|
||||
v = ver;
|
||||
while (*v && *v == ' ')
|
||||
v++;
|
||||
|
||||
p = path;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
VR_Install ( name, p, v, FALSE );
|
||||
}
|
||||
fclose( fh );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* STANDALONE_REGISTRY && (XP_UNIX || XP_OS2 || XP_MAC) */
|
||||
|
||||
#endif /* XP_UNIX || XP_OS2 */
|
||||
253
mozilla/modules/libreg/src/vr_stubs.h
Normal file
253
mozilla/modules/libreg/src/vr_stubs.h
Normal file
@@ -0,0 +1,253 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
/* vr_stubs.h
|
||||
*
|
||||
* XP code stubs for stand-alone registry library
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VR_STUBS_H_
|
||||
#define _VR_STUBS_H_
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef XP_MAC
|
||||
#include "macstdlibextras.h" /* For strcasecmp and strncasecmp */
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include "prio.h"
|
||||
#include "prmem.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#endif /* STANDALONE_REGISTRY*/
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include <stat.h>
|
||||
#else
|
||||
#if defined(BSDI) && !defined(BSDI_2)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
# define XP_CPLUSPLUS
|
||||
# define XP_IS_CPLUSPLUS 1
|
||||
#else
|
||||
# define XP_IS_CPLUSPLUS 0
|
||||
#endif
|
||||
|
||||
#if defined(XP_CPLUSPLUS)
|
||||
# define XP_BEGIN_PROTOS extern "C" {
|
||||
# define XP_END_PROTOS }
|
||||
#else
|
||||
# define XP_BEGIN_PROTOS
|
||||
# define XP_END_PROTOS
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef STANDALONE_REGISTRY
|
||||
|
||||
#define XP_FILE_READ "r"
|
||||
#define XP_FILE_READ_BIN "rb"
|
||||
#define XP_FILE_WRITE "w"
|
||||
#define XP_FILE_WRITE_BIN "wb"
|
||||
#define XP_FILE_UPDATE "r+"
|
||||
#define XP_FILE_TRUNCATE "w+"
|
||||
#ifdef SUNOS4
|
||||
/* XXX SunOS4 hack -- make this universal by using r+b and w+b */
|
||||
#define XP_FILE_UPDATE_BIN "r+"
|
||||
#define XP_FILE_TRUNCATE_BIN "w+"
|
||||
#else
|
||||
#define XP_FILE_UPDATE_BIN "rb+"
|
||||
#define XP_FILE_TRUNCATE_BIN "wb+"
|
||||
#endif
|
||||
|
||||
#define XP_FileSeek(file,offset,whence) fseek((file), (offset), (whence))
|
||||
#define XP_FileRead(dest,count,file) fread((dest), 1, (count), (file))
|
||||
#define XP_FileWrite(src,count,file) fwrite((src), 1, (count), (file))
|
||||
#define XP_FileTell(file) ftell(file)
|
||||
#define XP_FileFlush(file) fflush(file)
|
||||
#define XP_FileClose(file) fclose(file)
|
||||
|
||||
#define XP_ASSERT(x) ((void)0)
|
||||
|
||||
#define XP_STRCAT(a,b) strcat((a),(b))
|
||||
#define XP_ATOI atoi
|
||||
#define XP_STRCPY(a,b) strcpy((a),(b))
|
||||
#define XP_STRLEN(x) strlen(x)
|
||||
#define XP_SPRINTF sprintf
|
||||
#define XP_FREE(x) free((x))
|
||||
#define XP_ALLOC(x) malloc((x))
|
||||
#define XP_FREEIF(x) if ((x)) free((x))
|
||||
#define XP_STRCMP(x,y) strcmp((x),(y))
|
||||
#define XP_STRNCMP(x,y,n) strncmp((x),(y),(n))
|
||||
#define XP_STRDUP(s) strdup((s))
|
||||
#define XP_MEMCPY(d, s, l) memcpy((d), (s), (l))
|
||||
#define XP_MEMSET(d, c, l) memset((d), (c), (l))
|
||||
|
||||
#ifdef XP_PC
|
||||
#define XP_STRCASECMP(x,y) stricmp((x),(y))
|
||||
#define XP_STRNCASECMP(x,y,n) strnicmp((x),(y),(n))
|
||||
#else
|
||||
#define XP_STRCASECMP(x,y) strcasecmp((x),(y))
|
||||
#define XP_STRNCASECMP(x,y,n) strncasecmp((x),(y),(n))
|
||||
#endif /*XP_PC*/
|
||||
|
||||
typedef FILE * XP_File;
|
||||
|
||||
#else /* if not standalone, use NSPR */
|
||||
|
||||
#define XP_FILE_READ PR_RDONLY, 0700
|
||||
#define XP_FILE_READ_BIN PR_RDONLY, 0700
|
||||
#define XP_FILE_WRITE PR_WRONLY, 0700
|
||||
#define XP_FILE_WRITE_BIN PR_WRONLY, 0700
|
||||
#define XP_FILE_UPDATE PR_RDWR
|
||||
#define XP_FILE_TRUNCATE (PR_WRONLY | PR_TRUNCATE), 0700
|
||||
|
||||
#define XP_FILE_UPDATE_BIN PR_RDWR, 0700
|
||||
#define XP_FILE_TRUNCATE_BIN (PR_RDWR | PR_TRUNCATE), 0700
|
||||
|
||||
#ifdef SEEK_SET
|
||||
#undef SEEK_SET
|
||||
#undef SEEK_CUR
|
||||
#undef SEEK_END
|
||||
#define SEEK_SET PR_SEEK_SET
|
||||
#define SEEK_CUR PR_SEEK_CUR
|
||||
#define SEEK_END PR_SEEK_END
|
||||
#endif
|
||||
/*
|
||||
** Note that PR_Seek returns the offset (if successful) and -1 otherwise. So
|
||||
** to make this code work
|
||||
** if (XP_FileSeek(fh, offset, SEEK_SET) != 0) { error handling }
|
||||
** we return 1 if PR_Seek() returns a negative value, and 0 otherwise
|
||||
*/
|
||||
#define XP_FileSeek(file,offset,whence) (PR_Seek((file), (offset), (whence)) < 0)
|
||||
#define XP_FileRead(dest,count,file) PR_Read((file), (dest), (count))
|
||||
#define XP_FileWrite(src,count,file) PR_Write((file), (src), (count))
|
||||
#define XP_FileTell(file) PR_Seek(file, 0, PR_SEEK_CUR)
|
||||
#define XP_FileFlush(file) PR_Sync(file)
|
||||
#define XP_FileClose(file) PR_Close(file)
|
||||
|
||||
#define XP_ASSERT(x) PR_ASSERT((x))
|
||||
|
||||
#define XP_STRCAT(a,b) PL_strcat((a),(b))
|
||||
#define XP_ATOI PL_atoi
|
||||
#define XP_STRCPY(a,b) PL_strcpy((a),(b))
|
||||
#define XP_STRLEN(x) PL_strlen(x)
|
||||
#define XP_SPRINTF sprintf
|
||||
#define XP_FREE(x) PR_Free((x))
|
||||
#define XP_ALLOC(x) PR_Malloc((x))
|
||||
#define XP_FREEIF(x) PR_FREEIF(x)
|
||||
#define XP_STRCMP(x,y) PL_strcmp((x),(y))
|
||||
#define XP_STRNCMP(x,y,n) PL_strncmp((x),(y),(n))
|
||||
#define XP_STRDUP(s) PL_strdup((s))
|
||||
#define XP_MEMCPY(d, s, l) memcpy((d), (s), (l))
|
||||
#define XP_MEMSET(d, c, l) memset((d), (c), (l))
|
||||
|
||||
#define XP_STRCASECMP(x,y) PL_strcasecmp((x),(y))
|
||||
#define XP_STRNCASECMP(x,y,n) PL_strncasecmp((x),(y),(n))
|
||||
|
||||
typedef PRFileDesc* XP_File;
|
||||
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
#ifdef STANDALONE_REGISTRY /* included from prmon.h otherwise */
|
||||
#include "prtypes.h"
|
||||
|
||||
#if 0
|
||||
typedef long int32;
|
||||
typedef unsigned long uint32;
|
||||
typedef short int16;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned char uint8;
|
||||
|
||||
#ifdef XP_MAC
|
||||
#include <Types.h>
|
||||
typedef char BOOL;
|
||||
typedef char Bool;
|
||||
typedef char XP_Bool;
|
||||
#elif defined(XP_PC)
|
||||
typedef int Bool;
|
||||
typedef int XP_Bool;
|
||||
#else
|
||||
/* XP_UNIX: X11/Xlib.h "define"s Bool to be int. This is really lame
|
||||
* (that's what typedef is for losers). So.. in lieu of a #undef Bool
|
||||
* here (Xlib still needs ints for Bool-typed parameters) people have
|
||||
* been #undef-ing Bool before including this file.
|
||||
* Can we just #undef Bool here? <mailto:mcafee> (help from djw, converse)
|
||||
*/
|
||||
|
||||
typedef char Bool;
|
||||
typedef char XP_Bool;
|
||||
#endif /* XP_MAC */
|
||||
#endif /* 0 */
|
||||
#endif /*STANDALONE_REGISTRY*/
|
||||
|
||||
#ifdef XP_PC
|
||||
typedef struct _stat XP_StatStruct;
|
||||
#define XP_Stat(file,data,type) _stat((file),(data))
|
||||
#else
|
||||
typedef struct stat XP_StatStruct;
|
||||
#define XP_Stat(file,data,type) stat((file),(data))
|
||||
#endif /*XP_PC*/
|
||||
|
||||
#ifdef XP_MAC
|
||||
extern int nr_RenameFile(char *from, char *to);
|
||||
#else
|
||||
XP_BEGIN_PROTOS
|
||||
#define nr_RenameFile(from, to) rename((from), (to))
|
||||
XP_END_PROTOS
|
||||
#endif
|
||||
|
||||
#ifdef STANDALONE_REGISTRY /* included from prmon.h otherwise */
|
||||
|
||||
XP_BEGIN_PROTOS
|
||||
extern XP_File vr_fileOpen(const char *name, const char * mode);
|
||||
extern void vr_findGlobalRegName();
|
||||
|
||||
#if !defined(XP_PC) && !(defined(__GLIBC__) && __GLIBC__ >= 2)
|
||||
extern char * strdup(const char * s);
|
||||
#endif
|
||||
|
||||
XP_END_PROTOS
|
||||
|
||||
#else
|
||||
|
||||
#define vr_fileOpen PR_Open
|
||||
|
||||
XP_BEGIN_PROTOS
|
||||
extern void vr_findGlobalRegName();
|
||||
XP_END_PROTOS
|
||||
|
||||
#endif /* STANDALONE_REGISTRY */
|
||||
|
||||
|
||||
#endif /* _VR_STUBS_H_ */
|
||||
115
mozilla/modules/libreg/standalone/makefile.win
Normal file
115
mozilla/modules/libreg/standalone/makefile.win
Normal file
@@ -0,0 +1,115 @@
|
||||
#!gmake
|
||||
#
|
||||
# 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.
|
||||
IGNORE_MANIFEST=1
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Makefile to build
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Specify the depth of the current directory relative to the
|
||||
#// root of NS
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
DEPTH= ..\..\..
|
||||
|
||||
!ifndef MAKE_OBJ_TYPE
|
||||
MAKE_OBJ_TYPE=DLL
|
||||
!endif
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define the files necessary to build the target (ie. OBJS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
OBJS= \
|
||||
.\$(OBJDIR)\reg.obj \
|
||||
.\$(OBJDIR)\VerReg.obj \
|
||||
.\$(OBJDIR)\vr_stubs.obj \
|
||||
$(NULL)
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...)
|
||||
#// (these must be defined before the common makefiles are included)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
|
||||
LIBNAME=nsreg
|
||||
DLL=$(OBJDIR)\$(LIBNAME).dll
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Define any local options for the make tools
|
||||
#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS)
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
|
||||
LCFLAGS = -DSTANDALONE_REGISTRY
|
||||
|
||||
LINCS= $(LINCS) -I$(PUBLIC)/libreg \
|
||||
$(NULL)
|
||||
|
||||
#//------------------------------------------------------------------------
|
||||
#//
|
||||
#// Include the common makefile rules
|
||||
#//
|
||||
#//------------------------------------------------------------------------
|
||||
include <$(DEPTH)/config/rules.mak>
|
||||
|
||||
reg.c::
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\reg.h
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\reg.c
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\vr_stubs.h
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\vr_stubs.c
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\VerReg.c
|
||||
|
||||
copy $(DEPTH)\modules\libreg\src\reg.h $(DEPTH)\modules\libreg\standalone\reg.h
|
||||
copy $(DEPTH)\modules\libreg\src\reg.c $(DEPTH)\modules\libreg\standalone\reg.c
|
||||
copy $(DEPTH)\modules\libreg\src\vr_stubs.h $(DEPTH)\modules\libreg\standalone\vr_stubs.h
|
||||
copy $(DEPTH)\modules\libreg\src\vr_stubs.c $(DEPTH)\modules\libreg\standalone\vr_stubs.c
|
||||
copy $(DEPTH)\modules\libreg\src\VerReg.c $(DEPTH)\modules\libreg\standalone\VerReg.c
|
||||
|
||||
export:: $(DLL)
|
||||
|
||||
$(MAKE_INSTALL) $(DLL) $(DIST)\bin
|
||||
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\reg.h
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\reg.c
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\vr_stubs.h
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\vr_stubs.c
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\VerReg.c
|
||||
|
||||
clobber::
|
||||
|
||||
$(RM) $(DIST)\bin\$(DLL)
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\reg.h
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\reg.c
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\vr_stubs.h
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\vr_stubs.c
|
||||
$(RM) $(DEPTH)\modules\libreg\standalone\VerReg.c
|
||||
430
mozilla/modules/libreg/tests/interp.c
Normal file
430
mozilla/modules/libreg/tests/interp.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
// Registry interpreter
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "VerReg.h"
|
||||
#include "NSReg.h"
|
||||
|
||||
extern char *errstr(REGERR err);
|
||||
extern int DumpTree(void);
|
||||
|
||||
int gVerbose = 1;
|
||||
int gPretend = 0;
|
||||
|
||||
int error(char *func, int err)
|
||||
{
|
||||
if (err == REGERR_OK)
|
||||
{
|
||||
if (gVerbose)
|
||||
printf("%s Ok\n", func);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s returns %s\n", func, errstr(err));
|
||||
}
|
||||
|
||||
return err;
|
||||
|
||||
} // error
|
||||
|
||||
static char *GetNextWord(char *cmd, char *buf)
|
||||
{
|
||||
// copies until ',' or eos, then skips spaces
|
||||
if (!cmd || !buf)
|
||||
return 0;
|
||||
while (*cmd && *cmd != ',')
|
||||
*buf++ = *cmd++;
|
||||
*buf = '\0';
|
||||
if (*cmd == ',')
|
||||
{
|
||||
cmd++;
|
||||
while(*cmd && *cmd == ' ')
|
||||
cmd++;
|
||||
}
|
||||
return cmd;
|
||||
|
||||
} // GetNextWord
|
||||
|
||||
static int vr_ParseVersion(char *verstr, VERSION *result)
|
||||
{
|
||||
|
||||
result->major = result->minor = result->release = result->build = 0;
|
||||
result->major = atoi(verstr);
|
||||
while (*verstr && *verstr != '.')
|
||||
verstr++;
|
||||
if (*verstr)
|
||||
{
|
||||
verstr++;
|
||||
result->minor = atoi(verstr);
|
||||
while (*verstr && *verstr != '.')
|
||||
verstr++;
|
||||
if (*verstr)
|
||||
{
|
||||
verstr++;
|
||||
result->release = atoi(verstr);
|
||||
while (*verstr && *verstr != '.')
|
||||
verstr++;
|
||||
if (*verstr)
|
||||
{
|
||||
verstr++;
|
||||
result->build = atoi(verstr);
|
||||
while (*verstr && *verstr != '.')
|
||||
verstr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return REGERR_OK;
|
||||
|
||||
} // ParseVersion
|
||||
|
||||
void parse(char *cmd, char *name, VERSION *ver, char *path)
|
||||
{
|
||||
// expects 'cmd' points to: "<name>, <ver>, <path>"
|
||||
char buf[256];
|
||||
char *p;
|
||||
|
||||
cmd = GetNextWord(cmd, buf);
|
||||
strcpy(name, buf);
|
||||
|
||||
p = cmd; // 'cmd' points to version
|
||||
vr_ParseVersion(cmd, ver);
|
||||
ver->check = gPretend ? 0xad : 0;
|
||||
while (*p && *p != ',') // skip to next ','
|
||||
p++;
|
||||
if (*p == ',') // skip comma
|
||||
p++;
|
||||
while (*p && *p == ' ') // skip white space
|
||||
p++;
|
||||
|
||||
strcpy(path, p);
|
||||
|
||||
} // parse
|
||||
|
||||
void vVerbose(char *cmd)
|
||||
{
|
||||
|
||||
if (stricmp(cmd, "ON") == 0)
|
||||
{
|
||||
gVerbose = 1;
|
||||
printf("Verbose mode is now ON.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
gVerbose = 0;
|
||||
}
|
||||
|
||||
} // vVerbose
|
||||
|
||||
void vCreate(char *cmd)
|
||||
{
|
||||
|
||||
// Syntax: Create [new,] 5.0b1
|
||||
char buf[64];
|
||||
|
||||
int flag = 0;
|
||||
cmd = GetNextWord(cmd, buf);
|
||||
if (stricmp(buf, "NEW,") == 0)
|
||||
{
|
||||
flag = CR_NEWREGISTRY;
|
||||
}
|
||||
error("VR_CreateRegistry", VR_CreateRegistry(flag, cmd));
|
||||
|
||||
} // vCreate
|
||||
|
||||
void vDisplay(char *cmd)
|
||||
{
|
||||
|
||||
DumpTree();
|
||||
|
||||
} // vDisplay
|
||||
|
||||
|
||||
void vFind(char *cmd)
|
||||
{
|
||||
|
||||
VERSION ver;
|
||||
char path[MAXREGPATHLEN];
|
||||
|
||||
if (error("VR_GetVersion", VR_GetVersion(cmd, &ver)) == REGERR_OK)
|
||||
{
|
||||
if (error("VR_GetPath", VR_GetPath(cmd, sizeof(path), path)) == REGERR_OK)
|
||||
{
|
||||
printf("%s found: ver=%d.%d.%d.%d, check=0x%04x, path=%s\n",
|
||||
cmd, ver.major, ver.minor, ver.release, ver.build, ver.check,
|
||||
path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s not found.\n", cmd);
|
||||
return;
|
||||
|
||||
} // vFind
|
||||
|
||||
|
||||
void vHelp(char *cmd)
|
||||
{
|
||||
|
||||
puts("Enter a command:");
|
||||
puts("\tD)isplay - display the current contents of the Registry");
|
||||
puts("\tI)nstall <name>, <version>, <path> - install a new component");
|
||||
puts("\tU)pdate <name>, <version>, <path> - update a component");
|
||||
puts("\tF)ind <name> - returns version and path");
|
||||
puts("\tV)erify <name> - verify component exists and checks out");
|
||||
puts("\tC)reate <name> - create a new instance of Navigator (e.g., \"4.0\")");
|
||||
puts("\tR)emove <name> - deletes a component from the Registry");
|
||||
puts("\tT)est - perform a simple test on the Registry");
|
||||
puts("\tver(B)ose ON|off - turn verbose mode on or off");
|
||||
puts("\tP)retend on|OFF - pretend that test files exist");
|
||||
puts("\tS)ave - save the Registry to disk");
|
||||
puts("\tpac(K) registry - squeeze out unused space from the Registry");
|
||||
puts("\tQ)uit - end the program");
|
||||
|
||||
} // vHelp
|
||||
|
||||
|
||||
void vInstall(char *cmd)
|
||||
{
|
||||
|
||||
char name[MAXREGPATHLEN+1];
|
||||
char path[MAXREGPATHLEN+1];
|
||||
VERSION ver;
|
||||
|
||||
parse(cmd, name, &ver, path);
|
||||
error("VR_Install", VR_Install(name, path, &ver));
|
||||
|
||||
} // vInstall
|
||||
|
||||
void vPack(char *cmd)
|
||||
{
|
||||
error("VR_PackRegistry", VR_PackRegistry(0));
|
||||
|
||||
} // vPack
|
||||
|
||||
void vPretend(char *cmd)
|
||||
{
|
||||
|
||||
if (!cmd)
|
||||
{
|
||||
gPretend = !!gPretend;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stricmp(cmd, "ON") == 0)
|
||||
gPretend = 1;
|
||||
else
|
||||
gPretend = 0;
|
||||
}
|
||||
|
||||
if (gVerbose)
|
||||
printf("Pretend mode is %s\n", gPretend ? "ON" : "OFF");
|
||||
|
||||
} // vPretend
|
||||
|
||||
void vRemove(char *cmd)
|
||||
{
|
||||
|
||||
error("VR_Remove", VR_Remove(cmd));
|
||||
|
||||
} // vRemove
|
||||
|
||||
|
||||
void vSave(char *cmd)
|
||||
{
|
||||
|
||||
error("VR_Checkpoint", VR_Checkpoint());
|
||||
|
||||
} // vSave
|
||||
|
||||
|
||||
void vTest(char *cmd)
|
||||
{
|
||||
|
||||
VERSION ver;
|
||||
ver.major = 4;
|
||||
ver.minor = 0;
|
||||
ver.release = 0;
|
||||
ver.build = 237;
|
||||
ver.check = gPretend ? 0xad : 0;
|
||||
|
||||
if (error("VR_Install", VR_Install("Navigator/NS.exe",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\NETSCAPE.EXE", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Navigator/Help",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\NETSCAPE.HLP", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Navigator/NSPR",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\NSPR32.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Navigator/Player",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\NSPLAYER.EXE", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Navigator/NSJava",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\NSJAVA32.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Web/Certificate.DB",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\CERT.DB", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Web/CertificateNI.DB",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\CERTNI.DB", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Web/Keys",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\KEY.DB", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("MailNews/Postal",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\System\\POSTAL32.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("MailNews/Folders/Inbox",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Mail\\INBOX.SNM", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("MailNews/Folders/Sent",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Mail\\SENT.SNM", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("MailNews/Folders/Trash",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Mail\\TRASH.SNM", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Components/NUL",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\Plugins\\NPNUL32.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Components/PointCast",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\Plugins\\NPPCN32.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Components/AWT",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\Java\\bin\\AWT3220.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Components/MM",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\Java\\bin\\MM3220.DLL", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Java/Classes.Zip",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\Java\\classes\\MOZ2_0.ZIP", &ver)))
|
||||
return;
|
||||
if (error("VR_Install", VR_Install("Java/Classes Directory",
|
||||
"c:\\Program Files\\Netscape\\Navigator\\Program\\Java\\classes\\MOZ2_0", &ver)))
|
||||
return;
|
||||
|
||||
|
||||
} // vTest
|
||||
|
||||
|
||||
void vUpdate(char *cmd)
|
||||
{
|
||||
|
||||
char name[MAXREGPATHLEN+1];
|
||||
char path[MAXREGPATHLEN+1];
|
||||
VERSION ver;
|
||||
|
||||
parse(cmd, name, &ver, path);
|
||||
error("VR_Update", VR_Update(name, path, &ver));
|
||||
|
||||
} // vUpdate
|
||||
|
||||
|
||||
void vVerify(char *cmd)
|
||||
{
|
||||
|
||||
error("VR_CheckEntry", VR_CheckEntry(0, cmd));
|
||||
|
||||
} // vVerify
|
||||
|
||||
|
||||
void interp(void)
|
||||
{
|
||||
|
||||
char line[256];
|
||||
char *p;
|
||||
|
||||
while(1)
|
||||
{
|
||||
putchar('>');
|
||||
putchar(' ');
|
||||
flushall();
|
||||
gets(line);
|
||||
|
||||
// p points to next word after verb on command line
|
||||
p = line;
|
||||
while (*p && *p!=' ')
|
||||
p++;
|
||||
if (!*p)
|
||||
p = 0;
|
||||
else
|
||||
{
|
||||
while(*p && *p==' ')
|
||||
p++;
|
||||
}
|
||||
|
||||
switch(toupper(line[0]))
|
||||
{
|
||||
case 'B':
|
||||
vVerbose(p);
|
||||
break;
|
||||
case 'C':
|
||||
vCreate(p);
|
||||
break;
|
||||
case 'D':
|
||||
vDisplay(p);
|
||||
break;
|
||||
case 'F':
|
||||
vFind(p);
|
||||
break;
|
||||
case 'H':
|
||||
default:
|
||||
vHelp(line);
|
||||
break;
|
||||
case 'I':
|
||||
vInstall(p);
|
||||
break;
|
||||
case 'K':
|
||||
vPack(p);
|
||||
break;
|
||||
case 'P':
|
||||
vPretend(p);
|
||||
break;
|
||||
case 'R':
|
||||
vRemove(p);
|
||||
break;
|
||||
case 'S':
|
||||
vSave(p);
|
||||
break;
|
||||
case 'T':
|
||||
vTest(p);
|
||||
break;
|
||||
case 'U':
|
||||
vUpdate(p);
|
||||
break;
|
||||
case 'V':
|
||||
vVerify(p);
|
||||
break;
|
||||
case 'Q':
|
||||
case 'X':
|
||||
vSave(0);
|
||||
return;
|
||||
} // switch
|
||||
} // while
|
||||
|
||||
assert(0);
|
||||
return; // shouldn't get here
|
||||
|
||||
} // interp
|
||||
|
||||
// EOF: interp.c
|
||||
438
mozilla/modules/libreg/tests/regtest.c
Normal file
438
mozilla/modules/libreg/tests/regtest.c
Normal file
@@ -0,0 +1,438 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "NSReg.h"
|
||||
#include "VerReg.h"
|
||||
|
||||
extern void interp(void);
|
||||
|
||||
#define REGFILE "c:\\temp\\reg.dat"
|
||||
|
||||
char *gRegistry;
|
||||
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
char *errstr(REGERR err)
|
||||
{
|
||||
|
||||
switch( err )
|
||||
{
|
||||
case REGERR_OK:
|
||||
return "REGERR_OK";
|
||||
case REGERR_FAIL:
|
||||
return "REGERR_FAIL";
|
||||
case REGERR_NOMORE:
|
||||
return "REGERR_MORE";
|
||||
case REGERR_NOFIND:
|
||||
return "REGERR_NOFIND";
|
||||
case REGERR_BADREAD:
|
||||
return "REGERR_BADREAD";
|
||||
case REGERR_BADLOCN:
|
||||
return "REGERR_BADLOCN";
|
||||
case REGERR_PARAM:
|
||||
return "REGERR_PARAM";
|
||||
case REGERR_BADMAGIC:
|
||||
return "REGERR_BADMAGIC";
|
||||
default:
|
||||
return "<Unknown>";
|
||||
}
|
||||
|
||||
} // errstr
|
||||
|
||||
|
||||
int CreateEmptyRegistry(void)
|
||||
{
|
||||
|
||||
#if 0
|
||||
int fh;
|
||||
remove(REGFILE); // ignore errors like file not found
|
||||
|
||||
fh = _open(REGFILE, _O_CREAT, _S_IREAD|_S_IWRITE);
|
||||
if (fh < 0)
|
||||
return -1;
|
||||
close(fh);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return VR_CreateRegistry(CR_NEWREGISTRY, "4.0");
|
||||
|
||||
} // CreateEmptyRegistry
|
||||
|
||||
|
||||
|
||||
int BuildTree(void)
|
||||
{
|
||||
|
||||
REGERR err;
|
||||
|
||||
err = NR_RegAdd(0,"/Machine/Old");
|
||||
if (err != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegAdd() returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
err = NR_RegAdd(0,"/User");
|
||||
if (err != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegAdd() returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
err = NR_RegAdd(0,"/Machine/4.0/Name1=Val1");
|
||||
if (err != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegAdd() returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
err = NR_RegAdd(0,"/Machine/4.0/Name2=Val2");
|
||||
if (err != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegAdd() returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
err = NR_RegAdd(0,"/Machine/4.0/Name2=Val3");
|
||||
if (err != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegAdd() returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
err = NR_RegAdd(0,"/Machine/4.0/Name3=Val4");
|
||||
if (err != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegAdd() returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return VR_Checkpoint();
|
||||
|
||||
} // BuildTree
|
||||
|
||||
|
||||
int FindKeys(void)
|
||||
{
|
||||
|
||||
RKEY key;
|
||||
REGERR err;
|
||||
char buf[80];
|
||||
|
||||
if (NR_RegGetKey(0, "", &key) == REGERR_OK)
|
||||
{
|
||||
printf("NR_RegGetKey returns ok for an empty path.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NR_RegGetKey(0, "/", &key) != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegGetKey couldn't find root.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NR_RegGetKey(0, "/Machine/Old", &key) != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegGetKey couldn't find Old\n");
|
||||
return 1;
|
||||
}
|
||||
printf("NR_RegGetKey returns key for Old as: 0x%lx\n", (long) key);
|
||||
|
||||
if (NR_RegGetKey(0, "/Machine/4.0", &key) != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegGetKey couldn't find 4.0\n");
|
||||
return 1;
|
||||
}
|
||||
printf("NR_RegGetKey returns key for 4.0 as: 0x%lx\n", (long) key);
|
||||
|
||||
// ----------------------------------------
|
||||
if ((err = NR_RegFindValue(0, "/Machine/4.0/Name3", 64, buf)) != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegFindValue (no key) returns %s\n", errstr(err));
|
||||
return 1;
|
||||
}
|
||||
printf("NR_RegFindValue (no key) of Name3 = %s\n", buf);
|
||||
|
||||
if (NR_RegFindValue(key, "Aliens", 64, buf) == REGERR_OK)
|
||||
{
|
||||
printf("NR_RegFindValue finds Aliens.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((err = NR_RegFindValue(key, "Name3", 64, buf)) != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegFindValue (w/key) returns %s\n", errstr(err));
|
||||
return 1;
|
||||
}
|
||||
printf("NR_RegFindValue (w/key) of Name3 = %s\n", buf);
|
||||
|
||||
return 0;
|
||||
|
||||
} // FindTree
|
||||
|
||||
int DumpTree(void)
|
||||
{
|
||||
|
||||
char *path;
|
||||
char *line = "------------------------------------------------------------";
|
||||
|
||||
path = malloc(2048);
|
||||
if (!path)
|
||||
return REGERR_FAIL;
|
||||
|
||||
strcpy(path, "/");
|
||||
puts(line);
|
||||
puts(path);
|
||||
|
||||
while (NR_RegNext( 0, 512, path ) == REGERR_OK)
|
||||
{
|
||||
puts(path);
|
||||
}
|
||||
|
||||
puts(line);
|
||||
|
||||
return 0;
|
||||
|
||||
} // DumpTree
|
||||
|
||||
|
||||
int ChangeKeys(void)
|
||||
{
|
||||
|
||||
REGERR err;
|
||||
|
||||
err = NR_RegUpdate(0,"/Machine/4.0/name3", "Infospect Software, Inc.");
|
||||
if (err)
|
||||
{
|
||||
printf("Couldn't update name3's value to ISI.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = NR_RegUpdate(0,"/Machine/4.0/name3=Infospect Software, Inc.", "\"Jonathan=Kid1\"");
|
||||
if (err)
|
||||
{
|
||||
printf("Couldn't update name3's value to Jon.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = NR_RegRename(0,"/Machine/4.0/name3=\"Jonathan=Kid1\"", "First born");
|
||||
if (err)
|
||||
{
|
||||
printf("Couldn't update name3's name to First born.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = NR_RegUpdate(0,"/Machine/4.0/name2=Val2", "Kelley Ann");
|
||||
if (err)
|
||||
{
|
||||
printf("Couldn't update name2's value to Kelley.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
return VR_Checkpoint();
|
||||
|
||||
} // ChangeKeys
|
||||
|
||||
|
||||
int DeleteKeys(void)
|
||||
{
|
||||
|
||||
REGERR err;
|
||||
|
||||
err = NR_RegDelete(0, "/User");
|
||||
if (err)
|
||||
{
|
||||
printf("NR_RegDelete returned %s.\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
return VR_Checkpoint();
|
||||
|
||||
} // DeleteKeys
|
||||
|
||||
|
||||
int StressTest(void)
|
||||
{
|
||||
|
||||
REGERR err;
|
||||
RKEY key;
|
||||
|
||||
printf("Starting stress...\n");
|
||||
|
||||
err = NR_RegGetKey(0, "/Machine/4.0", &key);
|
||||
if (err)
|
||||
{
|
||||
printf("Error getting key for 4.0 = %s\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
err = NR_RegAdd(key, "A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/"
|
||||
"A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/"
|
||||
"A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/" );
|
||||
|
||||
if (err)
|
||||
{
|
||||
printf("Adding humungous string returned %s\n", errstr(err));
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO: Add a value to one of the middle keys, get it back.
|
||||
|
||||
printf("Stress done.\n");
|
||||
return 0;
|
||||
|
||||
} // StressTest
|
||||
|
||||
|
||||
int Install(void)
|
||||
{
|
||||
|
||||
int err;
|
||||
VERSION ver;
|
||||
|
||||
ver.major = 4;
|
||||
ver.minor = 2;
|
||||
ver.release = 10;
|
||||
ver.build = 937;
|
||||
ver.check = 0;
|
||||
|
||||
err = VR_Install("Web/Navigator/netscape.exe",
|
||||
"c:\\Netscape\\NETSCAPE.EXE", &ver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ver.release = 19;
|
||||
ver.build = 722;
|
||||
ver.check = 0;
|
||||
err = VR_Install("Web/Navigator/nspr.dll",
|
||||
"c:\\Netscape\\System\\Vtcprac.386", &ver);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return VR_Checkpoint();
|
||||
|
||||
}
|
||||
|
||||
int GetInfo(void)
|
||||
{
|
||||
|
||||
int err;
|
||||
char buf[256];
|
||||
VERSION ver;
|
||||
|
||||
err = VR_GetPath("Web/Navigator/nspr.dll", 256, buf);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
printf("GetPath(nspr.dll) returns %s\n", buf);
|
||||
|
||||
err = VR_GetVersion("Web/Navigator/netscape.exe", &ver);
|
||||
if (err)
|
||||
return err;
|
||||
printf("GetVersion(netscape.exe) returns %d.%d.%d.%d and check=%d\n",
|
||||
ver.major, ver.minor, ver.release, ver.build, ver.check);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
printf("Registry Test 10/01/96.\n");
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
gRegistry = argv[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
gRegistry = REGFILE;
|
||||
}
|
||||
VR_RegistryName(gRegistry);
|
||||
|
||||
#if 1
|
||||
if (NR_RegOpen(gRegistry) != REGERR_OK)
|
||||
VR_CreateRegistry(CR_NEWREGISTRY, "4.0");
|
||||
interp();
|
||||
#else
|
||||
if (CreateEmptyRegistry())
|
||||
goto abort;
|
||||
|
||||
if (Install())
|
||||
goto done;
|
||||
|
||||
if (DumpTree())
|
||||
goto done;
|
||||
|
||||
if (GetInfo())
|
||||
goto done;
|
||||
|
||||
|
||||
#if defined(TEST_NR)
|
||||
if ((err = NR_RegOpen(REGFILE)) != REGERR_OK)
|
||||
{
|
||||
printf("NR_RegOpen(%s) returned %s...Test aborted.\n", REGFILE, errstr(err));
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (BuildTree())
|
||||
goto done;
|
||||
|
||||
if (FindKeys())
|
||||
goto done;
|
||||
|
||||
if (DumpTree())
|
||||
goto done;
|
||||
|
||||
if (ChangeKeys())
|
||||
goto done;
|
||||
|
||||
if (DeleteKeys())
|
||||
goto done;
|
||||
|
||||
if (DumpTree())
|
||||
goto done;
|
||||
|
||||
if (StressTest())
|
||||
goto done;
|
||||
|
||||
if (DumpTree())
|
||||
goto done;
|
||||
|
||||
done:
|
||||
NR_RegClose();
|
||||
#else
|
||||
done:
|
||||
#endif
|
||||
|
||||
abort:
|
||||
puts("Press Enter to continue...");
|
||||
getchar();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
1204
mozilla/modules/libreg/xpcom/nsRegistry.cpp
Normal file
1204
mozilla/modules/libreg/xpcom/nsRegistry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
30
mozilla/xpcom/Makefile.in
Normal file
30
mozilla/xpcom/Makefile.in
Normal file
@@ -0,0 +1,30 @@
|
||||
#!gmake
|
||||
# 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.
|
||||
|
||||
DEPTH = ..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += tests
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
6027
mozilla/xpcom/base/IIDS.h
Normal file
6027
mozilla/xpcom/base/IIDS.h
Normal file
File diff suppressed because it is too large
Load Diff
170
mozilla/xpcom/base/nsAgg.h
Normal file
170
mozilla/xpcom/base/nsAgg.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/* -*- 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 nsAgg_h___
|
||||
#define nsAgg_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
/**
|
||||
* Outer objects can implement nsIOuter if they choose, allowing them to
|
||||
* get notification if their inner objects (children) are effectively freed.
|
||||
* This allows them to reset any state associated with the inner object and
|
||||
* potentially unload it.
|
||||
*/
|
||||
class nsIOuter : public nsISupports {
|
||||
public:
|
||||
|
||||
/**
|
||||
* This method is called whenever an inner object's refcount is about to
|
||||
* become zero and the inner object should be released by the outer. This
|
||||
* allows the outer to clean up any state associated with the inner and
|
||||
* potentially unload the inner object. This method should call
|
||||
* inner->Release().
|
||||
*/
|
||||
NS_IMETHOD
|
||||
ReleaseInner(nsISupports* inner) = 0;
|
||||
|
||||
};
|
||||
|
||||
#define NS_IOUTER_IID \
|
||||
{ /* ea0bf9f0-3d67-11d2-8163-006008119d7a */ \
|
||||
0xea0bf9f0, \
|
||||
0x3d67, \
|
||||
0x11d2, \
|
||||
{0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Put this in your class's declaration:
|
||||
#define NS_DECL_AGGREGATED \
|
||||
NS_DECL_ISUPPORTS \
|
||||
\
|
||||
protected: \
|
||||
\
|
||||
/* You must implement this operation instead of the nsISupports */ \
|
||||
/* methods if you inherit from nsAggregated. */ \
|
||||
NS_IMETHOD \
|
||||
AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr); \
|
||||
\
|
||||
class Internal : public nsISupports { \
|
||||
public: \
|
||||
\
|
||||
Internal() {} \
|
||||
\
|
||||
NS_IMETHOD QueryInterface(const nsIID& aIID, \
|
||||
void** aInstancePtr); \
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void); \
|
||||
NS_IMETHOD_(nsrefcnt) Release(void); \
|
||||
\
|
||||
}; \
|
||||
\
|
||||
friend class Internal; \
|
||||
\
|
||||
nsISupports* fOuter; \
|
||||
Internal fAggregated; \
|
||||
\
|
||||
nsISupports* GetInner(void) { return &fAggregated; } \
|
||||
\
|
||||
public: \
|
||||
|
||||
|
||||
// Put this in your class's constructor:
|
||||
#define NS_INIT_AGGREGATED(outer) \
|
||||
PR_BEGIN_MACRO \
|
||||
NS_INIT_REFCNT(); \
|
||||
fOuter = outer; \
|
||||
PR_END_MACRO
|
||||
|
||||
|
||||
// Put this in your class's implementation file:
|
||||
#define NS_IMPL_AGGREGATED(_class) \
|
||||
NS_IMETHODIMP \
|
||||
_class::QueryInterface(const nsIID& aIID, void** aInstancePtr) \
|
||||
{ \
|
||||
/* try our own interfaces first before delegating to outer */ \
|
||||
nsresult rslt = AggregatedQueryInterface(aIID, aInstancePtr); \
|
||||
if (rslt != NS_OK && fOuter) \
|
||||
return fOuter->QueryInterface(aIID, aInstancePtr); \
|
||||
else \
|
||||
return rslt; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP_(nsrefcnt) \
|
||||
_class::AddRef(void) \
|
||||
{ \
|
||||
++mRefCnt; /* keep track of our refcount as well as outer's */ \
|
||||
if (fOuter) \
|
||||
return NS_ADDREF(fOuter); \
|
||||
else \
|
||||
return mRefCnt; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP_(nsrefcnt) \
|
||||
_class::Release(void) \
|
||||
{ \
|
||||
if (fOuter) { \
|
||||
nsISupports* outer = fOuter; /* in case we release ourself */ \
|
||||
nsIOuter* outerIntf; \
|
||||
static NS_DEFINE_IID(kIOuterIID, NS_IOUTER_IID); \
|
||||
if (mRefCnt == 1 && \
|
||||
outer->QueryInterface(kIOuterIID, \
|
||||
(void**)&outerIntf) == NS_OK) { \
|
||||
outerIntf->ReleaseInner(GetInner()); \
|
||||
outerIntf->Release(); \
|
||||
} \
|
||||
else \
|
||||
--mRefCnt; /* keep track of our refcount as well as outer's */ \
|
||||
return outer->Release(); \
|
||||
} \
|
||||
else { \
|
||||
if (--mRefCnt == 0) { \
|
||||
delete this; \
|
||||
return 0; \
|
||||
} \
|
||||
return mRefCnt; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP \
|
||||
_class::Internal::QueryInterface(const nsIID& aIID, void** aInstancePtr) \
|
||||
{ \
|
||||
_class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \
|
||||
return agg->AggregatedQueryInterface(aIID, aInstancePtr); \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP_(nsrefcnt) \
|
||||
_class::Internal::AddRef(void) \
|
||||
{ \
|
||||
_class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \
|
||||
return ++agg->mRefCnt; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHODIMP_(nsrefcnt) \
|
||||
_class::Internal::Release(void) \
|
||||
{ \
|
||||
_class* agg = (_class*)((char*)(this) - offsetof(_class, fAggregated)); \
|
||||
if (--agg->mRefCnt == 0) { \
|
||||
delete agg; \
|
||||
return 0; \
|
||||
} \
|
||||
return agg->mRefCnt; \
|
||||
} \
|
||||
|
||||
#endif /* nsAgg_h___ */
|
||||
129
mozilla/xpcom/base/nsAllocator.cpp
Normal file
129
mozilla/xpcom/base/nsAllocator.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
/* -*- 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.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of nsIAllocator using NSPR
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "nsAllocator.h"
|
||||
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
static NS_DEFINE_IID(kIAllocatorIID, NS_IALLOCATOR_IID);
|
||||
|
||||
nsAllocator::nsAllocator(nsISupports* outer)
|
||||
{
|
||||
NS_INIT_AGGREGATED(outer);
|
||||
}
|
||||
|
||||
nsAllocator::~nsAllocator(void)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_AGGREGATED(nsAllocator);
|
||||
|
||||
NS_METHOD
|
||||
nsAllocator::AggregatedQueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(kIAllocatorIID) ||
|
||||
aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = (void*) this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsAllocator::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
|
||||
{
|
||||
if (outer && !aIID.Equals(kISupportsIID))
|
||||
return NS_NOINTERFACE; // XXX right error?
|
||||
nsAllocator* mm = new nsAllocator(outer);
|
||||
if (mm == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
mm->AddRef();
|
||||
if (aIID.Equals(kISupportsIID))
|
||||
*aInstancePtr = mm->GetInner();
|
||||
else
|
||||
*aInstancePtr = mm;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_METHOD_(void*)
|
||||
nsAllocator::Alloc(PRUint32 size)
|
||||
{
|
||||
return PR_Malloc(size);
|
||||
}
|
||||
|
||||
NS_METHOD_(void*)
|
||||
nsAllocator::Realloc(void* ptr, PRUint32 size)
|
||||
{
|
||||
return PR_Realloc(ptr, size);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsAllocator::Free(void* ptr)
|
||||
{
|
||||
PR_Free(ptr);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsAllocator::HeapMinimize(void)
|
||||
{
|
||||
#ifdef XP_MAC
|
||||
// This used to live in the memory allocators no Mac, but does no more
|
||||
// Needs to be hooked up in the new world.
|
||||
// CallCacheFlushers(0x7fffffff);
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsAllocatorFactory::nsAllocatorFactory(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsAllocatorFactory::~nsAllocatorFactory(void)
|
||||
{
|
||||
}
|
||||
|
||||
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
||||
NS_IMPL_ISUPPORTS(nsAllocatorFactory, kIFactoryIID);
|
||||
|
||||
NS_METHOD
|
||||
nsAllocatorFactory::CreateInstance(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
void **aResult)
|
||||
{
|
||||
return nsAllocator::Create(aOuter, aIID, aResult);
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
nsAllocatorFactory::LockFactory(PRBool aLock)
|
||||
{
|
||||
return NS_OK; // XXX what?
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
93
mozilla/xpcom/base/nsAllocator.h
Normal file
93
mozilla/xpcom/base/nsAllocator.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* -*- 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.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of nsIAllocator using NSPR
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef nsAllocator_h__
|
||||
#define nsAllocator_h__
|
||||
|
||||
#include "nsIAllocator.h"
|
||||
#include "prmem.h"
|
||||
#include "nsAgg.h"
|
||||
|
||||
class nsAllocator : public nsIAllocator {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Allocates a block of memory of a particular size.
|
||||
*
|
||||
* @param size - the size of the block to allocate
|
||||
* @result the block of memory
|
||||
*/
|
||||
NS_IMETHOD_(void*) Alloc(PRUint32 size);
|
||||
|
||||
/**
|
||||
* Reallocates a block of memory to a new size.
|
||||
*
|
||||
* @param ptr - the block of memory to reallocate
|
||||
* @param size - the new size
|
||||
* @result the rellocated block of memory
|
||||
*/
|
||||
NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size);
|
||||
|
||||
/**
|
||||
* Frees a block of memory.
|
||||
*
|
||||
* @param ptr - the block of memory to free
|
||||
*/
|
||||
NS_IMETHOD Free(void* ptr);
|
||||
|
||||
/**
|
||||
* Attempts to shrink the heap.
|
||||
*/
|
||||
NS_IMETHOD HeapMinimize(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsAllocator(nsISupports* outer);
|
||||
virtual ~nsAllocator(void);
|
||||
|
||||
NS_DECL_AGGREGATED
|
||||
|
||||
static NS_METHOD
|
||||
Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "nsIFactory.h"
|
||||
|
||||
class nsAllocatorFactory : nsIFactory {
|
||||
public:
|
||||
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
void **aResult);
|
||||
|
||||
NS_IMETHOD LockFactory(PRBool aLock);
|
||||
|
||||
nsAllocatorFactory(void);
|
||||
~nsAllocatorFactory(void);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#endif // nsAllocator_h__
|
||||
54
mozilla/xpcom/base/nsCOMPtr.cpp
Normal file
54
mozilla/xpcom/base/nsCOMPtr.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "nsCOMPtr.h"
|
||||
|
||||
void
|
||||
nsCOMPtr_base::assign_with_AddRef( nsISupports* rawPtr )
|
||||
{
|
||||
if ( rawPtr )
|
||||
NSCAP_ADDREF(rawPtr);
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = rawPtr;
|
||||
}
|
||||
|
||||
void
|
||||
nsCOMPtr_base::assign_with_QueryInterface( nsISupports* rawPtr, const nsIID& iid, nsresult* result )
|
||||
{
|
||||
nsresult status = NS_OK;
|
||||
if ( !rawPtr || !NS_SUCCEEDED( status = rawPtr->QueryInterface(iid, NSCAP_REINTERPRET_CAST(void**, &rawPtr)) ) )
|
||||
rawPtr = 0;
|
||||
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
|
||||
mRawPtr = rawPtr;
|
||||
|
||||
if ( result )
|
||||
*result = status;
|
||||
}
|
||||
|
||||
void**
|
||||
nsCOMPtr_base::begin_assignment()
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = 0;
|
||||
return NSCAP_REINTERPRET_CAST(void**, &mRawPtr);
|
||||
}
|
||||
668
mozilla/xpcom/base/nsCOMPtr.h
Normal file
668
mozilla/xpcom/base/nsCOMPtr.h
Normal file
@@ -0,0 +1,668 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsCOMPtr_h___
|
||||
#define nsCOMPtr_h___
|
||||
|
||||
|
||||
|
||||
// Wrapping includes can speed up compiles (see "Large Scale C++ Software Design")
|
||||
#ifndef nsDebug_h___
|
||||
#include "nsDebug.h"
|
||||
// for |NS_PRECONDITION|
|
||||
#endif
|
||||
|
||||
#ifndef nsISupports_h___
|
||||
#include "nsISupports.h"
|
||||
// for |nsresult|, |NS_ADDREF|, et al
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
TO DO...
|
||||
|
||||
+ make alternative function for |getter_AddRefs| (or something)
|
||||
+ make constructor for |nsQueryInterface| explicit (suddenly construct/assign from raw pointer becomes illegal)
|
||||
+ Improve internal documentation
|
||||
+ mention *&
|
||||
+ alternatives for comparison
|
||||
+ do_QueryInterface
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* USER MANUAL
|
||||
|
||||
See also:
|
||||
<http://www.meer.net/ScottCollins/doc/nsCOMPtr.html>, or
|
||||
<http://www.mozilla.org/projects/xpcom/nsCOMPtr.html>
|
||||
|
||||
What is |nsCOMPtr|?
|
||||
|
||||
|nsCOMPtr| is a `smart-pointer'. It is a template class that acts, syntactically,
|
||||
just like an ordinary pointer in C or C++, i.e., you can apply |*| or |->| to it to
|
||||
`get to' what it points at. |nsCOMPtr| is smart in that, unlike a raw COM
|
||||
interface pointer, |nsCOMPtr| manages |AddRef|, |Release|, and |QueryInterface|
|
||||
_for_ you.
|
||||
|
||||
For instance, here is a typical snippet of code (at its most compact) where you assign
|
||||
a COM interface pointer into a member variable:
|
||||
|
||||
NS_IF_RELEASE(mFoop); // If I have one already, I must release it before over-writing it.
|
||||
if ( mFooP = aPtr ) // Now it's safe to assign it in, and, if it's not NULL
|
||||
mFooP->AddRef(); // I must |AddRef| it, since I'll be holding on to it.
|
||||
|
||||
If our member variable |mFooP| were a |nsCOMPtr|, however, the snippet above
|
||||
would look like this:
|
||||
|
||||
mFoop = aPtr; // Note: automatically |Release|s the old and |AddRef|s the new
|
||||
|
||||
|nsCOMPtr| helps you write code that is leak-proof, exception safe, and significantly
|
||||
less verbose than you would with raw COM interface pointers. With |nsCOMPtr|, you
|
||||
may never have to call |AddRef|, |Release|, or |QueryInterface| by hand.
|
||||
|
||||
|
||||
You still have to understand COM. You still have to know which functions return
|
||||
interface pointers that have already been |AddRef|ed and which don't. You still
|
||||
have to ensure your program logic doesn't produce circularly referencing garbage.
|
||||
|nsCOMPtr| is not a panacea. It is, however, helpful, easy to use, well-tested,
|
||||
and polite. It doesn't require that a function author cooperate with you, nor does
|
||||
your use force others to use it.
|
||||
|
||||
|
||||
Where should I use |nsCOMPtr|?
|
||||
|
||||
...
|
||||
|
||||
|
||||
Where _shouldn't_ I use |nsCOMPtr|?
|
||||
|
||||
In public interfaces... [[others]]
|
||||
|
||||
|
||||
How does a |nsCOMPtr| differ from a raw pointer?
|
||||
|
||||
A |nsCOMPtr| differs, syntactically, from a raw COM interface pointer in three
|
||||
ways:
|
||||
|
||||
+ It's declared differently, e.g.,
|
||||
|
||||
// instead of saying // you say
|
||||
IFoo* fooP; nsCOMPtr<IFoo> fooP;
|
||||
|
||||
|
||||
+ You can't call |AddRef| or |Release| through it,
|
||||
|
||||
fooP->AddRef(); // OK fooP->AddRef(); // Error: no permission
|
||||
fooP->Release(); // OK fooP->Release(); // Error: no permission
|
||||
|
||||
|
||||
+ You can't just apply an |&| to it to pass it to the typical `getter' function
|
||||
|
||||
AcquireFoo(&fooP); AcquireFoo( getter_AddRefs(fooP) );
|
||||
GetFoo(&fooP); GetFoo( getter_doesnt_AddRef(fooP) );
|
||||
|
||||
|
||||
How do I use |nsCOMPtr|?
|
||||
|
||||
Typically, you can use a |nsCOMPtr| exactly as you would a standard COM
|
||||
interface pointer:
|
||||
|
||||
IFoo* fooP; nsCOMPtr<IFoo> fooP;
|
||||
// ... // ...
|
||||
fooP->SomeFunction(x, y, z); fooP->SomeFunction(x, y, z);
|
||||
AnotherFunction(fooP); AnotherFunction(fooP);
|
||||
|
||||
if ( fooP ) if ( fooP )
|
||||
// ... // ...
|
||||
|
||||
if ( fooP == barP ) if ( fooP == barP )
|
||||
// ... // ...
|
||||
|
||||
There are some differences, though. In particular, you can't call |AddRef| or |Release|
|
||||
through a |nsCOMPtr| directly, nor would you need to. |AddRef| is called for you
|
||||
whenever you assign a COM interface pointer _into_ a |nsCOMPtr|. |Release| is
|
||||
called on the old value, and also when the |nsCOMPtr| goes out of scope. Trying
|
||||
to call |AddRef| or |Release| yourself will generate a compile-time error.
|
||||
|
||||
fooP->AddRef(); // fooP->AddRef(); // ERROR: no permission
|
||||
fooP->Release(); // fooP->Release(); // ERROR: no permission
|
||||
|
||||
The final difference is that a bare |nsCOMPtr| (or rather a pointer to it) can't
|
||||
be supplied as an argument to a function that `fills in' a COM interface pointer.
|
||||
Rather it must be wrapped with a utility call that says whether the function calls
|
||||
|AddRef| before returning, e.g.,
|
||||
|
||||
...->QueryInterface(riid, &fooP) ...->QueryInterface(riid, getter_AddRefs(fooP))
|
||||
|
||||
LookupFoo(&fooP); LookupFoo( getter_doesnt_AddRef(fooP) );
|
||||
|
||||
Don't worry. It's a compile-time error if you forget to wrap it.
|
||||
|
||||
Compare the raw-pointer way...
|
||||
|
||||
IFoo* foo = 0;
|
||||
nsresult status = CreateIFoo(&foo);
|
||||
if ( NS_SUCCEEDED(status) )
|
||||
{
|
||||
IBar* bar = 0;
|
||||
if ( NS_SUCCEEDED(status = foo->QueryInterface(riid, &bar)) )
|
||||
{
|
||||
IFooBar* foobar = 0;
|
||||
if ( NS_SUCCEEDED(status = CreateIFooBar(foo, bar, &foobar)) )
|
||||
{
|
||||
foobar->DoTheReallyHardThing();
|
||||
foobar->Release();
|
||||
}
|
||||
bar->Release();
|
||||
}
|
||||
foo->Release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
To the smart-pointer way...
|
||||
|
||||
nsCOMPtr<IFoo> fooP;
|
||||
nsresult status = CreateIFoo( getter_AddRefs(fooP) );
|
||||
if ( NS_SUCCEEDED(status) )
|
||||
if ( nsCOMPtr<IBar> barP( fooP ) )
|
||||
{
|
||||
nsCOMPtr<IFooBar> fooBarP;
|
||||
if ( NS_SUCCEEDED(status = CreateIFooBar(fooP, barP, getter_AddRefs(fooBarP))) )
|
||||
fooBarP->DoTheReallyHardThing();
|
||||
}
|
||||
|
||||
|
||||
Is there an easy way to convert my current code?
|
||||
|
||||
...
|
||||
|
||||
|
||||
What do I have to beware of?
|
||||
|
||||
VC++ < 6.0 _can't_ handle the following situation
|
||||
|
||||
class nsIFoo; // forward declare some class
|
||||
// ...
|
||||
nsCOMPtr<nsIFoo> bar; // ERROR: incomplete type nsIFoo, etc.
|
||||
|
||||
Instead, you must make sure that you actually defined the underlying interface class, e.g.,
|
||||
|
||||
#include "nsIFoo.h" // fully defines |class nsIFoo|
|
||||
// ...
|
||||
nsCOMPtr<nsIFoo> bar; // no problem
|
||||
|
||||
Why is this? It's because VC++ tries to instantiate every member of the template
|
||||
as soon as it sees the template declarations. Bad compiler. No cookie!
|
||||
[[Thanks to mjudge, waterson, and pinkerton on this one.]]
|
||||
|
||||
|
||||
Why does |getter_AddRefs| have such a funny name? I.e., why doesn't it follow our
|
||||
naming conventions?
|
||||
|
||||
|getter_AddRefs| and |getter_doesnt_AddRef| use underscores for the same
|
||||
reason our special macros do, quoting from our coding conventions "...to make them
|
||||
stick out like a sore thumb". Note also that since |AddRef| is one word,
|
||||
|getter_AddRefs| and |getter_doesnt_AddRef| couldn't have the right spacing if only inter-
|
||||
caps were used.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
WARNING:
|
||||
This file defines several macros for internal use only. These macros begin with the
|
||||
prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use
|
||||
only for cross-platform compatibility, and are subject to change without notice.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Set up some |#define|s to turn off a couple of troublesome C++ features.
|
||||
Interestingly, none of the compilers barf on template stuff.
|
||||
|
||||
Ideally, we would want declarations like these in a configuration file
|
||||
that everybody would get. Deciding exactly how to do that should
|
||||
be part of the process of moving from experimental to production.
|
||||
|
||||
Update: ramiro is working on getting these into the configuration system.
|
||||
*/
|
||||
|
||||
#if defined(__GNUG__) && (__GNUC_MINOR__ <= 90) && !defined(SOLARIS)
|
||||
#define NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
|
||||
#if (defined(LINUX) || defined(__bsdi__)) && (__GNUC_MINOR__ <= 7)
|
||||
#define NSCAP_NEED_UNUSED_VIRTUAL_IMPLEMENTATIONS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS) && !defined(__GNUG__)
|
||||
#define NSCAP_NO_BOOL
|
||||
#define NSCAP_NO_EXPLICIT
|
||||
#define NSCAP_NO_NEW_CASTS
|
||||
#define NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER<1100)
|
||||
#define NSCAP_NO_EXPLICIT
|
||||
#define NSCAP_NO_BOOL
|
||||
#endif
|
||||
|
||||
#if defined(IRIX)
|
||||
#define NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
#define NSCAP_NO_EXPLICIT
|
||||
#define NSCAP_NO_NEW_CASTS
|
||||
#define NSCAP_NO_BOOL
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NSCAP_NO_EXPLICIT
|
||||
#define explicit
|
||||
#endif
|
||||
|
||||
#ifndef NSCAP_NO_NEW_CASTS
|
||||
#define NSCAP_REINTERPRET_CAST(T,x) reinterpret_cast<T>(x)
|
||||
#else
|
||||
#define NSCAP_REINTERPRET_CAST(T,x) ((T)(x))
|
||||
#endif
|
||||
|
||||
#ifndef NSCAP_NO_BOOL
|
||||
typedef bool NSCAP_BOOL;
|
||||
#else
|
||||
typedef PRBool NSCAP_BOOL;
|
||||
#endif
|
||||
|
||||
#ifdef NSCAP_FEATURE_DEBUG_MACROS
|
||||
#define NSCAP_ADDREF(ptr) NS_ADDREF(ptr)
|
||||
#define NSCAP_RELEASE(ptr) NS_RELEASE(ptr)
|
||||
#else
|
||||
#define NSCAP_ADDREF(ptr) (ptr)->AddRef()
|
||||
#define NSCAP_RELEASE(ptr) (ptr)->Release()
|
||||
#endif
|
||||
|
||||
/*
|
||||
WARNING:
|
||||
VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined
|
||||
in an order that satisfies:
|
||||
|
||||
nsDerivedSafe < nsCOMPtr
|
||||
nsDontAddRef < nsCOMPtr
|
||||
nsCOMPtr < nsGetterAddRefs
|
||||
|
||||
The other compilers probably won't complain, so please don't reorder these
|
||||
classes, on pain of breaking 4.2 compatibility.
|
||||
*/
|
||||
|
||||
|
||||
template <class T>
|
||||
class nsDerivedSafe : public T
|
||||
/*
|
||||
No client should ever see or have to type the name of this class. It is the
|
||||
artifact that makes it a compile-time error to call |AddRef| and |Release|
|
||||
on a |nsCOMPtr|.
|
||||
|
||||
See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al.
|
||||
*/
|
||||
{
|
||||
private:
|
||||
#ifndef NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
using T::AddRef;
|
||||
using T::Release;
|
||||
#else
|
||||
nsrefcnt AddRef();
|
||||
nsrefcnt Release();
|
||||
#endif
|
||||
|
||||
void operator delete( void* ); // NOT TO BE IMPLEMENTED
|
||||
// declaring |operator delete| private makes calling delete on an interface pointer a compile error
|
||||
|
||||
nsDerivedSafe& operator=( const nsDerivedSafe& ); // NOT TO BE IMPLEMENTED
|
||||
// you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one
|
||||
};
|
||||
|
||||
#if defined(NSCAP_NO_MEMBER_USING_DECLARATIONS) && defined(NSCAP_NEED_UNUSED_VIRTUAL_IMPLEMENTATIONS)
|
||||
template <class T>
|
||||
nsrefcnt
|
||||
nsDerivedSafe<T>::AddRef()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
nsrefcnt
|
||||
nsDerivedSafe<T>::Release()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct nsDontQueryInterface
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
explicit
|
||||
nsDontQueryInterface( T* aRawPtr )
|
||||
: mRawPtr(aRawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
T* mRawPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsDontQueryInterface<T>
|
||||
dont_QueryInterface( T* aRawPtr )
|
||||
{
|
||||
return nsDontQueryInterface<T>(aRawPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct nsQueryInterface
|
||||
{
|
||||
// explicit
|
||||
nsQueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
|
||||
: mRawPtr(aRawPtr),
|
||||
mErrorPtr(error)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsISupports* mRawPtr;
|
||||
nsresult* mErrorPtr;
|
||||
};
|
||||
|
||||
inline
|
||||
nsQueryInterface
|
||||
do_QueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
|
||||
{
|
||||
return nsQueryInterface(aRawPtr, error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct nsDontAddRef
|
||||
/*
|
||||
...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_
|
||||
|AddRef|ing it. You would rarely use this directly, but rather through the
|
||||
machinery of |getter_AddRefs| in the argument list to functions that |AddRef|
|
||||
their results before returning them to the caller.
|
||||
|
||||
See also |getter_AddRefs()| and |class nsGetterAddRefs|.
|
||||
*/
|
||||
{
|
||||
explicit
|
||||
nsDontAddRef( T* aRawPtr )
|
||||
: mRawPtr(aRawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
T* mRawPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsDontAddRef<T>
|
||||
dont_AddRef( T* aRawPtr )
|
||||
/*
|
||||
...makes typing easier, because it deduces the template type, e.g.,
|
||||
you write |dont_AddRef(fooP)| instead of |nsDontAddRef<IFoo>(fooP)|.
|
||||
|
||||
Like the class it is shorthand for, you would rarely use this directly,
|
||||
but rather through |getter_AddRefs|.
|
||||
*/
|
||||
{
|
||||
return nsDontAddRef<T>(aRawPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class nsCOMPtr_base
|
||||
{
|
||||
public:
|
||||
|
||||
nsCOMPtr_base( nsISupports* rawPtr = 0 )
|
||||
: mRawPtr(rawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
~nsCOMPtr_base()
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
}
|
||||
|
||||
NS_EXPORT void assign_with_AddRef( nsISupports* );
|
||||
NS_EXPORT void assign_with_QueryInterface( nsISupports*, const nsIID&, nsresult* );
|
||||
NS_EXPORT void** begin_assignment();
|
||||
|
||||
protected:
|
||||
nsISupports* mRawPtr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
class nsCOMPtr : private nsCOMPtr_base
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
nsCOMPtr()
|
||||
// : nsCOMPtr_base(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsQueryInterface& aSmartPtr )
|
||||
// : nsCOMPtr_base(0)
|
||||
{
|
||||
assign_with_QueryInterface(aSmartPtr.mRawPtr, T::IID(), aSmartPtr.mErrorPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsDontAddRef<T>& aSmartPtr )
|
||||
: nsCOMPtr_base(aSmartPtr.mRawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsDontQueryInterface<T>& aSmartPtr )
|
||||
: nsCOMPtr_base(aSmartPtr.mRawPtr)
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_ADDREF(mRawPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsCOMPtr<T>& aSmartPtr )
|
||||
: nsCOMPtr_base(aSmartPtr.mRawPtr)
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_ADDREF(mRawPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsQueryInterface& rhs )
|
||||
{
|
||||
assign_with_QueryInterface(rhs.mRawPtr, T::IID(), rhs.mErrorPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsDontAddRef<T>& rhs )
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = rhs.mRawPtr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsDontQueryInterface<T>& rhs )
|
||||
{
|
||||
assign_with_AddRef(rhs.mRawPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsCOMPtr& rhs )
|
||||
{
|
||||
assign_with_AddRef(rhs.mRawPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsDerivedSafe<T>*
|
||||
get() const
|
||||
// returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
|
||||
{
|
||||
return NSCAP_REINTERPRET_CAST(nsDerivedSafe<T>*, mRawPtr);
|
||||
}
|
||||
|
||||
nsDerivedSafe<T>*
|
||||
operator->() const
|
||||
// returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
|
||||
{
|
||||
NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->().");
|
||||
return get();
|
||||
}
|
||||
|
||||
nsDerivedSafe<T>&
|
||||
operator*() const
|
||||
// returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
|
||||
{
|
||||
NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*().");
|
||||
return *get();
|
||||
}
|
||||
|
||||
operator nsDerivedSafe<T>*() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
#if 0
|
||||
private:
|
||||
friend class nsGetterAddRefs<T>;
|
||||
|
||||
/*
|
||||
In a perfect world, the following member function, |StartAssignment|, would be private.
|
||||
It is and should be only accessed by the closely related class |nsGetterAddRefs<T>|.
|
||||
|
||||
Unfortunately, some compilers---most notably VC++5.0---fail to grok the
|
||||
friend declaration above or in any alternate acceptable form. So, physically
|
||||
it will be public (until our compilers get smarter); but it is not to be
|
||||
considered part of the logical public interface.
|
||||
*/
|
||||
#endif
|
||||
|
||||
T**
|
||||
StartAssignment()
|
||||
{
|
||||
return NSCAP_REINTERPRET_CAST(T**, begin_assignment());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class nsGetterAddRefs
|
||||
/*
|
||||
...
|
||||
|
||||
This class is designed to be used for anonymous temporary objects in the
|
||||
argument list of calls that return COM interface pointers, e.g.,
|
||||
|
||||
nsCOMPtr<IFoo> fooP;
|
||||
...->QueryInterface(iid, nsGetterAddRefs<IFoo>(fooP))
|
||||
...->QueryInterface(iid, getter_AddRefs(fooP))
|
||||
|
||||
When initialized with a |nsCOMPtr|, as in the example above, it returns
|
||||
a |void**| (or |T**| if needed) that the outer call (|QueryInterface| in this
|
||||
case) can fill in. When this temporary object goes out of scope, just after
|
||||
the call returns, its destructor assigned the resulting interface pointer, i.e.,
|
||||
|QueryInterface|s result, into the |nsCOMPtr| it was initialized with.
|
||||
|
||||
See also |nsGetterDoesntAddRef|.
|
||||
*/
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
nsGetterAddRefs( nsCOMPtr<T>& aSmartPtr )
|
||||
: mTargetSmartPtr(aSmartPtr)
|
||||
{
|
||||
// nothing else to do
|
||||
}
|
||||
|
||||
operator void**()
|
||||
{
|
||||
// NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
|
||||
return NSCAP_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment());
|
||||
}
|
||||
|
||||
T*&
|
||||
operator*()
|
||||
{
|
||||
// NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
|
||||
return *(mTargetSmartPtr.StartAssignment());
|
||||
}
|
||||
|
||||
operator T**()
|
||||
{
|
||||
// NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
|
||||
return mTargetSmartPtr.StartAssignment();
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<T>& mTargetSmartPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsGetterAddRefs<T>
|
||||
getter_AddRefs( nsCOMPtr<T>& aSmartPtr )
|
||||
/*
|
||||
Used around a |nsCOMPtr| when
|
||||
...makes the class |nsGetterAddRefs<T>| invisible.
|
||||
*/
|
||||
{
|
||||
return nsGetterAddRefs<T>(aSmartPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !defined(nsCOMPtr_h___)
|
||||
218
mozilla/xpcom/base/nsCom.h
Normal file
218
mozilla/xpcom/base/nsCom.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsCom_h__
|
||||
#define nsCom_h__
|
||||
|
||||
/*
|
||||
* API Import/Export macros
|
||||
*/
|
||||
|
||||
#ifdef _IMPL_NS_COM
|
||||
#ifdef XP_PC
|
||||
#define NS_COM _declspec(dllexport)
|
||||
#else /* !XP_PC */
|
||||
#define NS_COM
|
||||
#endif /* !XP_PC */
|
||||
#else /* !_IMPL_NS_COM */
|
||||
#ifdef XP_PC
|
||||
#define NS_COM _declspec(dllimport)
|
||||
#else /* !XP_PC */
|
||||
#define NS_COM
|
||||
#endif /* !XP_PC */
|
||||
#endif /* !_IMPL_NS_COM */
|
||||
|
||||
/*
|
||||
* DLL Export macro
|
||||
*/
|
||||
|
||||
#if defined(XP_PC)
|
||||
|
||||
#define NS_EXPORT _declspec(dllexport)
|
||||
#define NS_EXPORT_(type) _declspec(dllexport) type __stdcall
|
||||
|
||||
#define NS_IMETHOD_(type) virtual type __stdcall
|
||||
#define NS_IMETHOD virtual nsresult __stdcall
|
||||
#define NS_IMETHODIMP_(type) type __stdcall
|
||||
#define NS_IMETHODIMP nsresult __stdcall
|
||||
|
||||
#define NS_METHOD_(type) type __stdcall
|
||||
#define NS_METHOD nsresult __stdcall
|
||||
|
||||
#elif defined(XP_MAC)
|
||||
|
||||
#define NS_EXPORT __declspec(export)
|
||||
#define NS_EXPORT_(type) __declspec(export) type
|
||||
|
||||
#define NS_IMETHOD_(type) virtual type
|
||||
#define NS_IMETHOD virtual nsresult
|
||||
#define NS_IMETHODIMP_(type) type
|
||||
#define NS_IMETHODIMP nsresult
|
||||
|
||||
#define NS_METHOD_(type) type
|
||||
#define NS_METHOD nsresult
|
||||
|
||||
#else /* !XP_PC && !XP_MAC */
|
||||
|
||||
#define NS_EXPORT
|
||||
#define NS_EXPORT_(type) type
|
||||
|
||||
#define NS_IMETHOD_(type) virtual type
|
||||
#define NS_IMETHOD virtual nsresult
|
||||
#define NS_IMETHODIMP_(type) type
|
||||
#define NS_IMETHODIMP nsresult
|
||||
|
||||
#define NS_METHOD_(type) type
|
||||
#define NS_METHOD nsresult
|
||||
|
||||
#endif /* !XP_PC */
|
||||
|
||||
/* use these functions to associate get/set methods with a
|
||||
C++ member variable
|
||||
*/
|
||||
|
||||
#define NS_METHOD_GETTER(_method, _type, _member) \
|
||||
_method(_type* aResult) \
|
||||
{\
|
||||
if (!aResult) return NS_ERROR_NULL_POINTER; \
|
||||
*aResult = _member; \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
#define NS_METHOD_SETTER(_method, _type, _member) \
|
||||
_method(_type aResult) \
|
||||
{ \
|
||||
_member = aResult; \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
/*
|
||||
* special for strings to get/set char* strings
|
||||
* using PL_strdup and PR_FREEIF
|
||||
*/
|
||||
#define NS_METHOD_GETTER_STR(_method,_member) \
|
||||
_method(char* *aString)\
|
||||
{\
|
||||
if (!aString) return NS_ERROR_NULL_POINTER; \
|
||||
*aString = PL_strdup(_member); \
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
#define NS_METHOD_SETTER_STR(_method, _member) \
|
||||
_method(char *aString)\
|
||||
{\
|
||||
PR_FREEIF(_member);\
|
||||
if (aString) _member = PL_strdup(aString); \
|
||||
else _member = nsnull;\
|
||||
return NS_OK; \
|
||||
}
|
||||
|
||||
/* Getter/Setter macros.
|
||||
Usage:
|
||||
NS_IMPL_[CLASS_]GETTER[_<type>](method, [type,] member);
|
||||
NS_IMPL_[CLASS_]SETTER[_<type>](method, [type,] member);
|
||||
NS_IMPL_[CLASS_]GETSET[_<type>]([class, ]postfix, [type,] member);
|
||||
|
||||
where:
|
||||
CLASS_ - implementation is inside a class definition
|
||||
(otherwise the class name is needed)
|
||||
Do NOT use in publicly exported header files, because
|
||||
the implementation may be included many times over.
|
||||
Instead, use the non-CLASS_ version.
|
||||
_<type> - For more complex (STR, IFACE) data types
|
||||
(otherwise the simple data type is needed)
|
||||
method - name of the method, such as GetWidth or SetColor
|
||||
type - simple data type if required
|
||||
member - class member variable such as m_width or mColor
|
||||
class - the class name, such as Window or MyObject
|
||||
postfix - Method part after Get/Set such as "Width" for "GetWidth"
|
||||
|
||||
Example:
|
||||
class Window {
|
||||
public:
|
||||
NS_IMPL_CLASS_GETSET(Width, int, m_width);
|
||||
NS_IMPL_CLASS_GETTER_STR(GetColor, m_color);
|
||||
NS_IMETHOD SetColor(char *color);
|
||||
|
||||
private:
|
||||
int m_width; // read/write
|
||||
char *m_color; // readonly
|
||||
};
|
||||
|
||||
// defined outside of class
|
||||
NS_IMPL_SETTER_STR(Window::GetColor, m_color);
|
||||
|
||||
Questions/Comments to alecf@netscape.com
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Getter/Setter implementation within a class definition
|
||||
*/
|
||||
|
||||
/* simple data types */
|
||||
#define NS_IMPL_CLASS_GETTER(_method, _type, _member) \
|
||||
NS_IMETHOD NS_METHOD_GETTER(_method, _type, _member)
|
||||
|
||||
#define NS_IMPL_CLASS_SETTER(_method, _type, _member) \
|
||||
NS_IMETHOD NS_METHOD_SETTER(_method, _type, _member)
|
||||
|
||||
#define NS_IMPL_CLASS_GETSET(_postfix, _type, _member) \
|
||||
NS_IMPL_CLASS_GETTER(Get##_postfix, _type, _member) \
|
||||
NS_IMPL_CLASS_SETTER(Set##_postfix, _type, _member)
|
||||
|
||||
/* strings */
|
||||
#define NS_IMPL_CLASS_GETTER_STR(_method, _member) \
|
||||
NS_IMETHOD NS_METHOD_GETTER_STR(_method, _member)
|
||||
|
||||
#define NS_IMPL_CLASS_SETTER_STR(_method, _member) \
|
||||
NS_IMETHOD NS_METHOD_SETTER_STR(_method, _member)
|
||||
|
||||
#define NS_IMPL_CLASS_GETSET_STR(_postfix, _member) \
|
||||
NS_IMPL_CLASS_GETTER_STR(Get##_postfix, _member) \
|
||||
NS_IMPL_CLASS_SETTER_STR(Set##_postfix, _member)
|
||||
|
||||
/* Getter/Setter implementation outside of a class definition */
|
||||
|
||||
/* simple data types */
|
||||
#define NS_IMPL_GETTER(_method, _type, _member) \
|
||||
NS_IMETHODIMP NS_METHOD_GETTER(_method, _type, _member)
|
||||
|
||||
#define NS_IMPL_SETTER(_method, _type, _member) \
|
||||
NS_IMETHODIMP NS_METHOD_SETTER(_method, _type, _member)
|
||||
|
||||
#define NS_IMPL_GETSET(_class, _postfix, _type, _member) \
|
||||
NS_IMPL_GETTER(_class::Get##_postfix, _type, _member) \
|
||||
NS_IMPL_SETTER(_class::Set##_postfix, _type, _member)
|
||||
|
||||
/* strings */
|
||||
#define NS_IMPL_GETTER_STR(_method, _member) \
|
||||
NS_IMETHODIMP NS_METHOD_GETTER_STR(_method, _member)
|
||||
|
||||
#define NS_IMPL_SETTER_STR(_method, _member) \
|
||||
NS_IMETHODIMP NS_METHOD_SETTER_STR(_method, _member)
|
||||
|
||||
#define NS_IMPL_GETSET_STR(_class, _postfix, _member) \
|
||||
NS_IMPL_GETTER_STR(_class::Get##_postfix, _member) \
|
||||
NS_IMPL_SETTER_STR(_class::Set##_postfix, _member)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
169
mozilla/xpcom/base/nsDebug.cpp
Normal file
169
mozilla/xpcom/base/nsDebug.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "nsDebug.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(XP_MAC)
|
||||
#define TEMP_MAC_HACK
|
||||
|
||||
//------------------------
|
||||
#ifdef TEMP_MAC_HACK
|
||||
#include <MacTypes.h>
|
||||
#include <Processes.h>
|
||||
|
||||
// TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON
|
||||
// LOGGING ON MACINTOSH
|
||||
// At this moment, NSPR's logging is a no-op on Macintosh.
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#undef PR_LOG
|
||||
#define PR_LOG(module,level,args) dprintf args
|
||||
static void dprintf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
Str255 buffer;
|
||||
|
||||
va_start(ap, format);
|
||||
buffer[0] = vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
DebugStr(buffer);
|
||||
}
|
||||
#endif // TEMP_MAC_HACK
|
||||
//------------------------
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the nsDebug methods. Note that this code is
|
||||
* always compiled in, in case some other module that uses it is
|
||||
* compiled with debugging even if this library is not.
|
||||
*/
|
||||
|
||||
static PRLogModuleInfo* gDebugLog;
|
||||
|
||||
static void InitLog(void)
|
||||
{
|
||||
if (0 == gDebugLog) {
|
||||
gDebugLog = PR_NewLogModule("nsDebug");
|
||||
gDebugLog->level = PR_LOG_DEBUG;
|
||||
}
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Abort(const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Abort: at file %s, line %d", aFile, aLine));
|
||||
PR_LogFlush();
|
||||
#if defined(_WIN32)
|
||||
long* __p = (long*) 0x7;
|
||||
*__p = 0x7;
|
||||
#elif defined(XP_MAC)
|
||||
ExitToShell();
|
||||
#elif defined(XP_UNIX)
|
||||
::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Break(const char* aFile, PRIntn aLine)
|
||||
{
|
||||
#ifndef TEMP_MAC_HACK
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Break: at file %s, line %d", aFile, aLine));
|
||||
PR_LogFlush();
|
||||
//XXX this works on win32 only for now. For all the other platforms call Abort
|
||||
#if defined(_WIN32)
|
||||
::DebugBreak();
|
||||
#else
|
||||
Abort(aFile, aLine);
|
||||
#endif
|
||||
#endif // TEMP_MAC_HACK
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::PreCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("PreCondition: \"%s\" (%s) at file %s, line %d", aStr, aExpr,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::PostCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("PostCondition: \"%s\" (%s) at file %s, line %d", aStr, aExpr,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Assertion(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Assertion: \"%s\" (%s) at file %s, line %d", aStr, aExpr,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::NotYetImplemented(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("NotYetImplemented: \"%s\" at file %s, line %d", aMessage,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::NotReached(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("NotReached: \"%s\" at file %s, line %d", aMessage, aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Error(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Error: \"%s\" at file %s, line %d", aMessage, aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Warning(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Warning: \"%s\" at file %s, line %d", aMessage, aFile, aLine));
|
||||
}
|
||||
179
mozilla/xpcom/base/nsDebug.h
Normal file
179
mozilla/xpcom/base/nsDebug.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsDebug_h___
|
||||
#define nsDebug_h___
|
||||
|
||||
#include "nsCom.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define NS_DEBUG
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Namespace for debugging methods. Note that your code must use the
|
||||
* macros defined later in this file so that the debug code can be
|
||||
* conditionally compiled out.
|
||||
*/
|
||||
class nsDebug {
|
||||
public:
|
||||
// XXX add in log controls here
|
||||
// XXX probably want printf type arguments
|
||||
|
||||
/**
|
||||
* Abort the executing program. This works on all architectures.
|
||||
*/
|
||||
static NS_COM void Abort(const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Break the executing program into the debugger.
|
||||
*/
|
||||
static NS_COM void Break(const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a pre-condition message to the debug log
|
||||
*/
|
||||
static NS_COM void PreCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a post-condition message to the debug log
|
||||
*/
|
||||
static NS_COM void PostCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log an assertion message to the debug log
|
||||
*/
|
||||
static NS_COM void Assertion(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a not-yet-implemented message to the debug log
|
||||
*/
|
||||
static NS_COM void NotYetImplemented(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a not-reached message to the debug log
|
||||
*/
|
||||
static NS_COM void NotReached(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log an error message to the debug log. This call returns.
|
||||
*/
|
||||
static NS_COM void Error(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a warning message to the debug log.
|
||||
*/
|
||||
static NS_COM void Warning(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
};
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
/**
|
||||
* Test a precondition for truth. If the expression is not true then
|
||||
* trigger a program failure.
|
||||
*/
|
||||
#define NS_PRECONDITION(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::PreCondition(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Test an assertion for truth. If the expression is not true then
|
||||
* trigger a program failure.
|
||||
*/
|
||||
#define NS_ASSERTION(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::Assertion(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Test an assertion for truth. If the expression is not true then
|
||||
* trigger a program failure. The expression will still be
|
||||
* executed in release mode.
|
||||
*/
|
||||
#define NS_VERIFY(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::Assertion(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Test a post-condition for truth. If the expression is not true then
|
||||
* trigger a program failure.
|
||||
*/
|
||||
#define NS_POSTCONDITION(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::PostCondition(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* This macros triggers a program failure if executed. It indicates that
|
||||
* an attempt was made to execute some unimplimented functionality.
|
||||
*/
|
||||
#define NS_NOTYETIMPLEMENTED(str) \
|
||||
nsDebug::NotYetImplemented(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* This macros triggers a program failure if executed. It indicates that
|
||||
* an attempt was made to execute some unimplimented functionality.
|
||||
*/
|
||||
#define NS_NOTREACHED(str) \
|
||||
nsDebug::NotReached(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Log an error message.
|
||||
*/
|
||||
#define NS_ERROR(str) \
|
||||
nsDebug::Error(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Log a warning message.
|
||||
*/
|
||||
#define NS_WARNING(str) \
|
||||
nsDebug::Warning(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Trigger an abort
|
||||
*/
|
||||
#define NS_ABORT() \
|
||||
nsDebug::Abort(__FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Cause a break
|
||||
*/
|
||||
#define NS_BREAK() \
|
||||
nsDebug::Break(__FILE__, __LINE__)
|
||||
|
||||
#else /* NS_DEBUG */
|
||||
|
||||
#define NS_PRECONDITION(expr,str) {}
|
||||
#define NS_ASSERTION(expr,str) {}
|
||||
#define NS_VERIFY(expr,str) expr
|
||||
#define NS_POSTCONDITION(expr,str) {}
|
||||
#define NS_NOTYETIMPLEMENTED(str) {}
|
||||
#define NS_NOTREACHED(str) {}
|
||||
#define NS_ERROR(str) {}
|
||||
#define NS_WARNING(str) {}
|
||||
#define NS_ABORT() {}
|
||||
#define NS_BREAK() {}
|
||||
|
||||
#endif /* ! NS_DEBUG */
|
||||
|
||||
#endif /* nsDebug_h___ */
|
||||
186
mozilla/xpcom/base/nsError.h
Normal file
186
mozilla/xpcom/base/nsError.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsError_h
|
||||
#define nsError_h
|
||||
|
||||
#ifndef prtypes_h___
|
||||
#include "prtypes.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Generic result data type
|
||||
*/
|
||||
|
||||
typedef PRUint32 nsresult;
|
||||
|
||||
/*
|
||||
* To add error code to your module, you need to do the following:
|
||||
*
|
||||
* 1) Add a module offset code. Add yours to the bottom of the list
|
||||
* right below this comment, adding 1.
|
||||
*
|
||||
* 2) In your module, define a header file which uses one of the
|
||||
* NE_ERROR_GENERATExxxxxx macros. Some examples below:
|
||||
*
|
||||
* #define NS_ERROR_MYMODULE_MYERROR1 NS_ERROR_GENERATE(NS_ERROR_SEVERITY_ERROR,NS_ERROR_MODULE_MYMODULE,1)
|
||||
* #define NS_ERROR_MYMODULE_MYERROR2 NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_MYMODULE,2)
|
||||
* #define NS_ERROR_MYMODULE_MYERROR3 NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_MYMODULE,3)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @name Standard Module Offset Code. Each Module should identify a unique number
|
||||
* and then all errors associated with that module become offsets from the
|
||||
* base associated with that module id. There are 16 bits of code bits for
|
||||
* each module.
|
||||
*/
|
||||
|
||||
#define NS_ERROR_MODULE_XPCOM 1
|
||||
#define NS_ERROR_MODULE_BASE 2
|
||||
#define NS_ERROR_MODULE_GFX 3
|
||||
#define NS_ERROR_MODULE_WIDGET 4
|
||||
#define NS_ERROR_MODULE_CALENDAR 5
|
||||
#define NS_ERROR_MODULE_NETWORK 6
|
||||
#define NS_ERROR_MODULE_PLUGINS 7
|
||||
#define NS_ERROR_MODULE_LAYOUT 8
|
||||
#define NS_ERROR_MODULE_HTMLPARSER 9
|
||||
#define NS_ERROR_MODULE_RDF 10
|
||||
#define NS_ERROR_MODULE_UCONV 11
|
||||
#define NS_ERROR_MODULE_REG 12
|
||||
#define NS_ERROR_MODULE_FILES 13
|
||||
|
||||
#define NS_ERROR_MODULE_MAILNEWS 16
|
||||
|
||||
/**
|
||||
* @name Standard Error Handling Macros
|
||||
*/
|
||||
|
||||
#define NS_FAILED(_nsresult) ((_nsresult) & 0x80000000)
|
||||
#define NS_SUCCEEDED(_nsresult) (!((_nsresult) & 0x80000000))
|
||||
|
||||
/**
|
||||
* @name Severity Code. This flag identifies the level of warning
|
||||
*/
|
||||
|
||||
#define NS_ERROR_SEVERITY_SUCCESS 0
|
||||
#define NS_ERROR_SEVERITY_ERROR 1
|
||||
|
||||
/**
|
||||
* @name Mozilla Code. This flag separates consumers of mozilla code
|
||||
* from the native platform
|
||||
*/
|
||||
|
||||
#define NS_ERROR_MODULE_BASE_OFFSET 0x45
|
||||
|
||||
/**
|
||||
* @name Standard Error Generating Macros
|
||||
*/
|
||||
|
||||
#define NS_ERROR_GENERATE(sev,module,code) \
|
||||
((nsresult) (((PRUint32)(sev)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
|
||||
|
||||
#define NS_ERROR_GENERATE_SUCCESS(module,code) \
|
||||
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_SUCCESS)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
|
||||
|
||||
#define NS_ERROR_GENERATE_FAILURE(module,code) \
|
||||
((nsresult) (((PRUint32)(NS_ERROR_SEVERITY_ERROR)<<31) | ((PRUint32)(module+NS_ERROR_MODULE_BASE_OFFSET)<<16) | ((PRUint32)(code))) )
|
||||
|
||||
/**
|
||||
* @name Standard Macros for retrieving error bits
|
||||
*/
|
||||
|
||||
#if PR_BYTES_PER_INT == 4
|
||||
#define NS_IS_ERROR(err) (((nsresult)(err))<0)
|
||||
#else
|
||||
#define NS_IS_ERROR(err) (((((PRUint32)(err)) >> 31) & 0x1) == NS_ERROR_SEVERITY_ERROR)
|
||||
#endif
|
||||
|
||||
#define NS_ERROR_GET_CODE(err) ((err) & 0xffff)
|
||||
#define NS_ERROR_GET_MODULE(err) (((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff))
|
||||
#define NS_ERROR_GET_SEVERITY(err) (((err) >> 31) & 0x1)
|
||||
|
||||
/**
|
||||
* @name Standard return values
|
||||
*/
|
||||
|
||||
/*@{*/
|
||||
|
||||
/* Standard "it worked" return value */
|
||||
#define NS_OK 0
|
||||
|
||||
/* The backwards COM false */
|
||||
#define NS_COMFALSE 1
|
||||
|
||||
#define NS_ERROR_BASE ((nsresult) 0xC1F30000)
|
||||
|
||||
/* Returned when an instance is not initialized */
|
||||
#define NS_ERROR_NOT_INITIALIZED (NS_ERROR_BASE + 1)
|
||||
|
||||
/* Returned when an instance is already initialized */
|
||||
#define NS_ERROR_ALREADY_INITIALIZED (NS_ERROR_BASE + 2)
|
||||
|
||||
/* Returned by a not implemented function */
|
||||
#define NS_ERROR_NOT_IMPLEMENTED ((nsresult) 0x80004001L)
|
||||
|
||||
/* Returned when a given interface is not supported. */
|
||||
#define NS_NOINTERFACE ((nsresult) 0x80004002L)
|
||||
#define NS_ERROR_NO_INTERFACE NS_NOINTERFACE
|
||||
|
||||
#define NS_ERROR_INVALID_POINTER ((nsresult) 0x80004003L)
|
||||
#define NS_ERROR_NULL_POINTER NS_ERROR_INVALID_POINTER
|
||||
|
||||
/* Returned when a function aborts */
|
||||
#define NS_ERROR_ABORT ((nsresult) 0x80004004L)
|
||||
|
||||
/* Returned when a function fails */
|
||||
#define NS_ERROR_FAILURE ((nsresult) 0x80004005L)
|
||||
|
||||
/* Returned when an unexpected error occurs */
|
||||
#define NS_ERROR_UNEXPECTED ((nsresult) 0x8000ffffL)
|
||||
|
||||
/* Returned when a memory allocation failes */
|
||||
#define NS_ERROR_OUT_OF_MEMORY ((nsresult) 0x8007000eL)
|
||||
|
||||
/* Returned when an illegal value is passed */
|
||||
#define NS_ERROR_ILLEGAL_VALUE ((nsresult) 0x80070057L)
|
||||
#define NS_ERROR_INVALID_ARG NS_ERROR_ILLEGAL_VALUE
|
||||
|
||||
/* Returned when a class doesn't allow aggregation */
|
||||
#define NS_ERROR_NO_AGGREGATION ((nsresult) 0x80040110L)
|
||||
|
||||
/* Returned when a class doesn't allow aggregation */
|
||||
#define NS_ERROR_NOT_AVAILABLE ((nsresult) 0x80040111L)
|
||||
|
||||
/* Returned when a class is not registered */
|
||||
#define NS_ERROR_FACTORY_NOT_REGISTERED ((nsresult) 0x80040154L)
|
||||
|
||||
/* Returned when a dynamically loaded factory couldn't be found */
|
||||
#define NS_ERROR_FACTORY_NOT_LOADED ((nsresult) 0x800401f8L)
|
||||
|
||||
/* Returned when a factory doesn't support signatures */
|
||||
#define NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT \
|
||||
(NS_ERROR_BASE + 0x101)
|
||||
|
||||
/* Returned when a factory already is registered */
|
||||
#define NS_ERROR_FACTORY_EXISTS (NS_ERROR_BASE + 0x100)
|
||||
|
||||
/*@}*/
|
||||
#endif
|
||||
|
||||
82
mozilla/xpcom/base/nsIAllocator.h
Normal file
82
mozilla/xpcom/base/nsIAllocator.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* -*- 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 nsIAllocator_h___
|
||||
#define nsIAllocator_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
/**
|
||||
* Unlike IMalloc, this interface returns nsresults and doesn't
|
||||
* implement the problematic GetSize and DidAlloc routines.
|
||||
*/
|
||||
|
||||
class nsIAllocator : public nsISupports {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Allocates a block of memory of a particular size.
|
||||
*
|
||||
* @param size - the size of the block to allocate
|
||||
* @result the block of memory
|
||||
*/
|
||||
NS_IMETHOD_(void*) Alloc(PRUint32 size) = 0;
|
||||
|
||||
/**
|
||||
* Reallocates a block of memory to a new size.
|
||||
*
|
||||
* @param ptr - the block of memory to reallocate
|
||||
* @param size - the new size
|
||||
* @result the rellocated block of memory
|
||||
*/
|
||||
NS_IMETHOD_(void*) Realloc(void* ptr, PRUint32 size) = 0;
|
||||
|
||||
/**
|
||||
* Frees a block of memory.
|
||||
*
|
||||
* @param ptr - the block of memory to free
|
||||
*/
|
||||
NS_IMETHOD Free(void* ptr) = 0;
|
||||
|
||||
/**
|
||||
* Attempts to shrink the heap.
|
||||
*/
|
||||
NS_IMETHOD HeapMinimize(void) = 0;
|
||||
|
||||
};
|
||||
|
||||
#define NS_IALLOCATOR_IID \
|
||||
{ /* 56def700-b1b9-11d2-8177-006008119d7a */ \
|
||||
0x56def700, \
|
||||
0xb1b9, \
|
||||
0x11d2, \
|
||||
{0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
// To get the global memory manager service:
|
||||
#define NS_ALLOCATOR_CID \
|
||||
{ /* aafe6770-b1bb-11d2-8177-006008119d7a */ \
|
||||
0xaafe6770, \
|
||||
0xb1bb, \
|
||||
0x11d2, \
|
||||
{0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* nsIAllocator_h___ */
|
||||
73
mozilla/xpcom/base/nsID.cpp
Normal file
73
mozilla/xpcom/base/nsID.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "nsID.h"
|
||||
#include "prprf.h"
|
||||
|
||||
static const char gIDFormat[] =
|
||||
"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
|
||||
|
||||
static const char gIDFormat2[] =
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
|
||||
|
||||
/*
|
||||
* Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} string into
|
||||
* an nsID
|
||||
*/
|
||||
|
||||
NS_COM PRBool nsID::Parse(char *aIDStr)
|
||||
{
|
||||
PRInt32 count = 0;
|
||||
PRInt32 n1, n2, n3[8];
|
||||
PRInt32 n0;
|
||||
|
||||
if (NULL != aIDStr) {
|
||||
count = PR_sscanf(aIDStr,
|
||||
(aIDStr[0] == '{') ? gIDFormat : gIDFormat2,
|
||||
&n0, &n1, &n2,
|
||||
&n3[0],&n3[1],&n3[2],&n3[3],
|
||||
&n3[4],&n3[5],&n3[6],&n3[7]);
|
||||
|
||||
m0 = (PRInt32) n0;
|
||||
m1 = (PRInt16) n1;
|
||||
m2 = (PRInt16) n2;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
m3[i] = (PRInt8) n3[i];
|
||||
}
|
||||
}
|
||||
return (PRBool) (count == 11);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an allocated string in {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
* format. Caller should delete [] the string.
|
||||
*/
|
||||
|
||||
NS_COM char *nsID::ToString() const
|
||||
{
|
||||
char *res = new char[39];
|
||||
|
||||
if (res != NULL) {
|
||||
PR_snprintf(res, 39, gIDFormat,
|
||||
m0, (PRUint32) m1, (PRUint32) m2,
|
||||
(PRUint32) m3[0], (PRUint32) m3[1], (PRUint32) m3[2],
|
||||
(PRUint32) m3[3], (PRUint32) m3[4], (PRUint32) m3[5],
|
||||
(PRUint32) m3[6], (PRUint32) m3[7]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
89
mozilla/xpcom/base/nsID.h
Normal file
89
mozilla/xpcom/base/nsID.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsID_h__
|
||||
#define nsID_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "string.h"
|
||||
#include "nsCom.h"
|
||||
|
||||
/**
|
||||
* A "unique identifier". This is modeled after OSF DCE UUIDs.
|
||||
*/
|
||||
|
||||
struct nsID {
|
||||
/**
|
||||
* @name Indentifier values
|
||||
*/
|
||||
|
||||
//@{
|
||||
PRUint32 m0;
|
||||
PRUint16 m1;
|
||||
PRUint16 m2;
|
||||
PRUint8 m3[8];
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @name Methods
|
||||
*/
|
||||
|
||||
//@{
|
||||
/**
|
||||
* Equivalency method. Compares this nsID with another.
|
||||
* @return <b>PR_TRUE</b> if they are the same, <b>PR_FALSE</b> if not.
|
||||
*/
|
||||
|
||||
inline PRBool Equals(const nsID& other) const {
|
||||
return (PRBool)
|
||||
((((PRUint32*) &m0)[0] == ((PRUint32*) &other.m0)[0]) &&
|
||||
(((PRUint32*) &m0)[1] == ((PRUint32*) &other.m0)[1]) &&
|
||||
(((PRUint32*) &m0)[2] == ((PRUint32*) &other.m0)[2]) &&
|
||||
(((PRUint32*) &m0)[3] == ((PRUint32*) &other.m0)[3]));
|
||||
}
|
||||
|
||||
/**
|
||||
* nsID Parsing method. Turns a {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
* string into an nsID
|
||||
*/
|
||||
NS_COM PRBool Parse(char *aIDStr);
|
||||
|
||||
/**
|
||||
* nsID string encoder. Returns an allocated string in
|
||||
* {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} format. Caller should free string.
|
||||
*/
|
||||
NS_COM char* ToString() const;
|
||||
//@}
|
||||
};
|
||||
|
||||
/**
|
||||
* Declare an ID. If NS_IMPL_IDS is set, a variable <i>_name</i> is declared
|
||||
* with the given values, otherwise <i>_name</i> is declared as an
|
||||
* <tt>extern</tt> variable.
|
||||
*/
|
||||
|
||||
#ifdef NS_IMPL_IDS
|
||||
#define NS_DECLARE_ID(_name,m0,m1,m2,m30,m31,m32,m33,m34,m35,m36,m37) \
|
||||
extern "C" const nsID _name = {m0,m1,m2,{m30,m31,m32,m33,m34,m35,m36,m37}}
|
||||
#else
|
||||
#define NS_DECLARE_ID(_name,m0,m1,m2,m30,m31,m32,m33,m34,m35,m36,m37) \
|
||||
extern "C" const nsID _name
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
142
mozilla/xpcom/base/nsIPtr.h
Normal file
142
mozilla/xpcom/base/nsIPtr.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsIPtr_h___
|
||||
#define nsIPtr_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
/*
|
||||
* nsIPtr is an "auto-release pointer" class for nsISupports based interfaces
|
||||
*
|
||||
* It's intent is to be a "set and forget" pointer to help with managing
|
||||
* active references to nsISupports bases objects.
|
||||
*
|
||||
* The pointer object ensures that the underlying pointer is always
|
||||
* released whenever the value is changed or when the object leaves scope.
|
||||
*
|
||||
* Proper care needs to be taken when assigning pointers to a nsIPtr.
|
||||
* When asigning from a C pointer (nsISupports*), the pointer presumes
|
||||
* an active reference and subsumes it. When assigning from another nsIPtr,
|
||||
* a new reference is established.
|
||||
*
|
||||
* There are 3 ways to assign a value to a nsIPtr.
|
||||
* 1) Direct construction or assignment from a C pointer.
|
||||
* 2) Direct construction or assignment form another nsIPtr.
|
||||
* 3) Usage of an "out parameter" method.
|
||||
* a) AssignRef() releases the underlying pointer and returns a reference to it.
|
||||
* Useful for pointer reference out paramaters.
|
||||
* b) AssignPtr() releases the underlying pointer and returns a pointer to it.
|
||||
* c) Query() releases the underlying pointer and returns a (void**) pointer to it.
|
||||
* Useful for calls to QueryInterface()
|
||||
* 4) The SetAddRef() method. This is equivalent to an assignment followed by an AddRef().
|
||||
*
|
||||
* examples:
|
||||
*
|
||||
* class It {
|
||||
* void NS_NewFoo(nsIFoo** aFoo);
|
||||
* nsIFoo* GetFoo(void);
|
||||
* void GetBar(nsIBar*& aBar);
|
||||
* };
|
||||
*
|
||||
* nsIFooPtr foo = it->GetFoo();
|
||||
* nsIBarPtr bar;
|
||||
*
|
||||
* it->NS_NewFoo(foo.AssignPtr());
|
||||
* it->GetBar(bar.AssignRef());
|
||||
* it->QueryInterface(kIFooIID, foo.Query());
|
||||
* bar.SetAddRef(new Bar());
|
||||
*
|
||||
* Advantages:
|
||||
* Set and forget. Once a pointer is assigned to a nsIPtr, it is impossible
|
||||
* to forget to release it.
|
||||
* Always pre-initialized. You can't forget to initialize the pointer.
|
||||
*
|
||||
* Disadvantages:
|
||||
* Usage of this class doesn't eliminate the need to think about ref counts
|
||||
* and assign values properly, AddRef'ing as needed.
|
||||
* The nsIPtr doesn't typecast exactly like a C pointer. In order to achieve
|
||||
* typecasting, it may be necessary to first cast to a C pointer of the
|
||||
* underlying type.
|
||||
*
|
||||
*/
|
||||
|
||||
#define NS_DEF_PTR(cls) \
|
||||
class cls##Ptr { \
|
||||
public: \
|
||||
cls##Ptr(void) : mPtr(0) {} \
|
||||
cls##Ptr(const cls##Ptr& aCopy) : mPtr(aCopy.mPtr) \
|
||||
{ NS_IF_ADDREF(mPtr); } \
|
||||
cls##Ptr(cls* aInterface) : mPtr(aInterface) {} \
|
||||
~cls##Ptr(void) { NS_IF_RELEASE(mPtr); } \
|
||||
cls##Ptr& operator=(const cls##Ptr& aCopy) \
|
||||
{ if(mPtr == aCopy.mPtr) return *this; \
|
||||
NS_IF_ADDREF(aCopy.mPtr); \
|
||||
NS_IF_RELEASE(mPtr); \
|
||||
mPtr = aCopy.mPtr; return *this; } \
|
||||
cls##Ptr& operator=(cls* aInterface) \
|
||||
{ if(mPtr == aInterface) return *this; \
|
||||
NS_IF_RELEASE(mPtr); mPtr = aInterface; \
|
||||
return *this; } \
|
||||
cls##Ptr& operator=(PRInt32 aInt) \
|
||||
{ NS_IF_RELEASE(mPtr); \
|
||||
return *this; } \
|
||||
void SetAddRef(cls* aInterface) \
|
||||
{ if(aInterface == mPtr) return; \
|
||||
NS_IF_ADDREF(aInterface); \
|
||||
NS_IF_RELEASE(mPtr); mPtr = aInterface; } \
|
||||
cls* AddRef(void) { NS_ADDREF(mPtr); return mPtr; } \
|
||||
cls* IfAddRef(void) \
|
||||
{ NS_IF_ADDREF(mPtr); return mPtr; } \
|
||||
cls*& AssignRef(void) \
|
||||
{ NS_IF_RELEASE(mPtr); return mPtr; } \
|
||||
cls** AssignPtr(void) \
|
||||
{ NS_IF_RELEASE(mPtr); return &mPtr; } \
|
||||
void** Query(void) \
|
||||
{ NS_IF_RELEASE(mPtr); return (void**)&mPtr; } \
|
||||
PRBool IsNull() const \
|
||||
{ return PRBool(0 == mPtr); } \
|
||||
PRBool IsNotNull() const \
|
||||
{ return PRBool(0 != mPtr); } \
|
||||
PRBool operator==(const cls##Ptr& aCopy) const \
|
||||
{ return PRBool(mPtr == aCopy.mPtr); } \
|
||||
PRBool operator==(cls* aInterface) const \
|
||||
{ return PRBool(mPtr == aInterface); } \
|
||||
PRBool operator!=(const cls##Ptr& aCopy) const \
|
||||
{ return PRBool(mPtr != aCopy.mPtr); } \
|
||||
PRBool operator!=(cls* aInterface) const \
|
||||
{ return PRBool(mPtr != aInterface); } \
|
||||
cls* operator->(void) { return mPtr; } \
|
||||
cls& operator*(void) { return *mPtr; } \
|
||||
operator cls*(void) { return mPtr; } \
|
||||
const cls* operator->(void) const { return mPtr; } \
|
||||
const cls& operator*(void) const { return *mPtr; } \
|
||||
operator const cls* (void) const { return mPtr; } \
|
||||
private: \
|
||||
void* operator new(size_t size) { return 0; } \
|
||||
void operator delete(void* aPtr) {} \
|
||||
cls* mPtr; \
|
||||
public: \
|
||||
friend inline PRBool operator==(const cls* aInterface, const cls##Ptr& aPtr) \
|
||||
{ return PRBool(aInterface == aPtr.mPtr); } \
|
||||
friend inline PRBool operator!=(const cls* aInterface, const cls##Ptr& aPtr) \
|
||||
{ return PRBool(aInterface != aPtr.mPtr); } \
|
||||
}
|
||||
|
||||
#endif // nsIPtr_h___
|
||||
|
||||
314
mozilla/xpcom/base/nsTraceRefcnt.cpp
Normal file
314
mozilla/xpcom/base/nsTraceRefcnt.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsISupports.h"
|
||||
#include "prprf.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
static PRLogModuleInfo* gTraceRefcntLog;
|
||||
|
||||
#if defined(NS_MT_SUPPORTED)
|
||||
#include "prlock.h"
|
||||
|
||||
static PRLock* gTraceLock;
|
||||
|
||||
#define LOCK_TRACELOG() PR_Lock(gTraceLock)
|
||||
#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
|
||||
#else /* ! NT_MT_SUPPORTED */
|
||||
#define LOCK_TRACELOG()
|
||||
#define UNLOCK_TRACELOG()
|
||||
#endif /* ! NS_MT_SUPPORTED */
|
||||
|
||||
static void InitTraceLog(void)
|
||||
{
|
||||
if (0 == gTraceRefcntLog) {
|
||||
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
|
||||
|
||||
#if defined(NS_MT_SUPPORTED)
|
||||
gTraceLock = PR_NewLock();
|
||||
#endif /* NS_MT_SUPPORTED */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "imagehlp.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if 0
|
||||
static BOOL __stdcall
|
||||
EnumSymbolsCB(LPSTR aSymbolName,
|
||||
ULONG aSymbolAddress,
|
||||
ULONG aSymbolSize,
|
||||
PVOID aUserContext)
|
||||
{
|
||||
int* countp = (int*) aUserContext;
|
||||
int count = *countp;
|
||||
if (count < 3) {
|
||||
printf(" %p[%4d]: %s\n", aSymbolAddress, aSymbolSize, aSymbolName);
|
||||
count++;
|
||||
*countp = count++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL __stdcall
|
||||
EnumModulesCB(LPSTR aModuleName,
|
||||
ULONG aBaseOfDll,
|
||||
PVOID aUserContext)
|
||||
{
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
|
||||
printf("module=%s dll=%x\n", aModuleName, aBaseOfDll);
|
||||
// int count = 0;
|
||||
// SymEnumerateSymbols(myProcess, aBaseOfDll, EnumSymbolsCB, (void*) &count);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Walk the stack, translating PC's found into strings and recording the
|
||||
* chain in aBuffer. For this to work properly, the dll's must be rebased
|
||||
* so that the address in the file agrees with the address in memory.
|
||||
* Otherwise StackWalk will return FALSE when it hits a frame in a dll's
|
||||
* whose in memory address doesn't match it's in-file address.
|
||||
*
|
||||
* Fortunately, there is a handy dandy routine in IMAGEHLP.DLL that does
|
||||
* the rebasing and accordingly I've made a tool to use it to rebase the
|
||||
* DLL's in one fell swoop (see xpcom/tools/windows/rebasedlls.cpp).
|
||||
*/
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
||||
{
|
||||
CONTEXT context;
|
||||
STACKFRAME frame;
|
||||
char* cp = aBuffer;
|
||||
|
||||
aBuffer[0] = '\0';
|
||||
aBufLen--; // leave room for nul
|
||||
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
HANDLE myThread = ::GetCurrentThread();
|
||||
|
||||
// Get the context information for this thread. That way we will
|
||||
// know where our sp, fp, pc, etc. are and can fill in the
|
||||
// STACKFRAME with the initial values.
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
GetThreadContext(myThread, &context);
|
||||
|
||||
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
SymEnumerateModules(myProcess, EnumModulesCB, NULL);
|
||||
#endif
|
||||
|
||||
// Setup initial stack frame to walk from
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrReturn.Mode = AddrModeFlat;
|
||||
frame.AddrReturn.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.Params[0] = context.Eax;
|
||||
frame.Params[1] = context.Ecx;
|
||||
frame.Params[2] = context.Edx;
|
||||
frame.Params[3] = context.Ebx;
|
||||
|
||||
// Now walk the stack and map the pc's to symbol names that we stuff
|
||||
// append to *cp.
|
||||
|
||||
int skip = 2;
|
||||
int syms = 0;
|
||||
while (aBufLen > 0) {
|
||||
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 512];
|
||||
PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) symbolBuffer;
|
||||
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
|
||||
pSymbol->MaxNameLength = 512;
|
||||
|
||||
DWORD oldAddress = frame.AddrPC.Offset;
|
||||
BOOL b = ::StackWalk(IMAGE_FILE_MACHINE_I386, myProcess, myThread,
|
||||
&frame, &context, NULL,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
NULL);
|
||||
if (!b || (0 == frame.AddrPC.Offset)) {
|
||||
if (syms <= 1) {
|
||||
skip = 7;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (--skip >= 0) {
|
||||
continue;
|
||||
}
|
||||
DWORD disp;
|
||||
if (SymGetSymFromAddr(myProcess, frame.AddrPC.Offset, &disp, pSymbol)) {
|
||||
int nameLen = strlen(pSymbol->Name);
|
||||
if (nameLen + 2 > aBufLen) {
|
||||
break;
|
||||
}
|
||||
memcpy(cp, pSymbol->Name, nameLen);
|
||||
cp += nameLen;
|
||||
*cp++ = ' ';
|
||||
aBufLen -= nameLen + 1;
|
||||
syms++;
|
||||
}
|
||||
else {
|
||||
if (11 > aBufLen) {
|
||||
break;
|
||||
}
|
||||
char tmp[30];
|
||||
PR_snprintf(tmp, sizeof(tmp), "0x%08x ", frame.AddrPC.Offset);
|
||||
memcpy(cp, tmp, 11);
|
||||
cp += 11;
|
||||
aBufLen -= 11;
|
||||
syms++;
|
||||
}
|
||||
}
|
||||
*cp = 0;
|
||||
}
|
||||
|
||||
#else /* _WIN32 */
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
||||
{
|
||||
aBuffer[0] = '\0';
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
NS_COM void
|
||||
nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
||||
void* aLibrayHandle)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#if defined(_WIN32)
|
||||
InitTraceLog();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
|
||||
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL b = ::SymLoadModule(myProcess,
|
||||
NULL,
|
||||
(char*)aLibraryName,
|
||||
(char*)aLibraryName,
|
||||
0,
|
||||
0);
|
||||
// DWORD lastError = 0;
|
||||
// if (!b) lastError = ::GetLastError();
|
||||
// printf("loading symbols for library %s => %s [%d]\n", aLibraryName,
|
||||
// b ? "true" : "false", lastError);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_COM unsigned long
|
||||
nsTraceRefcnt::AddRef(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("AddRef: %p: %d=>%d [%s] in %s (line %d)",
|
||||
aPtr, aNewRefcnt-1, aNewRefcnt, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
return aNewRefcnt;
|
||||
|
||||
}
|
||||
|
||||
NS_COM unsigned long
|
||||
nsTraceRefcnt::Release(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("Release: %p: %d=>%d [%s] in %s (line %d)",
|
||||
aPtr, aNewRefcnt+1, aNewRefcnt, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
return aNewRefcnt;
|
||||
}
|
||||
|
||||
NS_COM void
|
||||
nsTraceRefcnt::Create(void* aPtr,
|
||||
const char* aType,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("Create: %p[%s]: [%s] in %s (line %d)",
|
||||
aPtr, aType, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_COM void
|
||||
nsTraceRefcnt::Destroy(void* aPtr,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("Destroy: %p: [%s] in %s (line %d)",
|
||||
aPtr, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
}
|
||||
61
mozilla/xpcom/base/nsTraceRefcnt.h
Normal file
61
mozilla/xpcom/base/nsTraceRefcnt.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#ifndef nsTraceRefcnt_h___
|
||||
#define nsTraceRefcnt_h___
|
||||
|
||||
#include "nsCom.h"
|
||||
|
||||
/**
|
||||
* This class is used to support tracing (and logging using nspr) of
|
||||
* addref and release calls. Note that only calls that use the
|
||||
* NS_ADDREF and related macros in nsISupports can be traced.
|
||||
*
|
||||
* The name of the nspr log module is "xpcomrefcnt" (case matters).
|
||||
*
|
||||
* This code only performs tracing built with debugging AND when
|
||||
* built with -DMOZ_TRACE_XPCOM_REFCNT (because it's expensive!).
|
||||
*/
|
||||
class nsTraceRefcnt {
|
||||
public:
|
||||
static NS_COM unsigned long AddRef(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM unsigned long Release(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM void Create(void* aPtr,
|
||||
const char* aType,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM void Destroy(void* aPtr,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM void LoadLibrarySymbols(const char* aLibraryName,
|
||||
void* aLibrayHandle);
|
||||
|
||||
static NS_COM void WalkTheStack(char* aBuffer, int aBufLen);
|
||||
};
|
||||
|
||||
#endif /* nsTraceRefcnt_h___ */
|
||||
314
mozilla/xpcom/base/nsTraceRefcntImpl.cpp
Normal file
314
mozilla/xpcom/base/nsTraceRefcntImpl.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#include "nsISupports.h"
|
||||
#include "prprf.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
static PRLogModuleInfo* gTraceRefcntLog;
|
||||
|
||||
#if defined(NS_MT_SUPPORTED)
|
||||
#include "prlock.h"
|
||||
|
||||
static PRLock* gTraceLock;
|
||||
|
||||
#define LOCK_TRACELOG() PR_Lock(gTraceLock)
|
||||
#define UNLOCK_TRACELOG() PR_Unlock(gTraceLock)
|
||||
#else /* ! NT_MT_SUPPORTED */
|
||||
#define LOCK_TRACELOG()
|
||||
#define UNLOCK_TRACELOG()
|
||||
#endif /* ! NS_MT_SUPPORTED */
|
||||
|
||||
static void InitTraceLog(void)
|
||||
{
|
||||
if (0 == gTraceRefcntLog) {
|
||||
gTraceRefcntLog = PR_NewLogModule("xpcomrefcnt");
|
||||
|
||||
#if defined(NS_MT_SUPPORTED)
|
||||
gTraceLock = PR_NewLock();
|
||||
#endif /* NS_MT_SUPPORTED */
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "imagehlp.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if 0
|
||||
static BOOL __stdcall
|
||||
EnumSymbolsCB(LPSTR aSymbolName,
|
||||
ULONG aSymbolAddress,
|
||||
ULONG aSymbolSize,
|
||||
PVOID aUserContext)
|
||||
{
|
||||
int* countp = (int*) aUserContext;
|
||||
int count = *countp;
|
||||
if (count < 3) {
|
||||
printf(" %p[%4d]: %s\n", aSymbolAddress, aSymbolSize, aSymbolName);
|
||||
count++;
|
||||
*countp = count++;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL __stdcall
|
||||
EnumModulesCB(LPSTR aModuleName,
|
||||
ULONG aBaseOfDll,
|
||||
PVOID aUserContext)
|
||||
{
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
|
||||
printf("module=%s dll=%x\n", aModuleName, aBaseOfDll);
|
||||
// int count = 0;
|
||||
// SymEnumerateSymbols(myProcess, aBaseOfDll, EnumSymbolsCB, (void*) &count);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Walk the stack, translating PC's found into strings and recording the
|
||||
* chain in aBuffer. For this to work properly, the dll's must be rebased
|
||||
* so that the address in the file agrees with the address in memory.
|
||||
* Otherwise StackWalk will return FALSE when it hits a frame in a dll's
|
||||
* whose in memory address doesn't match it's in-file address.
|
||||
*
|
||||
* Fortunately, there is a handy dandy routine in IMAGEHLP.DLL that does
|
||||
* the rebasing and accordingly I've made a tool to use it to rebase the
|
||||
* DLL's in one fell swoop (see xpcom/tools/windows/rebasedlls.cpp).
|
||||
*/
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
||||
{
|
||||
CONTEXT context;
|
||||
STACKFRAME frame;
|
||||
char* cp = aBuffer;
|
||||
|
||||
aBuffer[0] = '\0';
|
||||
aBufLen--; // leave room for nul
|
||||
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
HANDLE myThread = ::GetCurrentThread();
|
||||
|
||||
// Get the context information for this thread. That way we will
|
||||
// know where our sp, fp, pc, etc. are and can fill in the
|
||||
// STACKFRAME with the initial values.
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
GetThreadContext(myThread, &context);
|
||||
|
||||
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
SymEnumerateModules(myProcess, EnumModulesCB, NULL);
|
||||
#endif
|
||||
|
||||
// Setup initial stack frame to walk from
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrReturn.Mode = AddrModeFlat;
|
||||
frame.AddrReturn.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.Params[0] = context.Eax;
|
||||
frame.Params[1] = context.Ecx;
|
||||
frame.Params[2] = context.Edx;
|
||||
frame.Params[3] = context.Ebx;
|
||||
|
||||
// Now walk the stack and map the pc's to symbol names that we stuff
|
||||
// append to *cp.
|
||||
|
||||
int skip = 2;
|
||||
int syms = 0;
|
||||
while (aBufLen > 0) {
|
||||
char symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 512];
|
||||
PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) symbolBuffer;
|
||||
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
|
||||
pSymbol->MaxNameLength = 512;
|
||||
|
||||
DWORD oldAddress = frame.AddrPC.Offset;
|
||||
BOOL b = ::StackWalk(IMAGE_FILE_MACHINE_I386, myProcess, myThread,
|
||||
&frame, &context, NULL,
|
||||
SymFunctionTableAccess,
|
||||
SymGetModuleBase,
|
||||
NULL);
|
||||
if (!b || (0 == frame.AddrPC.Offset)) {
|
||||
if (syms <= 1) {
|
||||
skip = 7;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (--skip >= 0) {
|
||||
continue;
|
||||
}
|
||||
DWORD disp;
|
||||
if (SymGetSymFromAddr(myProcess, frame.AddrPC.Offset, &disp, pSymbol)) {
|
||||
int nameLen = strlen(pSymbol->Name);
|
||||
if (nameLen + 2 > aBufLen) {
|
||||
break;
|
||||
}
|
||||
memcpy(cp, pSymbol->Name, nameLen);
|
||||
cp += nameLen;
|
||||
*cp++ = ' ';
|
||||
aBufLen -= nameLen + 1;
|
||||
syms++;
|
||||
}
|
||||
else {
|
||||
if (11 > aBufLen) {
|
||||
break;
|
||||
}
|
||||
char tmp[30];
|
||||
PR_snprintf(tmp, sizeof(tmp), "0x%08x ", frame.AddrPC.Offset);
|
||||
memcpy(cp, tmp, 11);
|
||||
cp += 11;
|
||||
aBufLen -= 11;
|
||||
syms++;
|
||||
}
|
||||
}
|
||||
*cp = 0;
|
||||
}
|
||||
|
||||
#else /* _WIN32 */
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
||||
{
|
||||
aBuffer[0] = '\0';
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
|
||||
NS_COM void
|
||||
nsTraceRefcnt::LoadLibrarySymbols(const char* aLibraryName,
|
||||
void* aLibrayHandle)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#if defined(_WIN32)
|
||||
InitTraceLog();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
HANDLE myProcess = ::GetCurrentProcess();
|
||||
|
||||
if (!SymInitialize(myProcess, ".;..\\lib", TRUE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL b = ::SymLoadModule(myProcess,
|
||||
NULL,
|
||||
(char*)aLibraryName,
|
||||
(char*)aLibraryName,
|
||||
0,
|
||||
0);
|
||||
// DWORD lastError = 0;
|
||||
// if (!b) lastError = ::GetLastError();
|
||||
// printf("loading symbols for library %s => %s [%d]\n", aLibraryName,
|
||||
// b ? "true" : "false", lastError);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_COM unsigned long
|
||||
nsTraceRefcnt::AddRef(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("AddRef: %p: %d=>%d [%s] in %s (line %d)",
|
||||
aPtr, aNewRefcnt-1, aNewRefcnt, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
return aNewRefcnt;
|
||||
|
||||
}
|
||||
|
||||
NS_COM unsigned long
|
||||
nsTraceRefcnt::Release(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("Release: %p: %d=>%d [%s] in %s (line %d)",
|
||||
aPtr, aNewRefcnt+1, aNewRefcnt, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
return aNewRefcnt;
|
||||
}
|
||||
|
||||
NS_COM void
|
||||
nsTraceRefcnt::Create(void* aPtr,
|
||||
const char* aType,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("Create: %p[%s]: [%s] in %s (line %d)",
|
||||
aPtr, aType, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_COM void
|
||||
nsTraceRefcnt::Destroy(void* aPtr,
|
||||
const char* aFile,
|
||||
PRIntn aLine)
|
||||
{
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
InitTraceLog();
|
||||
|
||||
LOCK_TRACELOG();
|
||||
if (PR_LOG_TEST(gTraceRefcntLog,PR_LOG_DEBUG)) {
|
||||
char sb[1000];
|
||||
WalkTheStack(sb, sizeof(sb));
|
||||
PR_LOG(gTraceRefcntLog, PR_LOG_DEBUG,
|
||||
("Destroy: %p: [%s] in %s (line %d)",
|
||||
aPtr, sb, aFile, aLine));
|
||||
}
|
||||
UNLOCK_TRACELOG();
|
||||
#endif
|
||||
}
|
||||
61
mozilla/xpcom/base/nsTraceRefcntImpl.h
Normal file
61
mozilla/xpcom/base/nsTraceRefcntImpl.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
#ifndef nsTraceRefcnt_h___
|
||||
#define nsTraceRefcnt_h___
|
||||
|
||||
#include "nsCom.h"
|
||||
|
||||
/**
|
||||
* This class is used to support tracing (and logging using nspr) of
|
||||
* addref and release calls. Note that only calls that use the
|
||||
* NS_ADDREF and related macros in nsISupports can be traced.
|
||||
*
|
||||
* The name of the nspr log module is "xpcomrefcnt" (case matters).
|
||||
*
|
||||
* This code only performs tracing built with debugging AND when
|
||||
* built with -DMOZ_TRACE_XPCOM_REFCNT (because it's expensive!).
|
||||
*/
|
||||
class nsTraceRefcnt {
|
||||
public:
|
||||
static NS_COM unsigned long AddRef(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM unsigned long Release(void* aPtr,
|
||||
unsigned long aNewRefcnt,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM void Create(void* aPtr,
|
||||
const char* aType,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM void Destroy(void* aPtr,
|
||||
const char* aFile,
|
||||
int aLine);
|
||||
|
||||
static NS_COM void LoadLibrarySymbols(const char* aLibraryName,
|
||||
void* aLibrayHandle);
|
||||
|
||||
static NS_COM void WalkTheStack(char* aBuffer, int aBufLen);
|
||||
};
|
||||
|
||||
#endif /* nsTraceRefcnt_h___ */
|
||||
168
mozilla/xpcom/components/mozIClassRegistry.h
Normal file
168
mozilla/xpcom/components/mozIClassRegistry.h
Normal file
@@ -0,0 +1,168 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 __mozIClassRegistry_h
|
||||
#define __mozIClassRegistry_h
|
||||
|
||||
#include "nsRepository.h"
|
||||
|
||||
/*---------------------------- mozIClassRegistry -------------------------------
|
||||
| This interface provides access to a mapping from mnemonic interface names |
|
||||
| to shared libraries where implementations of those interfaces can be located.|
|
||||
| |
|
||||
| This interface is designed to provide two things: |
|
||||
| 1. A means of less static binding between clients and the code that |
|
||||
| implements the XPCOM interfaces those clients use. This accomplished |
|
||||
| by the mapping from interface names to nsCID (and the shared libraries |
|
||||
| that implement those classes). |
|
||||
| 2. A means of dynamically changing the mapping from interface name to |
|
||||
| implementation. The canonical example of this is to switch to a |
|
||||
| "native" widget set versus an "XP" (implemented using gfx) set. |
|
||||
| |
|
||||
| The first goal is achieved by storing (in a "Netscape Registry" file, see |
|
||||
| nsReg.h) information that maps interface/class "names" to information about |
|
||||
| where to load implementations of those interfaces. That information |
|
||||
| includes the interface ID, class ID (of the implementation class), and the |
|
||||
| name of the shared library that contains the implementation. |
|
||||
| |
|
||||
| The class registry object will register those classes with the "repository" |
|
||||
| (see nsRepository.h) the first time a request is made to create an |
|
||||
| instance. Subsequent requests will simply be forwarded to the repository |
|
||||
| after the appropriate interface and class IDs are determined. |
|
||||
| |
|
||||
| The second goal is accomplished by permitting the mnemonic interface |
|
||||
| "names" to be "overloaded", that is, mapped to distinct implementations |
|
||||
| by separate class registry objects. Further, class registries can be |
|
||||
| cascaded: they can be chained together so that when a name is not |
|
||||
| recognized by one registry, it can pass the request to the next registry in |
|
||||
| the chain. Users can control resolution by making the request of a |
|
||||
| registry further up/down the chain. |
|
||||
| |
|
||||
| For example, consider the case of "native" vs. "gfx" widgets. This might |
|
||||
| be structured by a class registry arrangment like this: |
|
||||
| |
|
||||
| nativeWidgetRegistry baseWidgetRegistry |
|
||||
| +----------+ +----------+ |
|
||||
| | ----+---------------->| | |
|
||||
| +----------+ +----------+ |
|
||||
| |toolbar| -+-----+ |toolbar| -+-----+ |
|
||||
| +----------+ | +----------+ | |
|
||||
| |button | -+-----+ |button | -+-----+ |
|
||||
| +----------+ | +----------+ | |
|
||||
| V V |
|
||||
| +-----------------+ +-----------------+ |
|
||||
| | native.dll | | base.dll | |
|
||||
| +-----------------+ +-----------------+ |
|
||||
| |
|
||||
| If a specialized implementation of widgets is present (e.g., native.dll) |
|
||||
| then a corresponding class registry object is created and added to the |
|
||||
| head of the registry chain. Object creation requests (normal ones) are |
|
||||
| resolved to the native implementation. If such a library is not present, |
|
||||
| then the resolution is to the base implementation. If objects of the |
|
||||
| base implementation are required, then creation requests can be directed |
|
||||
| directly to the baseWidgetRegistry object, rather than the head of the |
|
||||
| registry chain. |
|
||||
| |
|
||||
| It is intended that there be a single instance of this interface, accessed |
|
||||
| via the Service Manager (see nsServiceManager.h). |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct mozIClassRegistry : public ISupports {
|
||||
|
||||
/*------------------------------ CreateInstance ----------------------------
|
||||
| Create an instance of the requested class/interface. The interface |
|
||||
| ID is required to specify how the result will be treated. The class |
|
||||
| named by aName must support this interface. The result is placed in |
|
||||
| ncomment aResult (NULL if the request fails). "start" specifies the |
|
||||
| registry at which the search for an implementation of the named |
|
||||
| interface should start. It defaults to 0 (indicating to start at the |
|
||||
| head of the registry chain). |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD CreateInstance( const char *anInterfaceName,
|
||||
const nsIID &aIID,
|
||||
void* *aResult,
|
||||
const char *start = 0 ) = 0;
|
||||
|
||||
/*--------------------------- CreateEnumerator -----------------------------
|
||||
| Creates an nsIEnumerator interface object that can be used to examine |
|
||||
| the contents of the registry. "pattern" specifies either "*" or the |
|
||||
| name of a specific interface that you want to query. "result" will |
|
||||
| be set to point to a new object (which will be freed on the last call |
|
||||
| to its Release() member). See nsIEnumerator.h for details on how to |
|
||||
| use the returned interface pointer. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD CreateEnumerator( const char *pattern,
|
||||
nsIEnumerator* *result ) = 0;
|
||||
}; // mozIClassRegistry
|
||||
|
||||
|
||||
/*-------------------------- mozIClassRegistryEntry ----------------------------
|
||||
| Objects of this class represent the individual elements that comprise a |
|
||||
| mozIClassRegistry interface. You obtain such objects by applying the |
|
||||
| CreateEnumerator member function to the class registry and then applying |
|
||||
| the CurrentItem member function to the resulting nsIEnumerator interface. |
|
||||
| |
|
||||
| Each entry can be queried for the following information: |
|
||||
| o sub-registry name |
|
||||
| o interface name |
|
||||
| o Class ID |
|
||||
| o IIDs implemented |
|
||||
| |
|
||||
| The information obtained from the entry (specifically, the const char* |
|
||||
| strings) remains valid for the life of the entry (i.e., until you |
|
||||
| Release() it). |
|
||||
| |
|
||||
| Here is an example of code that uses this interface to dump the contents |
|
||||
| of a mozIClassRegistry: |
|
||||
| |
|
||||
| mozIClassRegistry *reg = nsServiceManager::GetService( kIDRegistry ); |
|
||||
| nsIEnumerator *enum; |
|
||||
| reg->CreateEnumerator( "*", &enum ); |
|
||||
| for ( enum->First(); !enum->IsDone(); enum->Next(); ) { |
|
||||
| mozIClassRegistryEntry *entry; |
|
||||
| enum->CurrentItem( &entry ); |
|
||||
| const char *subreg; |
|
||||
| const char *name; |
|
||||
| nsCID cid; |
|
||||
| int numIIDs; |
|
||||
| entry->GetSubRegistryName( &subreg ); |
|
||||
| entry->GetInterfaceName( &name ); |
|
||||
| entry->GetClassID( &cid ); |
|
||||
| entry->GetNumIIDs( &numIIDs ); |
|
||||
| cout << subreg << "/" << name << " = " << cid.ToString() << endl; |
|
||||
| for ( int i = 0; i < numIIDs; i++ ) { |
|
||||
| nsIID iid; |
|
||||
| entry->GetInterfaceID( i, &iid ); |
|
||||
| cout << "/tIID[" << i << "] = " << iid.ToString() << endl; |
|
||||
| } |
|
||||
| entry->Release(); |
|
||||
| } |
|
||||
| enum->Release(); |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct mozIClassRegistryEntry : public nsISupports {
|
||||
NS_IMETHOD GetSubRegistryName( const char **result ) = 0;
|
||||
NS_IMETHOD GetInterfaceName( const char **result ) = 0;
|
||||
NS_IMETHOD GetClassID( nsCID *result ) = 0;
|
||||
NS_IMETHOD GetNumIIDs( int *result ) = 0;
|
||||
NS_IMETHOD GetInterfaceID( int n, nsIID *result ) = 0;
|
||||
}; // mozIClassRegistryEntry
|
||||
|
||||
// {5D41A440-8E37-11d2-8059-00600811A9C3}
|
||||
#define MOZ_ICLASSREGISTRY_IID { 0x5d41a440, 0x8e37, 0x11d2, { 0x80, 0x59, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
// {D1B54831-AC07-11d2-805E-00600811A9C3}
|
||||
#define MOZ_ICLASSREGISTRYENTRY_IID { 0xd1b54831, 0xac07, 0x11d2, { 0x80, 0x5e, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
|
||||
#endif
|
||||
326
mozilla/xpcom/components/mozIRegistry.h
Normal file
326
mozilla/xpcom/components/mozIRegistry.h
Normal file
@@ -0,0 +1,326 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 __mozIRegistry_h
|
||||
#define __mozIRegistry_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsIEnumerator;
|
||||
|
||||
/*------------------------------- mozIRegistry ---------------------------------
|
||||
| This interface provides access to a tree of arbitrary values. |
|
||||
| |
|
||||
| Each node of the tree contains either a value or a subtree or both. |
|
||||
| |
|
||||
| The value at any of these leaf nodes can be any of these "primitive" types: |
|
||||
| o string (null terminated UTF string) |
|
||||
| o array of 32-bit integers |
|
||||
| o arbitrary array of bytes |
|
||||
| o file identifier |
|
||||
| Of course, since you can store an arbitrary array of bytes, you can put |
|
||||
| any data you like into a registry (although you have the burden of |
|
||||
| encoding/decoding your data in that case). |
|
||||
| |
|
||||
| Each branch of the tree is labelled with a string "key." The entire path |
|
||||
| from a given point of the tree to another point further down can be |
|
||||
| presented as a single string composed of each branch's label, concatenated |
|
||||
| to the next, with an intervening forward slash ('/'). The term "key" |
|
||||
| refers to both specific tree branch labels and to such concatenated paths. |
|
||||
| |
|
||||
| The branches from a given node must have unique labels. Distinct nodes can |
|
||||
| have branches with the same label. |
|
||||
| |
|
||||
| For example, here's a small registry tree: |
|
||||
| | |
|
||||
| /\ |
|
||||
| / \ |
|
||||
| / \ |
|
||||
| / \ |
|
||||
| "Classes" "Users" |
|
||||
| / \ |
|
||||
| / \ |
|
||||
| / ["joe"] |
|
||||
| / / \ |
|
||||
| | / \ |
|
||||
| /\ / \ |
|
||||
| / \ "joe" "bob" |
|
||||
| / \ / \ |
|
||||
| / \ |
|
||||
| "{xxxx-xx-1}" "{xxxx-xx-2}" ["c:/joe"] ["d:/Robert"] |
|
||||
| | | |
|
||||
| /\ /\ |
|
||||
| / \ / \ |
|
||||
| / \ / \ |
|
||||
| "Library" "Version" "Library" "Version" |
|
||||
| / \ / \ |
|
||||
| ["foo.dll"] 2 ["bar.dll"] 1 |
|
||||
| |
|
||||
| In this example, there are 2 keys under the root: "Classes" and "Users". |
|
||||
| The first denotes a subtree only (which has two subtrees, ...). The second |
|
||||
| denotes both a value ["joe"] and two subtrees labelled "joe" and "bob". |
|
||||
| The value at the node "/Users" is ["joe"], at "/Users/bob" is ["d:/Robert"]. |
|
||||
| The value at "/Classes/{xxxx-xx-1}/Version" is 2. |
|
||||
| |
|
||||
| The registry interface provides functions that let you navigate the tree |
|
||||
| and manipulate it's contents. |
|
||||
| |
|
||||
| Please note that the registry itself does not impose any structure or |
|
||||
| meaning on the contents of the tree. For example, the registry doesn't |
|
||||
| control whether the value at the key "/Users" is the label for the subtree |
|
||||
| with information about the last active user. That meaning is applied by |
|
||||
| the code that stores these values and uses them for that purpose. |
|
||||
| |
|
||||
| [Any resemblence between this example and actual contents of any actual |
|
||||
| registry is purely coincidental.] |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct mozIRegistry : public nsISupports {
|
||||
/*------------------------------ Constants ---------------------------------
|
||||
| The following enumerated types and values are used by the registry |
|
||||
| interface. |
|
||||
--------------------------------------------------------------------------*/
|
||||
typedef enum {
|
||||
String = 1,
|
||||
Int32,
|
||||
Bytes,
|
||||
File
|
||||
} DataType;
|
||||
|
||||
/*-------------------------------- Types -----------------------------------
|
||||
| The following data types are used by this interface. All are basically |
|
||||
| opaque types. You obtain objects of these types via certain member |
|
||||
| function calls and re-use them later (without having to know what they |
|
||||
| contain). |
|
||||
| |
|
||||
| Key - Placeholder to represent a particular node in a registry |
|
||||
| tree. There are 3 enumerated values that correspond to |
|
||||
| specific nodes: |
|
||||
| Common - Where most stuff goes. |
|
||||
| Users - Special subtree to hold info about |
|
||||
| "users"; if you don't know what goes |
|
||||
| here, don't mess with it. |
|
||||
| CurrentUser - Subtree under Users corresponding to |
|
||||
| whatever user is designed the "current" |
|
||||
| one; see note above. |
|
||||
| You can specify any of these enumerated values as "keys" |
|
||||
| on any member function that takes a mozRegistry::Key. |
|
||||
| ValueInfo - Structure describing a registry value. |
|
||||
--------------------------------------------------------------------------*/
|
||||
typedef uint32 Key;
|
||||
|
||||
enum { Users = 1, Common = 2, CurrentUser = 3 };
|
||||
|
||||
struct ValueInfo {
|
||||
DataType type;
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
/*--------------------------- Opening/Closing ------------------------------
|
||||
| These functions open the specified registry file (Open() with a non-null |
|
||||
| argument) or the default "standard" registry file (Open() with a null |
|
||||
| argument or OpenDefault()). |
|
||||
| |
|
||||
| Once opened, you can access the registry contents via the read/write |
|
||||
| or query functions. |
|
||||
| |
|
||||
| The registry file will be closed automatically when the registry object |
|
||||
| is destroyed. You can close the file prior to that by using the |
|
||||
| Close() function. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD Open( const char *regFile = 0 ) = 0;
|
||||
NS_IMETHOD OpenDefault() = 0;
|
||||
NS_IMETHOD Close() = 0;
|
||||
|
||||
/*----------------------- Reading/Writing Values ---------------------------
|
||||
| These functions read/write the registry values at a given node. |
|
||||
| |
|
||||
| All functions require you to specify where in the registry key to |
|
||||
| get/set the value. The location is specified using two components: |
|
||||
| o A "base key" indicating where to start from; this is a value of type |
|
||||
| mozIRegistry::Key. You use either one of the special "root" key |
|
||||
| values or a subkey obtained via some other member function call. |
|
||||
| o A "relative path," expressed as a sequence of subtree names |
|
||||
| separated by forward slashes. This path describes how to get from |
|
||||
| the base key to the node at which you want to store the data. This |
|
||||
| component can be a null pointer which means the value goes directly |
|
||||
| at the node denoted by the base key. |
|
||||
| |
|
||||
| When you request a value of a given type, the data stored at the |
|
||||
| specified node must be of the type requested. If not, an error results. |
|
||||
| |
|
||||
| GetString - Obtains a newly allocated copy of a string type value. The |
|
||||
| caller is obligated to free the returned string using |
|
||||
| PR_Free. |
|
||||
| SetString - Stores the argument string at the specified node. |
|
||||
| GetInt - Obtains an int32 value at the specified node. The result |
|
||||
| is returned into an int32 location you specify. |
|
||||
| SetInt - Stores a given int32 value at a node. |
|
||||
| GetBytes - Obtains a byte array value; this returns both an allocated |
|
||||
| array of bytes and a length (necessary because there may be |
|
||||
| embedded null bytes in the array). You must free the |
|
||||
| resulting array using PR_Free. |
|
||||
| SetBytes - Stores a given array of bytes; you specify the bytes via a |
|
||||
| pointer and a length. |
|
||||
| GetIntArray - Obtains the array of int32 values stored at a given node. |
|
||||
| The result is composed of two values: a pointer to an |
|
||||
| array of integer values (which must be freed using |
|
||||
| PR_Free) and the number of elements in that array. |
|
||||
| SetIntArray - Stores a set of int32 values at a given node. You must |
|
||||
| provide a pointer to the array and the number of entries. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD GetString( Key baseKey, const char *path, char **result ) = 0;
|
||||
NS_IMETHOD SetString( Key baseKey, const char *path, const char *value ) = 0;
|
||||
NS_IMETHOD GetInt( Key baseKey, const char *path, int32 *result ) = 0;
|
||||
NS_IMETHOD SetInt( Key baseKey, const char *path, int32 value ) = 0;
|
||||
NS_IMETHOD GetBytes( Key baseKey, const char *path, void **result, uint32 *len ) = 0;
|
||||
NS_IMETHOD SetBytes( Key baseKey, const char *path, void *value, uint32 len ) = 0;
|
||||
NS_IMETHOD GetIntArray( Key baseKey, const char *path, int32 **result, uint32 *len ) = 0;
|
||||
NS_IMETHOD SetIntArray( Key baseKey, const char *path, const int32 *value, uint32 len ) = 0;
|
||||
|
||||
/*------------------------------ Navigation --------------------------------
|
||||
| These functions let you navigate through the registry tree, querying |
|
||||
| its contents. |
|
||||
| |
|
||||
| As above, all these functions requires a starting tree location ("base |
|
||||
| key") specified as a mozIRegistry::Key. Some also require a path |
|
||||
| name to locate the registry node location relative to this base key. |
|
||||
| |
|
||||
| AddSubtree - Adds a new registry subtree at the specified |
|
||||
| location. Returns the resulting key in |
|
||||
| the location specified by the third argument |
|
||||
| (unless that pointer is 0). |
|
||||
| RemoveNode - Removes the specified registry subtree or |
|
||||
| value at the specified location. |
|
||||
| GetSubtree - Returns a mozIRegistry::Key that can be used |
|
||||
| to refer to the specified registry location. |
|
||||
| EnumerateSubtrees - Returns a nsIEnumerator object that you can |
|
||||
| use to enumerate all the subtrees descending |
|
||||
| from a specified location. You must free the |
|
||||
| enumerator via Release() when you're done with |
|
||||
| it. |
|
||||
| EnumerateAllSubtrees - Like EnumerateSubtrees, but will recursively |
|
||||
| enumerate lower-level subtrees, too. |
|
||||
| GetValueInfo - Returns a uint32 value that designates the type |
|
||||
| of data stored at this location in the registry; |
|
||||
| the possible values are defined by the enumerated |
|
||||
| type mozIRegistry::DataType. |
|
||||
| GetValueLength - Returns a uint32 value that indicates the length |
|
||||
| of this registry value; the length is the number |
|
||||
| of characters (for Strings), the number of bytes |
|
||||
| (for Bytes), or the number of int32 values (for |
|
||||
| Int32). |
|
||||
| EnumerateValues - Returns a nsIEnumerator that you can use to |
|
||||
| enumerate all the value nodes descending from |
|
||||
| a specified location. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD AddSubtree( Key baseKey, const char *path, Key *result ) = 0;
|
||||
NS_IMETHOD RemoveSubtree( Key baseKey, const char *path ) = 0;
|
||||
NS_IMETHOD GetSubtree( Key baseKey, const char *path, Key *result ) = 0;
|
||||
|
||||
NS_IMETHOD EnumerateSubtrees( Key baseKey, nsIEnumerator **result ) = 0;
|
||||
NS_IMETHOD EnumerateAllSubtrees( Key baseKey, nsIEnumerator **result ) = 0;
|
||||
|
||||
NS_IMETHOD GetValueType( Key baseKey, const char *path, uint32 *result ) = 0;
|
||||
NS_IMETHOD GetValueLength( Key baseKey, const char *path, uint32 *result ) = 0;
|
||||
|
||||
NS_IMETHOD EnumerateValues( Key baseKey, nsIEnumerator **result ) = 0;
|
||||
|
||||
/*------------------------------ User Name ---------------------------------
|
||||
| These functions manipulate the current "user name." This value controls |
|
||||
| the behavior of certain registry functions (namely, ?). |
|
||||
| |
|
||||
| GetCurrentUserName allocates a copy of the current user name (which the |
|
||||
| caller should free using PR_Free). |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD GetCurrentUserName( char **result ) = 0;
|
||||
NS_IMETHOD SetCurrentUserName( const char *name ) = 0;
|
||||
|
||||
/*------------------------------ Utilities ---------------------------------
|
||||
| Various utility functions: |
|
||||
| |
|
||||
| Pack() is used to compress the contents of an open registry file. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD Pack() = 0;
|
||||
|
||||
}; // mozIRegistry
|
||||
|
||||
/*----------------------------- mozIRegistryNode -------------------------------
|
||||
| This interface is implemented by all the objects obtained from the |
|
||||
| nsIEnumerators that mozIRegistry provides when you call either of the |
|
||||
| subtree enumeration functions EnumerateSubtrees or EnumerateAllSubtrees. |
|
||||
| |
|
||||
| You can call this function to get the name of this subtree. This is the |
|
||||
| relative path from the base key from which you got this interface. |
|
||||
| |
|
||||
| GetName - Returns the path name of this node; this is the relative path |
|
||||
| from the base key from which this subtree was obtained. The |
|
||||
| function allocates a copy of the name; the caller must free it |
|
||||
| using PR_Free. |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct mozIRegistryNode : public nsISupports {
|
||||
NS_IMETHOD GetName( char **result ) = 0;
|
||||
}; // mozIRegistryNode
|
||||
|
||||
/*----------------------------- mozIRegistryValue ------------------------------
|
||||
| This interface is implemented by the objects obtained from the |
|
||||
| nsIEnumerators that mozIRegistry provides when you call the |
|
||||
| EnumerateValues function. An object supporting this interface is |
|
||||
| returned when you call the CurrentItem() function on that enumerator. |
|
||||
| |
|
||||
| You use the member functions of this interface to obtain information |
|
||||
| about each registry value. |
|
||||
| |
|
||||
| GetName - Returns the path name of this node; this is the relative |
|
||||
| path\ from the base key from which this value was obtained. |
|
||||
| The function allocates a copy of the name; the caller must |
|
||||
| subsequently free it via PR_Free. |
|
||||
| GetValueType - Returns (into a location provided by the caller) the type |
|
||||
| of the value; the types are defined by the enumerated |
|
||||
| type mozIRegistry::DataType. |
|
||||
| GetValueLength - Returns a uint32 value that indicates the length |
|
||||
| of this registry value; the length is the number |
|
||||
| of characters (for Strings), the number of bytes |
|
||||
| (for Bytes), or the number of int32 values (for |
|
||||
| Int32). |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct mozIRegistryValue : public nsISupports {
|
||||
NS_IMETHOD GetName( char **result ) = 0;
|
||||
NS_IMETHOD GetValueType( uint32 *result ) = 0;
|
||||
NS_IMETHOD GetValueLength( uint32 *result ) = 0;
|
||||
}; // mozIRegistryEntry
|
||||
|
||||
|
||||
/*------------------------------- Error Codes ----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
#define NS_ERROR_REG_BADTYPE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 1 )
|
||||
#define NS_ERROR_REG_NO_MORE NS_ERROR_GENERATE_SUCCESS( NS_ERROR_MODULE_REG, 2 )
|
||||
#define NS_ERROR_REG_NOT_FOUND NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 3 )
|
||||
#define NS_ERROR_REG_NOFILE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 4 )
|
||||
#define NS_ERROR_REG_BUFFER_TOO_SMALL NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 5 )
|
||||
#define NS_ERROR_REG_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 6 )
|
||||
#define NS_ERROR_REG_NO_PATH NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 7 )
|
||||
#define NS_ERROR_REG_READ_ONLY NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 8 )
|
||||
#define NS_ERROR_REG_BAD_UTF8 NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 9 )
|
||||
|
||||
// {5D41A440-8E37-11d2-8059-00600811A9C3}
|
||||
#define MOZ_IREGISTRY_IID { 0x5d41a440, 0x8e37, 0x11d2, { 0x80, 0x59, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
// {D1B54831-AC07-11d2-805E-00600811A9C3}
|
||||
#define MOZ_IREGISTRYNODE_IID { 0xd1b54831, 0xac07, 0x11d2, { 0x80, 0x5e, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
// {5316C380-B2F8-11d2-A374-0080C6F80E4B}
|
||||
#define MOZ_IREGISTRYVALUE_IID { 0x5316c380, 0xb2f8, 0x11d2, { 0xa3, 0x74, 0x0, 0x80, 0xc6, 0xf8, 0xe, 0x4b } }
|
||||
|
||||
#endif
|
||||
1204
mozilla/xpcom/components/mozRegistry.cpp
Normal file
1204
mozilla/xpcom/components/mozRegistry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
80
mozilla/xpcom/components/nsIFactory.h
Normal file
80
mozilla/xpcom/components/nsIFactory.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 __nsIFactory_h
|
||||
#define __nsIFactory_h
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
/*
|
||||
* Datatypes and helper macros
|
||||
*/
|
||||
|
||||
typedef nsID nsCID;
|
||||
|
||||
// Define an CID
|
||||
#define NS_DEFINE_CID(_name, _cidspec) \
|
||||
const nsCID _name = _cidspec
|
||||
|
||||
#define REFNSCID const nsCID&
|
||||
|
||||
/*
|
||||
* nsIFactory interface
|
||||
*/
|
||||
|
||||
// {00000001-0000-0000-c000-000000000046}
|
||||
#define NS_IFACTORY_IID \
|
||||
{ 0x00000001, 0x0000, 0x0000, \
|
||||
{ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }
|
||||
|
||||
class nsIFactory: public nsISupports {
|
||||
public:
|
||||
static const nsIID& IID() { static nsIID iid = NS_IFACTORY_IID; return iid; }
|
||||
|
||||
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
void **aResult) = 0;
|
||||
|
||||
NS_IMETHOD LockFactory(PRBool aLock) = 0;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* Excluding IFactory2 until there is proof of its use - dp */
|
||||
/**
|
||||
* nsIFactory2 allows passing in a signature token when creating an
|
||||
* instance. This allows instance recycling.
|
||||
*/
|
||||
|
||||
// {19997C41-A343-11d1-B665-00805F8A2676}
|
||||
#define NS_IFACTORY2_IID \
|
||||
{ 0x19997c41, 0xa343, 0x11d1, \
|
||||
{ 0xb6, 0x65, 0x0, 0x80, 0x5f, 0x8a, 0x26, 0x76 } }
|
||||
|
||||
class nsIFactory2: public nsIFactory {
|
||||
public:
|
||||
static const nsIID& IID() { static nsIID iid = NS_IFACTORY2_IID; return iid; }
|
||||
|
||||
NS_IMETHOD CreateInstance2(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
void *aSignature,
|
||||
void **aResult) = 0;
|
||||
};
|
||||
#endif /* 0 */
|
||||
|
||||
#endif
|
||||
326
mozilla/xpcom/components/nsIRegistry.h
Normal file
326
mozilla/xpcom/components/nsIRegistry.h
Normal file
@@ -0,0 +1,326 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 __nsIRegistry_h
|
||||
#define __nsIRegistry_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsIEnumerator;
|
||||
|
||||
/*-------------------------------- nsIRegistry ---------------------------------
|
||||
| This interface provides access to a tree of arbitrary values. |
|
||||
| |
|
||||
| Each node of the tree contains either a value or a subtree or both. |
|
||||
| |
|
||||
| The value at any of these leaf nodes can be any of these "primitive" types: |
|
||||
| o string (null terminated UTF string) |
|
||||
| o array of 32-bit integers |
|
||||
| o arbitrary array of bytes |
|
||||
| o file identifier |
|
||||
| Of course, since you can store an arbitrary array of bytes, you can put |
|
||||
| any data you like into a registry (although you have the burden of |
|
||||
| encoding/decoding your data in that case). |
|
||||
| |
|
||||
| Each branch of the tree is labelled with a string "key." The entire path |
|
||||
| from a given point of the tree to another point further down can be |
|
||||
| presented as a single string composed of each branch's label, concatenated |
|
||||
| to the next, with an intervening forward slash ('/'). The term "key" |
|
||||
| refers to both specific tree branch labels and to such concatenated paths. |
|
||||
| |
|
||||
| The branches from a given node must have unique labels. Distinct nodes can |
|
||||
| have branches with the same label. |
|
||||
| |
|
||||
| For example, here's a small registry tree: |
|
||||
| | |
|
||||
| /\ |
|
||||
| / \ |
|
||||
| / \ |
|
||||
| / \ |
|
||||
| "Classes" "Users" |
|
||||
| / \ |
|
||||
| / \ |
|
||||
| / ["joe"] |
|
||||
| / / \ |
|
||||
| | / \ |
|
||||
| /\ / \ |
|
||||
| / \ "joe" "bob" |
|
||||
| / \ / \ |
|
||||
| / \ |
|
||||
| "{xxxx-xx-1}" "{xxxx-xx-2}" ["c:/joe"] ["d:/Robert"] |
|
||||
| | | |
|
||||
| /\ /\ |
|
||||
| / \ / \ |
|
||||
| / \ / \ |
|
||||
| "Library" "Version" "Library" "Version" |
|
||||
| / \ / \ |
|
||||
| ["foo.dll"] 2 ["bar.dll"] 1 |
|
||||
| |
|
||||
| In this example, there are 2 keys under the root: "Classes" and "Users". |
|
||||
| The first denotes a subtree only (which has two subtrees, ...). The second |
|
||||
| denotes both a value ["joe"] and two subtrees labelled "joe" and "bob". |
|
||||
| The value at the node "/Users" is ["joe"], at "/Users/bob" is ["d:/Robert"]. |
|
||||
| The value at "/Classes/{xxxx-xx-1}/Version" is 2. |
|
||||
| |
|
||||
| The registry interface provides functions that let you navigate the tree |
|
||||
| and manipulate it's contents. |
|
||||
| |
|
||||
| Please note that the registry itself does not impose any structure or |
|
||||
| meaning on the contents of the tree. For example, the registry doesn't |
|
||||
| control whether the value at the key "/Users" is the label for the subtree |
|
||||
| with information about the last active user. That meaning is applied by |
|
||||
| the code that stores these values and uses them for that purpose. |
|
||||
| |
|
||||
| [Any resemblence between this example and actual contents of any actual |
|
||||
| registry is purely coincidental.] |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct nsIRegistry : public nsISupports {
|
||||
/*------------------------------ Constants ---------------------------------
|
||||
| The following enumerated types and values are used by the registry |
|
||||
| interface. |
|
||||
--------------------------------------------------------------------------*/
|
||||
typedef enum {
|
||||
String = 1,
|
||||
Int32,
|
||||
Bytes,
|
||||
File
|
||||
} DataType;
|
||||
|
||||
/*-------------------------------- Types -----------------------------------
|
||||
| The following data types are used by this interface. All are basically |
|
||||
| opaque types. You obtain objects of these types via certain member |
|
||||
| function calls and re-use them later (without having to know what they |
|
||||
| contain). |
|
||||
| |
|
||||
| Key - Placeholder to represent a particular node in a registry |
|
||||
| tree. There are 3 enumerated values that correspond to |
|
||||
| specific nodes: |
|
||||
| Common - Where most stuff goes. |
|
||||
| Users - Special subtree to hold info about |
|
||||
| "users"; if you don't know what goes |
|
||||
| here, don't mess with it. |
|
||||
| CurrentUser - Subtree under Users corresponding to |
|
||||
| whatever user is designed the "current" |
|
||||
| one; see note above. |
|
||||
| You can specify any of these enumerated values as "keys" |
|
||||
| on any member function that takes a nsRegistry::Key. |
|
||||
| ValueInfo - Structure describing a registry value. |
|
||||
--------------------------------------------------------------------------*/
|
||||
typedef uint32 Key;
|
||||
|
||||
enum { Users = 1, Common = 2, CurrentUser = 3 };
|
||||
|
||||
struct ValueInfo {
|
||||
DataType type;
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
/*--------------------------- Opening/Closing ------------------------------
|
||||
| These functions open the specified registry file (Open() with a non-null |
|
||||
| argument) or the default "standard" registry file (Open() with a null |
|
||||
| argument or OpenDefault()). |
|
||||
| |
|
||||
| Once opened, you can access the registry contents via the read/write |
|
||||
| or query functions. |
|
||||
| |
|
||||
| The registry file will be closed automatically when the registry object |
|
||||
| is destroyed. You can close the file prior to that by using the |
|
||||
| Close() function. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD Open( const char *regFile = 0 ) = 0;
|
||||
NS_IMETHOD OpenDefault() = 0;
|
||||
NS_IMETHOD Close() = 0;
|
||||
|
||||
/*----------------------- Reading/Writing Values ---------------------------
|
||||
| These functions read/write the registry values at a given node. |
|
||||
| |
|
||||
| All functions require you to specify where in the registry key to |
|
||||
| get/set the value. The location is specified using two components: |
|
||||
| o A "base key" indicating where to start from; this is a value of type |
|
||||
| nsIRegistry::Key. You use either one of the special "root" key |
|
||||
| values or a subkey obtained via some other member function call. |
|
||||
| o A "relative path," expressed as a sequence of subtree names |
|
||||
| separated by forward slashes. This path describes how to get from |
|
||||
| the base key to the node at which you want to store the data. This |
|
||||
| component can be a null pointer which means the value goes directly |
|
||||
| at the node denoted by the base key. |
|
||||
| |
|
||||
| When you request a value of a given type, the data stored at the |
|
||||
| specified node must be of the type requested. If not, an error results. |
|
||||
| |
|
||||
| GetString - Obtains a newly allocated copy of a string type value. The |
|
||||
| caller is obligated to free the returned string using |
|
||||
| PR_Free. |
|
||||
| SetString - Stores the argument string at the specified node. |
|
||||
| GetInt - Obtains an int32 value at the specified node. The result |
|
||||
| is returned into an int32 location you specify. |
|
||||
| SetInt - Stores a given int32 value at a node. |
|
||||
| GetBytes - Obtains a byte array value; this returns both an allocated |
|
||||
| array of bytes and a length (necessary because there may be |
|
||||
| embedded null bytes in the array). You must free the |
|
||||
| resulting array using PR_Free. |
|
||||
| SetBytes - Stores a given array of bytes; you specify the bytes via a |
|
||||
| pointer and a length. |
|
||||
| GetIntArray - Obtains the array of int32 values stored at a given node. |
|
||||
| The result is composed of two values: a pointer to an |
|
||||
| array of integer values (which must be freed using |
|
||||
| PR_Free) and the number of elements in that array. |
|
||||
| SetIntArray - Stores a set of int32 values at a given node. You must |
|
||||
| provide a pointer to the array and the number of entries. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD GetString( Key baseKey, const char *path, char **result ) = 0;
|
||||
NS_IMETHOD SetString( Key baseKey, const char *path, const char *value ) = 0;
|
||||
NS_IMETHOD GetInt( Key baseKey, const char *path, int32 *result ) = 0;
|
||||
NS_IMETHOD SetInt( Key baseKey, const char *path, int32 value ) = 0;
|
||||
NS_IMETHOD GetBytes( Key baseKey, const char *path, void **result, uint32 *len ) = 0;
|
||||
NS_IMETHOD SetBytes( Key baseKey, const char *path, void *value, uint32 len ) = 0;
|
||||
NS_IMETHOD GetIntArray( Key baseKey, const char *path, int32 **result, uint32 *len ) = 0;
|
||||
NS_IMETHOD SetIntArray( Key baseKey, const char *path, const int32 *value, uint32 len ) = 0;
|
||||
|
||||
/*------------------------------ Navigation --------------------------------
|
||||
| These functions let you navigate through the registry tree, querying |
|
||||
| its contents. |
|
||||
| |
|
||||
| As above, all these functions requires a starting tree location ("base |
|
||||
| key") specified as a nsIRegistry::Key. Some also require a path |
|
||||
| name to locate the registry node location relative to this base key. |
|
||||
| |
|
||||
| AddSubtree - Adds a new registry subtree at the specified |
|
||||
| location. Returns the resulting key in |
|
||||
| the location specified by the third argument |
|
||||
| (unless that pointer is 0). |
|
||||
| RemoveNode - Removes the specified registry subtree or |
|
||||
| value at the specified location. |
|
||||
| GetSubtree - Returns a nsIRegistry::Key that can be used |
|
||||
| to refer to the specified registry location. |
|
||||
| EnumerateSubtrees - Returns a nsIEnumerator object that you can |
|
||||
| use to enumerate all the subtrees descending |
|
||||
| from a specified location. You must free the |
|
||||
| enumerator via Release() when you're done with |
|
||||
| it. |
|
||||
| EnumerateAllSubtrees - Like EnumerateSubtrees, but will recursively |
|
||||
| enumerate lower-level subtrees, too. |
|
||||
| GetValueInfo - Returns a uint32 value that designates the type |
|
||||
| of data stored at this location in the registry; |
|
||||
| the possible values are defined by the enumerated |
|
||||
| type nsIRegistry::DataType. |
|
||||
| GetValueLength - Returns a uint32 value that indicates the length |
|
||||
| of this registry value; the length is the number |
|
||||
| of characters (for Strings), the number of bytes |
|
||||
| (for Bytes), or the number of int32 values (for |
|
||||
| Int32). |
|
||||
| EnumerateValues - Returns a nsIEnumerator that you can use to |
|
||||
| enumerate all the value nodes descending from |
|
||||
| a specified location. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD AddSubtree( Key baseKey, const char *path, Key *result ) = 0;
|
||||
NS_IMETHOD RemoveSubtree( Key baseKey, const char *path ) = 0;
|
||||
NS_IMETHOD GetSubtree( Key baseKey, const char *path, Key *result ) = 0;
|
||||
|
||||
NS_IMETHOD EnumerateSubtrees( Key baseKey, nsIEnumerator **result ) = 0;
|
||||
NS_IMETHOD EnumerateAllSubtrees( Key baseKey, nsIEnumerator **result ) = 0;
|
||||
|
||||
NS_IMETHOD GetValueType( Key baseKey, const char *path, uint32 *result ) = 0;
|
||||
NS_IMETHOD GetValueLength( Key baseKey, const char *path, uint32 *result ) = 0;
|
||||
|
||||
NS_IMETHOD EnumerateValues( Key baseKey, nsIEnumerator **result ) = 0;
|
||||
|
||||
/*------------------------------ User Name ---------------------------------
|
||||
| These functions manipulate the current "user name." This value controls |
|
||||
| the behavior of certain registry functions (namely, ?). |
|
||||
| |
|
||||
| GetCurrentUserName allocates a copy of the current user name (which the |
|
||||
| caller should free using PR_Free). |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD GetCurrentUserName( char **result ) = 0;
|
||||
NS_IMETHOD SetCurrentUserName( const char *name ) = 0;
|
||||
|
||||
/*------------------------------ Utilities ---------------------------------
|
||||
| Various utility functions: |
|
||||
| |
|
||||
| Pack() is used to compress the contents of an open registry file. |
|
||||
--------------------------------------------------------------------------*/
|
||||
NS_IMETHOD Pack() = 0;
|
||||
|
||||
}; // nsIRegistry
|
||||
|
||||
/*------------------------------ nsIRegistryNode -------------------------------
|
||||
| This interface is implemented by all the objects obtained from the |
|
||||
| nsIEnumerators that nsIRegistry provides when you call either of the |
|
||||
| subtree enumeration functions EnumerateSubtrees or EnumerateAllSubtrees. |
|
||||
| |
|
||||
| You can call this function to get the name of this subtree. This is the |
|
||||
| relative path from the base key from which you got this interface. |
|
||||
| |
|
||||
| GetName - Returns the path name of this node; this is the relative path |
|
||||
| from the base key from which this subtree was obtained. The |
|
||||
| function allocates a copy of the name; the caller must free it |
|
||||
| using PR_Free. |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct nsIRegistryNode : public nsISupports {
|
||||
NS_IMETHOD GetName( char **result ) = 0;
|
||||
}; // nsIRegistryNode
|
||||
|
||||
/*------------------------------ nsIRegistryValue ------------------------------
|
||||
| This interface is implemented by the objects obtained from the |
|
||||
| nsIEnumerators that nsIRegistry provides when you call the |
|
||||
| EnumerateValues function. An object supporting this interface is |
|
||||
| returned when you call the CurrentItem() function on that enumerator. |
|
||||
| |
|
||||
| You use the member functions of this interface to obtain information |
|
||||
| about each registry value. |
|
||||
| |
|
||||
| GetName - Returns the path name of this node; this is the relative |
|
||||
| path\ from the base key from which this value was obtained. |
|
||||
| The function allocates a copy of the name; the caller must |
|
||||
| subsequently free it via PR_Free. |
|
||||
| GetValueType - Returns (into a location provided by the caller) the type |
|
||||
| of the value; the types are defined by the enumerated |
|
||||
| type nsIRegistry::DataType. |
|
||||
| GetValueLength - Returns a uint32 value that indicates the length |
|
||||
| of this registry value; the length is the number |
|
||||
| of characters (for Strings), the number of bytes |
|
||||
| (for Bytes), or the number of int32 values (for |
|
||||
| Int32). |
|
||||
------------------------------------------------------------------------------*/
|
||||
struct nsIRegistryValue : public nsISupports {
|
||||
NS_IMETHOD GetName( char **result ) = 0;
|
||||
NS_IMETHOD GetValueType( uint32 *result ) = 0;
|
||||
NS_IMETHOD GetValueLength( uint32 *result ) = 0;
|
||||
}; // nsIRegistryEntry
|
||||
|
||||
|
||||
/*------------------------------- Error Codes ----------------------------------
|
||||
------------------------------------------------------------------------------*/
|
||||
#define NS_ERROR_REG_BADTYPE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 1 )
|
||||
#define NS_ERROR_REG_NO_MORE NS_ERROR_GENERATE_SUCCESS( NS_ERROR_MODULE_REG, 2 )
|
||||
#define NS_ERROR_REG_NOT_FOUND NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 3 )
|
||||
#define NS_ERROR_REG_NOFILE NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 4 )
|
||||
#define NS_ERROR_REG_BUFFER_TOO_SMALL NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 5 )
|
||||
#define NS_ERROR_REG_NAME_TOO_LONG NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 6 )
|
||||
#define NS_ERROR_REG_NO_PATH NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 7 )
|
||||
#define NS_ERROR_REG_READ_ONLY NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 8 )
|
||||
#define NS_ERROR_REG_BAD_UTF8 NS_ERROR_GENERATE_FAILURE( NS_ERROR_MODULE_REG, 9 )
|
||||
|
||||
// {5D41A440-8E37-11d2-8059-00600811A9C3}
|
||||
#define NS_IREGISTRY_IID { 0x5d41a440, 0x8e37, 0x11d2, { 0x80, 0x59, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
// {D1B54831-AC07-11d2-805E-00600811A9C3}
|
||||
#define NS_IREGISTRYNODE_IID { 0xd1b54831, 0xac07, 0x11d2, { 0x80, 0x5e, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
// {5316C380-B2F8-11d2-A374-0080C6F80E4B}
|
||||
#define NS_IREGISTRYVALUE_IID { 0x5316c380, 0xb2f8, 0x11d2, { 0xa3, 0x74, 0x0, 0x80, 0xc6, 0xf8, 0xe, 0x4b } }
|
||||
|
||||
#endif
|
||||
148
mozilla/xpcom/components/nsIServiceManager.h
Normal file
148
mozilla/xpcom/components/nsIServiceManager.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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 nsIServiceManager_h___
|
||||
#define nsIServiceManager_h___
|
||||
|
||||
#include "nsRepository.h"
|
||||
|
||||
class nsIShutdownListener;
|
||||
|
||||
/**
|
||||
* The nsIServiceManager manager interface provides a means to obtain
|
||||
* global services in an application. The service manager depends on the
|
||||
* repository to find and instantiate factories to obtain services.
|
||||
*
|
||||
* Users of the service manager must first obtain a pointer to the global
|
||||
* service manager by calling NS_GetGlobalServiceManager. After that,
|
||||
* they can request specific services by calling GetService. When they are
|
||||
* finished with a service the release it by calling ReleaseService (instead
|
||||
* of releasing the service object directly):
|
||||
*
|
||||
* nsICacheManager* cm;
|
||||
* nsServiceManager::GetService(kCacheManagerCID, kICacheManagerIID, (nsISupports**)&cm);
|
||||
*
|
||||
* ... use cm, and then sometime later ...
|
||||
*
|
||||
* nsServiceManager::ReleaseService(kCacheManagerCID, cm);
|
||||
*
|
||||
* A user of a service may keep references to particular services indefinitely
|
||||
* and only must call ReleaseService when it shuts down. However if the user
|
||||
* wishes to voluntarily cooperate with the shutdown of the service it is
|
||||
* using, it may supply an nsIShutdownListener to provide for asynchronous
|
||||
* release of the services it is using. The shutdown listener's OnShutdown
|
||||
* method will be called for a service that is being shut down, and it is
|
||||
* its responsiblity to release references obtained from that service if at
|
||||
* all possible.
|
||||
*
|
||||
* The process of shutting down a particular service is initiated by calling
|
||||
* the service manager's ShutdownService method. This will iterate through
|
||||
* all the registered shutdown listeners for the service being shut down, and
|
||||
* then will attempt to unload the library associated with the service if
|
||||
* possible. The status result of ShutdownService indicates whether the
|
||||
* service was successfully shut down, failed, or was not in service.
|
||||
*
|
||||
* XXX QUESTIONS:
|
||||
* - Should a "service" be more than nsISupports? Should it be a factory
|
||||
* and/or have Startup(), Shutdown(), etc.
|
||||
* - If the asynchronous OnShutdown operation gets called, does the user
|
||||
* of a service still need to call ReleaseService? (Or should they _not_
|
||||
* call it?)
|
||||
*/
|
||||
class nsIServiceManager : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_IMETHOD
|
||||
GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener = NULL) = 0;
|
||||
|
||||
NS_IMETHOD
|
||||
ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener = NULL) = 0;
|
||||
|
||||
/**
|
||||
* Requests a service to be shut down, possibly unloading its DLL.
|
||||
*
|
||||
* @returns NS_OK - if shutdown was successful and service was unloaded,
|
||||
* @returns NS_ERROR_SERVICE_NOT_FOUND - if shutdown failed because
|
||||
* the service was not currently loaded
|
||||
* @returns NS_ERROR_SERVICE_IN_USE - if shutdown failed because some
|
||||
* user of the service wouldn't voluntarily release it by using
|
||||
* a shutdown listener.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
ShutdownService(const nsCID& aClass) = 0;
|
||||
|
||||
};
|
||||
|
||||
#define NS_ISERVICEMANAGER_IID \
|
||||
{ /* cf0df3b0-3401-11d2-8163-006008119d7a */ \
|
||||
0xcf0df3b0, \
|
||||
0x3401, \
|
||||
0x11d2, \
|
||||
{0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
#define NS_ERROR_SERVICE_NOT_FOUND NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 22)
|
||||
#define NS_ERROR_SERVICE_IN_USE NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 23)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsIShutdownListener : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_IMETHOD
|
||||
OnShutdown(const nsCID& aClass, nsISupports* service) = 0;
|
||||
|
||||
};
|
||||
|
||||
#define NS_ISHUTDOWNLISTENER_IID \
|
||||
{ /* 56decae0-3406-11d2-8163-006008119d7a */ \
|
||||
0x56decae0, \
|
||||
0x3406, \
|
||||
0x11d2, \
|
||||
{0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface to Global Services
|
||||
|
||||
class NS_COM nsServiceManager {
|
||||
public:
|
||||
static nsresult GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener = NULL);
|
||||
|
||||
static nsresult ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener = NULL);
|
||||
|
||||
static nsresult ShutdownService(const nsCID& aClass);
|
||||
|
||||
// Since the global Service Manager is truly global, there's no need to
|
||||
// release it.
|
||||
static nsresult GetGlobalServiceManager(nsIServiceManager* *result);
|
||||
|
||||
protected:
|
||||
static nsIServiceManager* globalServiceManager;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* nsIServiceManager_h___ */
|
||||
@@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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
|
||||
@@ -16,14 +16,16 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SSA_TOOLS_H_
|
||||
#define _SSA_TOOLS_H_
|
||||
#ifndef __nsIServerProvider_h
|
||||
#define __nsIServerProvider_h
|
||||
#include "nsISupports.h"
|
||||
|
||||
#include "Fundamentals.h"
|
||||
typedef nsID nsSID;
|
||||
#define NSSIDREF const nsSID&
|
||||
|
||||
class ControlGraph;
|
||||
class VirtualRegisterManager;
|
||||
class nsIServiceProvider: public nsISupports {
|
||||
public:
|
||||
NS_IMETHOD QueryService(NSSIDREF aSID, NSIIDREF sIID, (void **) pService);
|
||||
};
|
||||
|
||||
extern void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
|
||||
|
||||
#endif // _SSA_TOOLS_H_
|
||||
#endif /* __nsIServerProvider_h */
|
||||
118
mozilla/xpcom/components/nsMacRepository.h
Normal file
118
mozilla/xpcom/components/nsMacRepository.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifdef XP_MAC
|
||||
#ifdef MOZ_NGLAYOUT
|
||||
|
||||
#error "nsMacRepository.h became obsolete when the shared lib conversion was completed."
|
||||
|
||||
// The Mac NGLayout is not based on shared libraries yet.
|
||||
// All the DLLs are built as static libraries and we present them as
|
||||
// shared libraries by redefining PR_LoadLibrary(), PR_UnloadLibrary()
|
||||
// and PR_FindSymbol() below.
|
||||
//
|
||||
// If you add or remove shared libraries on other platforms, you must
|
||||
// - Add the library name to the defines below.
|
||||
// - Rename the "NSGetFactory" and "NSCanUnload" procs for the Mac:
|
||||
// just append the library name to the function name.
|
||||
// - Add the library and its procs to the static list below.
|
||||
|
||||
|
||||
typedef struct MacLibrary
|
||||
{
|
||||
char * name;
|
||||
nsFactoryProc factoryProc;
|
||||
nsCanUnloadProc unloadProc;
|
||||
} MacLibrary;
|
||||
|
||||
// library names
|
||||
#define WIDGET_DLL "WIDGET_DLL"
|
||||
#define GFXWIN_DLL "GFXWIN_DLL"
|
||||
#define VIEW_DLL "VIEW_DLL"
|
||||
#define WEB_DLL "WEB_DLL"
|
||||
#define PLUGIN_DLL "PLUGIN_DLL"
|
||||
#define PREF_DLL "PREF_DLL"
|
||||
#define PARSER_DLL "PARSER_DLL"
|
||||
#define DOM_DLL "DOM_DLL"
|
||||
#define LAYOUT_DLL "LAYOUT_DLL"
|
||||
#define NETLIB_DLL "NETLIB_DLL"
|
||||
#define EDITOR_DLL "EDITOR_DLL"
|
||||
|
||||
#ifdef IMPL_MAC_REPOSITORY
|
||||
|
||||
extern "C" nsresult NSGetFactory_WIDGET_DLL(const nsCID &, nsISupports* , nsIFactory ** );
|
||||
extern "C" nsresult NSGetFactory_GFXWIN_DLL(const nsCID &, nsISupports*, nsIFactory ** );
|
||||
extern "C" nsresult NSGetFactory_VIEW_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_WEB_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
//extern "C" nsresult NSGetFactory_PLUGIN_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_PREF_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_PARSER_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_DOM_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_LAYOUT_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_NETLIB_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
extern "C" nsresult NSGetFactory_EDITOR_DLL(const nsCID &, nsISupports*, nsIFactory **);
|
||||
|
||||
extern "C" PRBool NSCanUnload_PREF_DLL(void);
|
||||
|
||||
// library list
|
||||
static MacLibrary libraries[] = {
|
||||
#if 0
|
||||
WIDGET_DLL, NSGetFactory_WIDGET_DLL, NULL,
|
||||
GFXWIN_DLL, NSGetFactory_GFXWIN_DLL, NULL,
|
||||
VIEW_DLL, NSGetFactory_VIEW_DLL, NULL,
|
||||
WEB_DLL, NSGetFactory_WEB_DLL, NULL,
|
||||
//PLUGIN_DLL, NSGetFactory_PLUGIN_DLL, NULL,
|
||||
PREF_DLL, NSGetFactory_PREF_DLL, NSCanUnload_PREF_DLL,
|
||||
PARSER_DLL, NSGetFactory_PARSER_DLL, NULL,
|
||||
DOM_DLL, NSGetFactory_DOM_DLL, NULL,
|
||||
LAYOUT_DLL, NSGetFactory_LAYOUT_DLL, NULL,
|
||||
NETLIB_DLL, NSGetFactory_NETLIB_DLL, NULL,
|
||||
//EDITOR_DLL, NSGetFactory_EDITOR_DLL, NULL, // FIX ME
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static void* FindMacSymbol(char* libName, const char *symbolName)
|
||||
{
|
||||
MacLibrary * macLib;
|
||||
|
||||
for (macLib = libraries; ; macLib ++)
|
||||
{
|
||||
if (macLib->name == NULL)
|
||||
return NULL;
|
||||
|
||||
if (PL_strcmp(macLib->name, libName) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (PL_strcmp(symbolName, "NSGetFactory") == 0) {
|
||||
return macLib->factoryProc;
|
||||
}
|
||||
else if (PL_strcmp(symbolName, "NSCanUnload") == 0) {
|
||||
return macLib->unloadProc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define PR_LoadLibrary(libName) (PRLibrary *)libName
|
||||
#define PR_UnloadLibrary(lib) lib = NULL
|
||||
#define PR_FindSymbol(lib, symbolName) FindMacSymbol((char*)lib, symbolName)
|
||||
|
||||
#endif // IMPL_MAC_REPOSITORY
|
||||
|
||||
#endif // MOZ_NGLAYOUT
|
||||
#endif // XP_MAC
|
||||
1204
mozilla/xpcom/components/nsRegistry.cpp
Normal file
1204
mozilla/xpcom/components/nsRegistry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1592
mozilla/xpcom/components/nsRepository.cpp
Normal file
1592
mozilla/xpcom/components/nsRepository.cpp
Normal file
File diff suppressed because it is too large
Load Diff
213
mozilla/xpcom/components/nsRepository.h
Normal file
213
mozilla/xpcom/components/nsRepository.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 __nsRespository_h
|
||||
#define __nsRespository_h
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "prlog.h"
|
||||
#include "prmon.h"
|
||||
#include "nsCom.h"
|
||||
#include "nsID.h"
|
||||
#include "nsError.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
/*
|
||||
* Prototypes for dynamic library export functions
|
||||
*/
|
||||
|
||||
class nsIServiceManager;
|
||||
|
||||
|
||||
//***********************************************************
|
||||
//
|
||||
// NSGetFactory should take nsISupports instead of nsIServiceManager
|
||||
// as the second param. This is done on purpose!! Please don't change
|
||||
// it.
|
||||
// sudu / stanley
|
||||
//
|
||||
//***********************************************************
|
||||
extern "C" NS_EXPORT nsresult NSGetFactory(const nsCID &aClass,
|
||||
nsISupports* serviceMgr,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" NS_EXPORT PRBool NSCanUnload();
|
||||
extern "C" NS_EXPORT nsresult NSRegisterSelf(const char *fullpath);
|
||||
extern "C" NS_EXPORT nsresult NSUnregisterSelf(const char *fullpath);
|
||||
|
||||
/* Quick Registration
|
||||
*
|
||||
* For quick registration, dlls can define
|
||||
* NSQuickRegisterClassData g_NSQuickRegisterData[];
|
||||
* and export the symbol "g_NSQuickRegisterData"
|
||||
*
|
||||
* Quick registration is tried only if the symbol "NSRegisterSelf"
|
||||
* is not found. If it is found but fails registration, quick registration
|
||||
* will not kick in.
|
||||
*
|
||||
* The array is terminated by having a NULL last element. Specifically, the
|
||||
* array will be assumed to end when
|
||||
* (g_NSQuickRegisterData[i].classIdStr == NULL)
|
||||
*
|
||||
*/
|
||||
#define NS_QUICKREGISTER_DATA_SYMBOL "g_NSQuickRegisterData"
|
||||
|
||||
typedef struct NSQuickRegisterClassData {
|
||||
const char *CIDString; // {98765-8776-8958758759-958785}
|
||||
const char *className; // "Layout Engine"
|
||||
const char *progID; // "Gecko.LayoutEngine.1"
|
||||
} NSQuickRegisterClassData;
|
||||
|
||||
typedef NSQuickRegisterClassData* NSQuickRegisterData;
|
||||
|
||||
/* Autoregistration will try only files with these extensions.
|
||||
* All extensions are case insensitive.
|
||||
".dll", // Windows
|
||||
".dso", // Unix
|
||||
".so", // Unix
|
||||
".sl", // Unix: HP
|
||||
"_dll", // Mac
|
||||
".dlm", // new for all platforms
|
||||
*/
|
||||
|
||||
/*
|
||||
* Dynamic library export function types
|
||||
*/
|
||||
|
||||
typedef nsresult (*nsFactoryProc)(const nsCID &aCLass,
|
||||
nsISupports* serviceMgr,
|
||||
nsIFactory **aFactory);
|
||||
typedef PRBool (*nsCanUnloadProc)(void);
|
||||
typedef nsresult (*nsRegisterProc)(const char *path);
|
||||
typedef nsresult (*nsUnregisterProc)(const char *path);
|
||||
|
||||
/*
|
||||
* Support types
|
||||
*/
|
||||
|
||||
class FactoryEntry;
|
||||
class nsDllStore;
|
||||
class nsDll;
|
||||
|
||||
enum NSRegistrationInstant
|
||||
{
|
||||
NS_Startup = 0,
|
||||
NS_Script = 1,
|
||||
NS_Timer = 2
|
||||
};
|
||||
|
||||
/* Error codes generated by the repository methods */
|
||||
|
||||
#define NS_XPCOM_ERRORCODE_IS_DIR 1
|
||||
|
||||
/* The separator for each path part in the pathlist for autoregistration */
|
||||
|
||||
#define NS_PATH_SEPARATOR ';'
|
||||
|
||||
|
||||
/*
|
||||
* nsRepository class
|
||||
*/
|
||||
|
||||
class NS_COM nsRepository {
|
||||
private:
|
||||
|
||||
#define NS_MAX_FILENAME_LEN 1024
|
||||
|
||||
static nsHashtable *factories;
|
||||
static PRMonitor *monitor;
|
||||
|
||||
static nsresult checkInitialized(void);
|
||||
static nsresult loadFactory(FactoryEntry *aEntry, nsIFactory **aFactory);
|
||||
static nsresult SelfRegisterDll(nsDll *dll);
|
||||
static nsresult SelfUnregisterDll(nsDll *dll);
|
||||
|
||||
public:
|
||||
static nsDllStore *dllStore;
|
||||
|
||||
static nsresult Initialize(void);
|
||||
// Finds a factory for a specific class ID
|
||||
static nsresult FindFactory(const nsCID &aClass,
|
||||
nsIFactory **aFactory);
|
||||
|
||||
// Finds a class ID for a specific Program ID
|
||||
static nsresult ProgIDToCLSID(const char *aProgID,
|
||||
nsCID *aClass);
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
static nsresult CreateInstance(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult);
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
/*
|
||||
static nsresult CreateInstance2(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void *aSignature,
|
||||
void **aResult);
|
||||
*/
|
||||
|
||||
// Manually registry a factory for a class
|
||||
static nsresult RegisterFactory(const nsCID &aClass,
|
||||
nsIFactory *aFactory,
|
||||
PRBool aReplace);
|
||||
|
||||
// Manually registry a dynamically loaded factory for a class
|
||||
static nsresult RegisterFactory(const nsCID &aClass,
|
||||
const char *aLibrary,
|
||||
PRBool aReplace,
|
||||
PRBool aPersist);
|
||||
|
||||
// Manually register a dynamically loaded component.
|
||||
static nsresult RegisterComponent(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
const char *aLibrary,
|
||||
PRBool aReplace,
|
||||
PRBool aPersist);
|
||||
|
||||
// Manually unregister a factory for a class
|
||||
static nsresult UnregisterFactory(const nsCID &aClass,
|
||||
nsIFactory *aFactory);
|
||||
|
||||
// Manually unregister a dynamically loaded factory for a class
|
||||
static nsresult UnregisterFactory(const nsCID &aClass,
|
||||
const char *aLibrary);
|
||||
|
||||
// Manually unregister a dynamically loaded component
|
||||
static nsresult UnregisterComponent(const nsCID &aClass,
|
||||
const char *aLibrary);
|
||||
|
||||
// Unload dynamically loaded factories that are not in use
|
||||
static nsresult FreeLibraries(void);
|
||||
|
||||
// DLL registration support
|
||||
static nsresult AutoRegister(NSRegistrationInstant when,
|
||||
const char* pathlist);
|
||||
// Pathlist is a semicolon separated list of pathnames
|
||||
static nsresult AddToDefaultPathList(const char *pathlist);
|
||||
static nsresult SyncComponentsInPathList(const char *pathlist);
|
||||
static nsresult SyncComponentsInDir(const char *path);
|
||||
static nsresult SyncComponentsInFile(const char *fullname);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
350
mozilla/xpcom/components/nsServiceManager.cpp
Normal file
350
mozilla/xpcom/components/nsServiceManager.cpp
Normal file
@@ -0,0 +1,350 @@
|
||||
/* -*- Mode: C++; tab-width: 2; 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 "nsIServiceManager.h"
|
||||
#include "nsVector.h"
|
||||
#include "prcmon.h"
|
||||
#include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */
|
||||
|
||||
class nsServiceEntry {
|
||||
public:
|
||||
|
||||
nsServiceEntry(const nsCID& cid, nsISupports* service);
|
||||
~nsServiceEntry();
|
||||
|
||||
nsresult AddListener(nsIShutdownListener* listener);
|
||||
nsresult RemoveListener(nsIShutdownListener* listener);
|
||||
nsresult NotifyListeners(void);
|
||||
|
||||
const nsCID& mClassID;
|
||||
nsISupports* mService;
|
||||
nsVector* mListeners; // nsVector<nsIShutdownListener>
|
||||
PRBool mShuttingDown;
|
||||
|
||||
};
|
||||
|
||||
nsServiceEntry::nsServiceEntry(const nsCID& cid, nsISupports* service)
|
||||
: mClassID(cid), mService(service), mListeners(NULL), mShuttingDown(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
nsServiceEntry::~nsServiceEntry()
|
||||
{
|
||||
if (mListeners) {
|
||||
NS_ASSERTION(mListeners->GetSize() == 0, "listeners not removed or notified");
|
||||
#if 0
|
||||
PRUint32 size = mListeners->GetSize();
|
||||
for (PRUint32 i = 0; i < size; i++) {
|
||||
nsIShutdownListener* listener = (nsIShutdownListener*)(*mListeners)[i];
|
||||
listener->Release();
|
||||
}
|
||||
#endif
|
||||
delete mListeners;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceEntry::AddListener(nsIShutdownListener* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return NS_OK;
|
||||
if (mListeners == NULL) {
|
||||
mListeners = new nsVector();
|
||||
if (mListeners == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
PRInt32 err = mListeners->Add(listener);
|
||||
listener->AddRef();
|
||||
return err == -1 ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceEntry::RemoveListener(nsIShutdownListener* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return NS_OK;
|
||||
NS_ASSERTION(mListeners, "no listeners added yet");
|
||||
PRUint32 size = mListeners->GetSize();
|
||||
for (PRUint32 i = 0; i < size; i++) {
|
||||
if ((*mListeners)[i] == listener) {
|
||||
mListeners->Remove(i);
|
||||
listener->Release();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(0, "unregistered shutdown listener");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceEntry::NotifyListeners(void)
|
||||
{
|
||||
if (mListeners) {
|
||||
PRUint32 size = mListeners->GetSize();
|
||||
for (PRUint32 i = 0; i < size; i++) {
|
||||
nsIShutdownListener* listener = (nsIShutdownListener*)(*mListeners)[0];
|
||||
nsresult err = listener->OnShutdown(mClassID, mService);
|
||||
if (err) return err;
|
||||
listener->Release();
|
||||
mListeners->Remove(0);
|
||||
}
|
||||
NS_ASSERTION(mListeners->GetSize() == 0, "failed to notify all listeners");
|
||||
delete mListeners;
|
||||
mListeners = NULL;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsServiceManagerImpl : public nsIServiceManager {
|
||||
public:
|
||||
|
||||
NS_IMETHOD
|
||||
GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener = NULL);
|
||||
|
||||
NS_IMETHOD
|
||||
ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener = NULL);
|
||||
|
||||
NS_IMETHOD
|
||||
ShutdownService(const nsCID& aClass);
|
||||
|
||||
nsServiceManagerImpl(void);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~nsServiceManagerImpl(void);
|
||||
|
||||
nsHashtable* mServices; // nsHashtable<nsServiceEntry>
|
||||
};
|
||||
|
||||
nsServiceManagerImpl::nsServiceManagerImpl(void)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mServices = new nsHashtable();
|
||||
NS_ASSERTION(mServices, "out of memory already?");
|
||||
}
|
||||
|
||||
static PRBool
|
||||
DeleteEntry(nsHashKey *aKey, void *aData, void* closure)
|
||||
{
|
||||
nsServiceEntry* entry = (nsServiceEntry*)aData;
|
||||
entry->mService->Release();
|
||||
delete entry;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsServiceManagerImpl::~nsServiceManagerImpl(void)
|
||||
{
|
||||
mServices->Enumerate(DeleteEntry);
|
||||
delete mServices;
|
||||
}
|
||||
|
||||
static NS_DEFINE_IID(kIServiceManagerIID, NS_ISERVICEMANAGER_IID);
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
|
||||
NS_IMPL_ADDREF(nsServiceManagerImpl);
|
||||
NS_IMPL_RELEASE(nsServiceManagerImpl);
|
||||
|
||||
nsresult
|
||||
nsServiceManagerImpl::QueryInterface(const nsIID& aIID, void* *aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
*aInstancePtr = NULL;
|
||||
if (aIID.Equals(kIServiceManagerIID) ||
|
||||
aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = (void*) this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsresult err = NS_OK;
|
||||
/* XXX: This is a hack to force NSPR initialization.. This should be
|
||||
* removed once PR_CEnterMonitor(...) initializes NSPR... (rick)
|
||||
*/
|
||||
(void)PR_GetCurrentThread();
|
||||
PR_CEnterMonitor(this);
|
||||
|
||||
nsIDKey key(aClass);
|
||||
nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key);
|
||||
|
||||
if (entry) {
|
||||
nsISupports* service;
|
||||
err = entry->mService->QueryInterface(aIID, (void**)&service);
|
||||
if (err == NS_OK) {
|
||||
err = entry->AddListener(shutdownListener);
|
||||
if (err == NS_OK) {
|
||||
*result = service;
|
||||
|
||||
// If someone else requested the service to be shut down,
|
||||
// and we just asked to get it again before it could be
|
||||
// released, then cancel their shutdown request:
|
||||
if (entry->mShuttingDown) {
|
||||
entry->mShuttingDown = PR_FALSE;
|
||||
service->AddRef(); // Released in ShutdownService
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsISupports* service;
|
||||
err = nsRepository::CreateInstance(aClass, NULL, aIID, (void**)&service);
|
||||
if (err == NS_OK) {
|
||||
entry = new nsServiceEntry(aClass, service);
|
||||
if (entry == NULL) {
|
||||
service->Release();
|
||||
err = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
err = entry->AddListener(shutdownListener);
|
||||
if (err == NS_OK) {
|
||||
mServices->Put(&key, entry);
|
||||
*result = service;
|
||||
service->AddRef(); // Released in ShutdownService
|
||||
}
|
||||
else {
|
||||
service->Release();
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_CExitMonitor(this);
|
||||
return err;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsresult err = NS_OK;
|
||||
PR_CEnterMonitor(this);
|
||||
|
||||
nsIDKey key(aClass);
|
||||
nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key);
|
||||
|
||||
NS_ASSERTION(entry, "service not found");
|
||||
NS_ASSERTION(entry->mService == service, "service looked failed");
|
||||
|
||||
if (entry) {
|
||||
err = entry->RemoveListener(shutdownListener);
|
||||
nsrefcnt cnt = service->Release();
|
||||
if (err == NS_OK && cnt == 0) {
|
||||
mServices->Remove(&key);
|
||||
delete entry;
|
||||
err = nsRepository::FreeLibraries();
|
||||
}
|
||||
}
|
||||
|
||||
PR_CExitMonitor(this);
|
||||
return err;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManagerImpl::ShutdownService(const nsCID& aClass)
|
||||
{
|
||||
nsresult err = NS_OK;
|
||||
PR_CEnterMonitor(this);
|
||||
|
||||
nsIDKey key(aClass);
|
||||
nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key);
|
||||
|
||||
if (entry == NULL) {
|
||||
err = NS_ERROR_SERVICE_NOT_FOUND;
|
||||
}
|
||||
else {
|
||||
err = entry->NotifyListeners(); // break the cycles
|
||||
entry->mShuttingDown = PR_TRUE;
|
||||
nsrefcnt cnt = entry->mService->Release(); // AddRef in GetService
|
||||
if (err == NS_OK && cnt == 0) {
|
||||
mServices->Remove(&key);
|
||||
delete entry;
|
||||
err = nsRepository::FreeLibraries();
|
||||
}
|
||||
else
|
||||
err = NS_ERROR_SERVICE_IN_USE;
|
||||
}
|
||||
|
||||
PR_CExitMonitor(this);
|
||||
return err;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global service manager interface (see nsIServiceManager.h)
|
||||
|
||||
nsIServiceManager* nsServiceManager::globalServiceManager = NULL;
|
||||
|
||||
nsresult
|
||||
nsServiceManager::GetGlobalServiceManager(nsIServiceManager* *result)
|
||||
{
|
||||
if (globalServiceManager == NULL) {
|
||||
globalServiceManager = new nsServiceManagerImpl();
|
||||
if (globalServiceManager == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
globalServiceManager->AddRef();
|
||||
}
|
||||
*result = globalServiceManager;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rslt = GetGlobalServiceManager(&mgr);
|
||||
if (rslt != NS_OK) return rslt;
|
||||
return mgr->GetService(aClass, aIID, result, shutdownListener);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rslt = GetGlobalServiceManager(&mgr);
|
||||
if (rslt != NS_OK) return rslt;
|
||||
return mgr->ReleaseService(aClass, service, shutdownListener);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::ShutdownService(const nsCID& aClass)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rslt = GetGlobalServiceManager(&mgr);
|
||||
if (rslt != NS_OK) return rslt;
|
||||
return mgr->ShutdownService(aClass);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
153
mozilla/xpcom/components/nsXPComFactory.h
Normal file
153
mozilla/xpcom/components/nsXPComFactory.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and limitations
|
||||
* under the License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape Communications
|
||||
* Corporation. Portions created by Netscape are Copyright (C) 1998
|
||||
* Netscape Communications Corporation. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef nsXPComFactory_h__
|
||||
#define nsXPComFactory_h__
|
||||
|
||||
#include "nsIFactory.h"
|
||||
|
||||
/*
|
||||
* This file contains a templatized implementation of a simple XPCOM factory.
|
||||
*
|
||||
* To implement a factory for a given component, just provide a function
|
||||
* like the one below which can be called by your DLL's NSGetFactory(...)
|
||||
* entry point...
|
||||
*
|
||||
* nsresult NS_New_SomeComponent_Factory(nsIFactory** aResult)
|
||||
* {
|
||||
* nsresult rv = NS_OK;
|
||||
* nsIFactory* inst = new nsFactory<SomeComponent>();
|
||||
* if (NULL == inst) {
|
||||
* rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
* } else {
|
||||
* NS_ADDREF(inst);
|
||||
* }
|
||||
* *aResult = inst;
|
||||
* return rv;
|
||||
* }
|
||||
*
|
||||
* NOTE:
|
||||
* ----
|
||||
* The factories created by this template are not thread-safe and do not
|
||||
* support aggregation.
|
||||
*
|
||||
*/
|
||||
template <class T> class nsFactory : public nsIFactory
|
||||
{
|
||||
public:
|
||||
nsFactory() { NS_INIT_REFCNT(); }
|
||||
|
||||
//
|
||||
// nsISupports interface...
|
||||
//
|
||||
// These implementations were copied from the NS_IMPL_ISUPPORTS macro
|
||||
// in nsISupports.h
|
||||
//
|
||||
NS_IMETHOD_(nsrefcnt) AddRef (void)
|
||||
{
|
||||
return ++mRefCnt;
|
||||
}
|
||||
|
||||
NS_IMETHOD_(nsrefcnt) Release(void)
|
||||
{
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release");
|
||||
if (--mRefCnt == 0) {
|
||||
NS_DELETEXPCOM(this);
|
||||
return 0;
|
||||
}
|
||||
return mRefCnt;
|
||||
}
|
||||
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
*aInstancePtr = NULL;
|
||||
|
||||
static NS_DEFINE_IID(kIFactoryIID, NS_IFACTORY_IID);
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
if (aIID.Equals(kIFactoryIID)) {
|
||||
*aInstancePtr = (void*) this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
if (aIID.Equals(kISupportsIID)) {
|
||||
*aInstancePtr = (void*) ((nsISupports*)this);
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
//
|
||||
// nsIFactory interface...
|
||||
//
|
||||
NS_IMETHOD CreateInstance(nsISupports *aOuter,
|
||||
const nsIID &aIID,
|
||||
void **aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
T* inst;
|
||||
// Parameter validation...
|
||||
if (NULL == aResult) {
|
||||
rv = NS_ERROR_NULL_POINTER;
|
||||
goto done;
|
||||
}
|
||||
// Do not support aggregatable components...
|
||||
*aResult = NULL;
|
||||
if (NULL != aOuter) {
|
||||
rv = NS_ERROR_NO_AGGREGATION;
|
||||
goto done;
|
||||
}
|
||||
// Create a new instance of the component...
|
||||
NS_NEWXPCOM(inst, T);
|
||||
if (NULL == inst) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
goto done;
|
||||
}
|
||||
// If the QI fails, the component will be destroyed...
|
||||
NS_ADDREF(inst);
|
||||
rv = inst->QueryInterface(aIID, aResult);
|
||||
NS_RELEASE(inst);
|
||||
|
||||
done:
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD LockFactory(PRBool aLock)
|
||||
{
|
||||
// Not implemented in simplest case.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual ~nsFactory()
|
||||
{
|
||||
NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction");
|
||||
}
|
||||
|
||||
// Reference count variable used by nsISupports...
|
||||
nsrefcnt mRefCnt;
|
||||
};
|
||||
|
||||
|
||||
#endif /* nsXPComFactory_h__ */
|
||||
184
mozilla/xpcom/components/xcDll.cpp
Normal file
184
mozilla/xpcom/components/xcDll.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* nsDll
|
||||
*
|
||||
* Abstraction of a Dll. Stores modifiedTime and size for easy detection of
|
||||
* change in dll.
|
||||
*
|
||||
* dp Suresh <dp@netscape.com>
|
||||
*/
|
||||
|
||||
#include "xcDll.h"
|
||||
#include "plstr.h" // strdup and strfree
|
||||
|
||||
nsDll::nsDll(const char *libFullPath) : m_fullpath(NULL), m_instance(NULL),
|
||||
m_status(DLL_OK)
|
||||
{
|
||||
m_lastModTime = LL_ZERO;
|
||||
m_size = 0;
|
||||
|
||||
if (libFullPath == NULL)
|
||||
{
|
||||
m_status = DLL_INVALID_PARAM;
|
||||
return;
|
||||
}
|
||||
m_fullpath = PL_strdup(libFullPath);
|
||||
if (m_fullpath == NULL)
|
||||
{
|
||||
// No more memory
|
||||
m_status = DLL_NO_MEM;
|
||||
return;
|
||||
}
|
||||
|
||||
PRFileInfo statinfo;
|
||||
if (PR_GetFileInfo(m_fullpath, &statinfo) != PR_SUCCESS)
|
||||
{
|
||||
// The stat things works only if people pass in the full pathname.
|
||||
// Even if our stat fails, we could be able to load it because of
|
||||
// LD_LIBRARY_PATH and other such paths where dlls are searched for
|
||||
|
||||
// XXX we need a way of marking this occurance.
|
||||
// XXX m_status = DLL_STAT_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_size = statinfo.size;
|
||||
m_lastModTime = statinfo.modifyTime;
|
||||
if (statinfo.type != PR_FILE_FILE)
|
||||
{
|
||||
// Not a file. Cant work with it.
|
||||
m_status = DLL_NOT_FILE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_status = DLL_OK;
|
||||
}
|
||||
|
||||
|
||||
nsDll::nsDll(const char *libFullPath, PRTime lastModTime, PRUint32 fileSize)
|
||||
: m_fullpath(NULL), m_instance(NULL), m_status(DLL_OK)
|
||||
{
|
||||
m_lastModTime = lastModTime;
|
||||
m_size = fileSize;
|
||||
|
||||
if (libFullPath == NULL)
|
||||
{
|
||||
m_status = DLL_INVALID_PARAM;
|
||||
return;
|
||||
}
|
||||
m_fullpath = PL_strdup(libFullPath);
|
||||
if (m_fullpath == NULL)
|
||||
{
|
||||
// No more memory
|
||||
m_status = DLL_NO_MEM;
|
||||
return;
|
||||
}
|
||||
|
||||
m_status = DLL_OK;
|
||||
}
|
||||
|
||||
nsDll::~nsDll(void)
|
||||
{
|
||||
if (m_instance != NULL)
|
||||
Unload();
|
||||
if (m_fullpath != NULL) PL_strfree(m_fullpath);
|
||||
m_fullpath = NULL;
|
||||
}
|
||||
|
||||
|
||||
PRBool nsDll::Load(void)
|
||||
{
|
||||
// Of course, this is all buggy, because it uses paths instead of nsFileSpec.
|
||||
// Also, instead of writing yet another converter for path separators, for
|
||||
// pete's sake use the converters in nsFileSpec.h. Thank you.
|
||||
#ifdef XP_MAC
|
||||
char *macFileName = NULL;
|
||||
int loop;
|
||||
#endif
|
||||
|
||||
if (m_status != DLL_OK)
|
||||
{
|
||||
return (PR_FALSE);
|
||||
}
|
||||
if (m_instance != NULL)
|
||||
{
|
||||
// Already loaded
|
||||
return (PR_TRUE);
|
||||
}
|
||||
#ifdef XP_MAC
|
||||
// err = ConvertUnixPathToMacPath(m_fullpath, &macFileName);
|
||||
if ((macFileName = PL_strdup(m_fullpath)) != NULL)
|
||||
{
|
||||
if (macFileName[0] == '/')
|
||||
{
|
||||
for (loop=0; loop<PL_strlen(macFileName); loop++)
|
||||
{
|
||||
if (macFileName[loop] == '/') macFileName[loop] = ':';
|
||||
}
|
||||
m_instance = PR_LoadLibrary(&macFileName[1]); // skip over initial slash
|
||||
}
|
||||
else
|
||||
{
|
||||
m_instance = PR_LoadLibrary(macFileName);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef XP_UNIX
|
||||
// On linux we seem to load multiple copies of the same dll but with different path
|
||||
// like libraptorhtml.so and ./libraptorhtml.so
|
||||
// Until this get fixed right, for now for ./libraptorhtml.so remove the "./"
|
||||
if (m_fullpath[0] == '.' && m_fullpath[1] == '/')
|
||||
m_instance = PR_LoadLibrary( &(m_fullpath[2]) );
|
||||
else
|
||||
#endif /* XP_UNIX */
|
||||
{
|
||||
// This is the only right way of doing this...
|
||||
m_instance = PR_LoadLibrary(m_fullpath);
|
||||
}
|
||||
#endif /* XP_MAC */
|
||||
return ((m_instance == NULL) ? PR_FALSE : PR_TRUE);
|
||||
|
||||
}
|
||||
|
||||
PRBool nsDll::Unload(void)
|
||||
{
|
||||
if (m_status != DLL_OK || m_instance == NULL)
|
||||
return (PR_FALSE);
|
||||
PRStatus ret = PR_UnloadLibrary(m_instance);
|
||||
if (ret == PR_SUCCESS)
|
||||
{
|
||||
m_instance = NULL;
|
||||
return (PR_TRUE);
|
||||
}
|
||||
else
|
||||
return (PR_FALSE);
|
||||
}
|
||||
|
||||
void * nsDll::FindSymbol(const char *symbol)
|
||||
{
|
||||
if (symbol == NULL)
|
||||
return (NULL);
|
||||
|
||||
// If not already loaded, load it now.
|
||||
if (Load() != PR_TRUE)
|
||||
return (NULL);
|
||||
|
||||
return (PR_FindSymbol(m_instance, symbol));
|
||||
}
|
||||
71
mozilla/xpcom/components/xcDll.h
Normal file
71
mozilla/xpcom/components/xcDll.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Dll
|
||||
*
|
||||
* Programmatic representation of a dll. Stores modifiedTime and size for
|
||||
* easy detection of change in dll.
|
||||
*
|
||||
* dp Suresh <dp@netscape.com>
|
||||
*/
|
||||
|
||||
#include "prio.h"
|
||||
#include "prlink.h"
|
||||
|
||||
typedef enum nsDllStatus
|
||||
{
|
||||
DLL_OK = 0,
|
||||
DLL_NO_MEM = 1,
|
||||
DLL_STAT_ERROR = 2,
|
||||
DLL_NOT_FILE = 3,
|
||||
DLL_INVALID_PARAM = 4
|
||||
} nsDllStatus;
|
||||
|
||||
class nsDll
|
||||
{
|
||||
private:
|
||||
char *m_fullpath; // system format full filename of dll
|
||||
PRTime m_lastModTime; // last modified time
|
||||
PRUint32 m_size; // size of the dynamic library
|
||||
PRLibrary *m_instance; // Load instance
|
||||
nsDllStatus m_status; // holds current status
|
||||
|
||||
public:
|
||||
|
||||
nsDll(const char *libFullPath);
|
||||
nsDll(const char *libFullPath, PRTime lastModTime, PRUint32 fileSize);
|
||||
|
||||
~nsDll(void);
|
||||
|
||||
// Status checking on operations completed
|
||||
nsDllStatus GetStatus(void) { return (m_status); }
|
||||
|
||||
// Dll Loading
|
||||
PRBool Load(void);
|
||||
PRBool Unload(void);
|
||||
PRBool IsLoaded(void)
|
||||
{
|
||||
return ((m_instance != 0) ? PR_TRUE : PR_FALSE);
|
||||
}
|
||||
void *FindSymbol(const char *symbol);
|
||||
|
||||
const char *GetFullPath(void) { return (m_fullpath); }
|
||||
PRTime GetLastModifiedTime(void) { return(m_lastModTime); }
|
||||
PRUint32 GetSize(void) { return(m_size); }
|
||||
PRLibrary *GetInstance(void) { return (m_instance); }
|
||||
};
|
||||
87
mozilla/xpcom/components/xcDllStore.cpp
Normal file
87
mozilla/xpcom/components/xcDllStore.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
/* nsDllStore
|
||||
*
|
||||
* Stores dll and their accociated info in a hash keyed on the system format
|
||||
* full dll path name e.g C:\Program Files\Netscape\Program\raptor.dll
|
||||
*
|
||||
* NOTE: dll names are considered to be case sensitive.
|
||||
*/
|
||||
|
||||
#include "xcDllStore.h"
|
||||
|
||||
static PR_CALLBACK PRIntn _deleteDllInfo(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
delete (nsDll *)he->value;
|
||||
return (HT_ENUMERATE_NEXT);
|
||||
}
|
||||
|
||||
nsDllStore::nsDllStore(void) : m_dllHashTable(NULL)
|
||||
{
|
||||
PRUint32 initSize = 128;
|
||||
|
||||
m_dllHashTable = PL_NewHashTable(initSize, PL_HashString,
|
||||
PL_CompareStrings, PL_CompareValues, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
nsDllStore::~nsDllStore(void)
|
||||
{
|
||||
if (m_dllHashTable)
|
||||
{
|
||||
// Delete each of the nsDll stored before deleting the Hash Table
|
||||
PL_HashTableEnumerateEntries(m_dllHashTable, _deleteDllInfo, NULL);
|
||||
PL_HashTableDestroy(m_dllHashTable);
|
||||
}
|
||||
m_dllHashTable = NULL;
|
||||
}
|
||||
|
||||
|
||||
nsDll* nsDllStore::Get(const char *dll)
|
||||
{
|
||||
nsDll *dllInfo = NULL;
|
||||
if (m_dllHashTable)
|
||||
{
|
||||
dllInfo = (nsDll *)PL_HashTableLookup(m_dllHashTable, dll);
|
||||
}
|
||||
return (dllInfo);
|
||||
}
|
||||
|
||||
|
||||
nsDll* nsDllStore::Remove(const char *dll)
|
||||
{
|
||||
if (m_dllHashTable == NULL)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
nsDll *dllInfo = Get(dll);
|
||||
PL_HashTableRemove(m_dllHashTable, dll);
|
||||
return (dllInfo);
|
||||
}
|
||||
|
||||
PRBool nsDllStore::Put(const char *dll, nsDll *dllInfo)
|
||||
{
|
||||
if (m_dllHashTable == NULL)
|
||||
return(PR_FALSE);
|
||||
|
||||
PLHashEntry *entry =
|
||||
PL_HashTableAdd(m_dllHashTable, (void *)dll, (void *)dllInfo);
|
||||
return ((entry != NULL) ? PR_TRUE : PR_FALSE);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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
|
||||
@@ -16,25 +16,34 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "Instruction.h"
|
||||
|
||||
/* nsDllStore
|
||||
*
|
||||
* Stores dll and their accociated info in a hash keyed on the system format
|
||||
* full dll path name e.g C:\Program Files\Netscape\Program\raptor.dll
|
||||
*
|
||||
* NOTE: dll names are considered to be case sensitive.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegister -
|
||||
#include "plhash.h"
|
||||
#include "xcDll.h"
|
||||
|
||||
#ifdef MANUAL_TEMPLATES
|
||||
template class IndexedPool<VirtualRegister>;
|
||||
#endif
|
||||
|
||||
// Set the defining instruction.
|
||||
//
|
||||
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
|
||||
class nsDllStore
|
||||
{
|
||||
if (definingInstruction != NULL) {
|
||||
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
|
||||
return;
|
||||
}
|
||||
definingInstruction = &instruction;
|
||||
}
|
||||
private:
|
||||
PLHashTable *m_dllHashTable;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
nsDllStore(void);
|
||||
~nsDllStore(void);
|
||||
|
||||
// Caller is not expected to delete nsDll returned
|
||||
// The nsDll returned in NOT removed from the hash
|
||||
nsDll* Get(const char *filename);
|
||||
PRBool Put(const char *filename, nsDll *dllInfo);
|
||||
|
||||
// The nsDll returned is removed from the hash
|
||||
// Caller is expected to delete the returned nsDll
|
||||
nsDll* Remove(const char *filename);
|
||||
};
|
||||
117
mozilla/xpcom/doc/ObjectModel.html
Normal file
117
mozilla/xpcom/doc/ObjectModel.html
Normal file
@@ -0,0 +1,117 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="Author" CONTENT="Kipp E.B. Hickman">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (WinNT; I) [Netscape]">
|
||||
<TITLE>Gemini Object Model</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H1>
|
||||
Gemini Object Model</H1>
|
||||
The gemini object model is a cross platform component object model modelled
|
||||
after win32's IUnknown and COM. We do not support a C API to gemini at
|
||||
this time.
|
||||
<H2>
|
||||
nsID</H2>
|
||||
Like OSF's DCE, we use an "interface id" which is a unique identifer which
|
||||
names the interface. The nsID and be used as a key into a cross platform
|
||||
registry service to discover an implementation of an interface. Here is
|
||||
the declaration of nsID:
|
||||
<UL><TT>struct nsID {</TT>
|
||||
<BR><TT> PRUint32 m0;</TT>
|
||||
<BR><TT> PRUint16 m1, m2;</TT>
|
||||
<BR><TT> PRUint8 m3[8];</TT>
|
||||
|
||||
<P><TT> inline nsbool Equals(const nsID& other) const {</TT>
|
||||
<BR><TT> return</TT>
|
||||
<BR><TT> (((PRUint32*) &m0)[0] == ((PRUint32*)
|
||||
&other.m0)[0]) &&</TT>
|
||||
<BR><TT> (((PRUint32*) &m0)[1] == ((PRUint32*)
|
||||
&other.m0)[1]) &&</TT>
|
||||
<BR><TT> (((PRUint32*) &m0)[2] == ((PRUint32*)
|
||||
&other.m0)[2]) &&</TT>
|
||||
<BR><TT> (((PRUint32*) &m0)[3] == ((PRUint32*)
|
||||
&other.m0)[3]);</TT>
|
||||
<BR><TT> }</TT>
|
||||
<BR><TT>};</TT></UL>
|
||||
On windows, the "uuidgen" program (provided with Visual C++) can be used
|
||||
to generate these identifiers.
|
||||
<H2>
|
||||
nsISupports</H2>
|
||||
This is the base class for all component objects. Not all objects are component
|
||||
objects; these rules apply to objects which expose an interface which is
|
||||
shared across dll/exe boundaries. Here is nsISupports:
|
||||
<UL><TT>typedef nsID nsIID;</TT>
|
||||
<BR><TT>class nsISupports {</TT>
|
||||
<BR><TT>public:</TT>
|
||||
<BR><TT> virtual nsqresult QueryInterface(const nsIID& aIID,</TT>
|
||||
<BR><TT>
|
||||
void** aInstancePtr) = 0;</TT>
|
||||
<BR><TT> virtual nsrefcnt AddRef() = 0;</TT>
|
||||
<BR><TT> virtual nsrefcnt Release() = 0;</TT>
|
||||
<BR><TT>};</TT></UL>
|
||||
The semantics of this interface are identical to win32's "COM" IUnknown
|
||||
interface. In addition, the types are carefully mapped and the names are
|
||||
the same so that if necessary we can "flip a switch" and have the windows
|
||||
version (or any other platform that embraces COM) use the native COM IUnknown
|
||||
without source code modification.
|
||||
<H2>
|
||||
Factory Procedures</H2>
|
||||
Factory procedures use this design pattern
|
||||
<UL><TT>nsqresult NS_NewFoo(nsIFoo** aInstancePtr, nsISupports* aOuter,
|
||||
...);</TT></UL>
|
||||
The return value is a status value (see nsISupports.h for the legal return
|
||||
values); the first argument is a pointer to a cell which will hold the
|
||||
new instance pointer if the factory procedure succeeds. The second argument
|
||||
is a pointer to a containing component object that wishes to aggregate
|
||||
in the Foo object. This pointer will be null if no aggregation is requested.
|
||||
If the factory procedure cannot support aggregation of the Foo type then
|
||||
it fails and returns an error if aggregation is requested.
|
||||
|
||||
<P>The following symbols are defined for standard error return values from
|
||||
<TT>QueryInterface</TT> and from factory procedures:
|
||||
<UL><TT>#define NS_FAILED(_nsresult) ((_nsresult) < 0)</TT>
|
||||
<BR><TT>#define NS_SUCCEEDED(_nsresult) ((_nsresult) >= 0)</TT>
|
||||
|
||||
<P><TT>// Standard "it worked" return value</TT>
|
||||
<BR><TT>#define NS_OK 0</TT>
|
||||
|
||||
<P><TT>// Some standard error codes we use</TT>
|
||||
<BR><TT>#define NS_ERROR_BASE ((nsresult) 0xC1F30000)</TT>
|
||||
<BR><TT>#define NS_ERROR_OUT_OF_MEMORY (NS_ERROR_BASE + 0)</TT>
|
||||
<BR><TT>#define NS_ERROR_NO_AGGREGATION (NS_ERROR_BASE + 1)</TT>
|
||||
<BR><TT>#define NS_NOINTERFACE ((nqresult) 0x80004002L)</TT></UL>
|
||||
|
||||
<H2>
|
||||
nsIFactory</H2>
|
||||
Factory classes should eventually replace factory procedures for major
|
||||
classes. They provide an easy mechanism for placing code in DLLs. The nsIFactory
|
||||
class is as follows:
|
||||
<BR>
|
||||
<UL><TT>class nsIFactory: public nsISupports {</TT>
|
||||
<BR><TT>public:</TT>
|
||||
<UL><TT>virtual nsresult CreateInstance(const nsIID &aIID,</TT>
|
||||
<BR><TT>
|
||||
nsISupports *aOuter,</TT>
|
||||
<BR><TT>
|
||||
void **aResult) = 0;</TT>
|
||||
<BR><TT>virtual void LockFactory(PRBool aLock) = 0;</TT></UL>
|
||||
<TT>};</TT></UL>
|
||||
This interface is again identical to the COM version. More on registering
|
||||
factories shortly.
|
||||
<H2>
|
||||
Error Handling</H2>
|
||||
Because no exceptions are returned, error handling is done in the traditional
|
||||
"error status value" method.
|
||||
<H2>
|
||||
Cross Platform Registry</H2>
|
||||
A cross platform registry was written for the SmartUpdate feature of Communicator.
|
||||
We will investigate it's usefulness for our purposes.
|
||||
<H2>
|
||||
Library Management</H2>
|
||||
NSPR 2.x provides the cross platform mechanism for loading and unloading
|
||||
libraries, and run time linking.
|
||||
<BR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
93
mozilla/xpcom/doc/c++tips.html
Normal file
93
mozilla/xpcom/doc/c++tips.html
Normal file
@@ -0,0 +1,93 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="Author" CONTENT="Kipp E.B. Hickman">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (WinNT; U) [Netscape]">
|
||||
<TITLE>C++ Tips</TITLE>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
|
||||
<H1>
|
||||
C++ Tips</H1>
|
||||
This is a compilation of tips on how to write cross-platform C++ code that
|
||||
compiles everywhere.
|
||||
<H2>
|
||||
General</H2>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
Always use the nspr types for intrinsic integer types. The only exception
|
||||
to this rule is when writing machine dependent code that is called from
|
||||
xp code. In this case you will probably need to bridge the type systems
|
||||
and cast from an nspr type to a native type. The other exception is floating
|
||||
point; nspr defines PRFloat as a double (!).</LI>
|
||||
|
||||
<LI>
|
||||
Exceptions do not work everywhere so don't use them anywhere except in
|
||||
machine specific code, and then if you do use them in machine specific
|
||||
code you must catch all exceptions there because you can't throw the exception
|
||||
across xp code.</LI>
|
||||
|
||||
<LI>
|
||||
Templates do not work everywhere so don't use them anywhere.</LI>
|
||||
|
||||
<LI>
|
||||
Do not wrap include statements with an #ifdef. The reason is that when
|
||||
the symbol is not defined, other compiler symbols will not be defined and
|
||||
it will be hard to test the code on all platforms. An example of what <B>not</B>
|
||||
to do:</LI>
|
||||
|
||||
<BR>
|
||||
<UL><TT>#ifdef X</TT>
|
||||
<BR><TT>#include "foo.h"</TT>
|
||||
<BR><TT>#endif</TT>
|
||||
<BR><TT></TT> </UL>
|
||||
|
||||
<LI>
|
||||
For types that do not need operator= or a copy constructor, declare them
|
||||
yourselves and make them private. Example:</LI>
|
||||
|
||||
<BR>
|
||||
<UL><TT>class foo {</TT>
|
||||
<BR><TT>...</TT>
|
||||
<BR><TT>private:</TT>
|
||||
<BR><TT> // These are not supported and are not implemented!</TT>
|
||||
<BR><TT> foo(const foo& x);</TT>
|
||||
<BR><TT> foo& operator=(const foo& x);</TT>
|
||||
<BR><TT>};</TT></UL>
|
||||
|
||||
<LI>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
<H2>
|
||||
Windows Compatability</H2>
|
||||
|
||||
<H2>
|
||||
Metroworks Compatability</H2>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
MAC compilers do not handle #include path names in the same manner as other
|
||||
systems. Consequently #include statements should not contain path names,
|
||||
just simple file names. An example of what <B>not</B> to do:</LI>
|
||||
|
||||
<BR>
|
||||
<UL>#include "gemini/nsICSSParser.h"
|
||||
<BR> </UL>
|
||||
|
||||
<LI>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
<H2>
|
||||
G++ Compatability</H2>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
Use void in argument lists for functions that have no arguments (this works
|
||||
around a bug in g++ 2.6.3)</LI>
|
||||
</UL>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
175
mozilla/xpcom/ds/nsHashtable.cpp
Normal file
175
mozilla/xpcom/ds/nsHashtable.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "prmem.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
//
|
||||
// Key operations
|
||||
//
|
||||
|
||||
static PR_CALLBACK PLHashNumber _hashValue(const void *key)
|
||||
{
|
||||
return ((const nsHashKey *) key)->HashValue();
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashKeyCompare(const void *key1, const void *key2) {
|
||||
return ((const nsHashKey *) key1)->Equals((const nsHashKey *) key2);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashValueCompare(const void *value1,
|
||||
const void *value2) {
|
||||
// We're not going to make any assumptions about value equality
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Memory callbacks
|
||||
//
|
||||
|
||||
static PR_CALLBACK void *_hashAllocTable(void *pool, PRSize size) {
|
||||
return PR_MALLOC(size);
|
||||
}
|
||||
|
||||
static PR_CALLBACK void _hashFreeTable(void *pool, void *item) {
|
||||
PR_DELETE(item);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PLHashEntry *_hashAllocEntry(void *pool, const void *key) {
|
||||
return PR_NEW(PLHashEntry);
|
||||
}
|
||||
|
||||
static PR_CALLBACK void _hashFreeEntry(void *pool, PLHashEntry *entry,
|
||||
PRUintn flag) {
|
||||
if (flag == HT_FREE_ENTRY) {
|
||||
delete (nsHashKey *) (entry->key);
|
||||
PR_DELETE(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static PLHashAllocOps _hashAllocOps = {
|
||||
_hashAllocTable, _hashFreeTable,
|
||||
_hashAllocEntry, _hashFreeEntry
|
||||
};
|
||||
|
||||
//
|
||||
// Enumerator callback
|
||||
//
|
||||
|
||||
struct _HashEnumerateArgs {
|
||||
nsHashtableEnumFunc fn;
|
||||
void* arg;
|
||||
};
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerate(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
_HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
|
||||
return thunk->fn((nsHashKey *) he->key, he->value, thunk->arg)
|
||||
? HT_ENUMERATE_NEXT
|
||||
: HT_ENUMERATE_STOP;
|
||||
}
|
||||
|
||||
//
|
||||
// HashKey
|
||||
//
|
||||
nsHashKey::nsHashKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsHashKey::~nsHashKey(void)
|
||||
{
|
||||
}
|
||||
|
||||
nsHashtable::nsHashtable(PRUint32 aInitSize) {
|
||||
hashtable = PL_NewHashTable(aInitSize,
|
||||
_hashValue,
|
||||
_hashKeyCompare,
|
||||
_hashValueCompare,
|
||||
&_hashAllocOps,
|
||||
NULL);
|
||||
}
|
||||
|
||||
nsHashtable::~nsHashtable() {
|
||||
PL_HashTableDestroy(hashtable);
|
||||
}
|
||||
|
||||
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
|
||||
void *res = NULL;
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
he->value = aData;
|
||||
} else {
|
||||
PL_HashTableRawAdd(hashtable, hep, hash,
|
||||
(void *) aKey->Clone(), aData);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *nsHashtable::Get(nsHashKey *aKey) {
|
||||
return PL_HashTableLookup(hashtable, (void *) aKey);
|
||||
}
|
||||
|
||||
void *nsHashtable::Remove(nsHashKey *aKey) {
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
void *res = NULL;
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
PL_HashTableRawRemove(hashtable, hep, he);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerateCopy(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
nsHashtable *newHashtable = (nsHashtable *)arg;
|
||||
newHashtable->Put((nsHashKey *) he->key, he->value);
|
||||
return HT_ENUMERATE_NEXT;
|
||||
}
|
||||
|
||||
nsHashtable * nsHashtable::Clone() {
|
||||
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries);
|
||||
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateCopy, newHashTable);
|
||||
return newHashTable;
|
||||
}
|
||||
|
||||
void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure) {
|
||||
_HashEnumerateArgs thunk;
|
||||
thunk.fn = aEnumFunc;
|
||||
thunk.arg = closure;
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerate, &thunk);
|
||||
}
|
||||
|
||||
static PR_CALLBACK PRIntn _hashEnumerateRemove(PLHashEntry *he, PRIntn i, void *arg)
|
||||
{
|
||||
return HT_ENUMERATE_REMOVE;
|
||||
}
|
||||
|
||||
void nsHashtable::Reset() {
|
||||
PL_HashTableEnumerateEntries(hashtable, _hashEnumerateRemove, NULL);
|
||||
}
|
||||
|
||||
141
mozilla/xpcom/ds/nsHashtable.h
Normal file
141
mozilla/xpcom/ds/nsHashtable.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsHashtable_h__
|
||||
#define nsHashtable_h__
|
||||
|
||||
#include "plhash.h"
|
||||
#include "nsCom.h"
|
||||
|
||||
class NS_COM nsHashKey {
|
||||
protected:
|
||||
nsHashKey(void);
|
||||
public:
|
||||
virtual ~nsHashKey(void);
|
||||
virtual PRUint32 HashValue(void) const = 0;
|
||||
virtual PRBool Equals(const nsHashKey *aKey) const = 0;
|
||||
virtual nsHashKey *Clone(void) const = 0;
|
||||
};
|
||||
|
||||
// Enumerator callback function. Use
|
||||
|
||||
typedef PRBool (*nsHashtableEnumFunc)(nsHashKey *aKey, void *aData, void* closure);
|
||||
|
||||
class NS_COM nsHashtable {
|
||||
private:
|
||||
// members
|
||||
PLHashTable *hashtable;
|
||||
|
||||
public:
|
||||
nsHashtable(PRUint32 aSize = 256);
|
||||
~nsHashtable();
|
||||
|
||||
PRInt32 Count(void) { return hashtable->nentries; }
|
||||
void *Put(nsHashKey *aKey, void *aData);
|
||||
void *Get(nsHashKey *aKey);
|
||||
void *Remove(nsHashKey *aKey);
|
||||
nsHashtable *Clone();
|
||||
void Enumerate(nsHashtableEnumFunc aEnumFunc, void* closure = NULL);
|
||||
void Reset();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsISupportsKey: Where keys are nsISupports objects that get refcounted.
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
class nsISupportsKey : public nsHashKey {
|
||||
private:
|
||||
nsISupports* mKey;
|
||||
|
||||
public:
|
||||
nsISupportsKey(nsISupports* key) {
|
||||
mKey = key;
|
||||
NS_IF_ADDREF(mKey);
|
||||
}
|
||||
|
||||
~nsISupportsKey(void) {
|
||||
NS_IF_RELEASE(mKey);
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return (PRUint32)mKey;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mKey == ((nsISupportsKey *) aKey)->mKey);
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsISupportsKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsVoidKey: Where keys are void* objects that don't get refcounted.
|
||||
|
||||
class nsVoidKey : public nsHashKey {
|
||||
private:
|
||||
const void* mKey;
|
||||
|
||||
public:
|
||||
nsVoidKey(const void* key) {
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return (PRUint32)mKey;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mKey == ((const nsVoidKey *) aKey)->mKey);
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsVoidKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIDKey: Where keys are nsIDs (e.g. nsIID, nsCID).
|
||||
|
||||
#include "nsID.h"
|
||||
|
||||
class nsIDKey : public nsHashKey {
|
||||
private:
|
||||
nsID mID;
|
||||
|
||||
public:
|
||||
nsIDKey(const nsID &aID) {
|
||||
mID = aID;
|
||||
}
|
||||
|
||||
PRUint32 HashValue(void) const {
|
||||
return mID.m0;
|
||||
}
|
||||
|
||||
PRBool Equals(const nsHashKey *aKey) const {
|
||||
return (mID.Equals(((const nsIDKey *) aKey)->mID));
|
||||
}
|
||||
|
||||
nsHashKey *Clone(void) const {
|
||||
return new nsIDKey(mID);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
61
mozilla/xpcom/ds/nsICollection.h
Normal file
61
mozilla/xpcom/ds/nsICollection.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* 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 specifzic 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 nsICollection_h___
|
||||
#define nsICollection_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
// IID for the nsICollection interface
|
||||
#define NS_ICOLLECTION_IID \
|
||||
{ 0xaeca730, 0x835b, 0x11d2, \
|
||||
{ 0x8f, 0x30, 0x0, 0x60, 0x8, 0x31, 0x1, 0x94 } }
|
||||
|
||||
|
||||
// IID for the nsICollection Factort interface
|
||||
#define NS_ICOLLECTIONFACTORY_IID \
|
||||
{ 0xf8052641, 0x8768, 0x11d2, \
|
||||
{ 0x8f, 0x39, 0x0, 0x60, 0x8, 0x31, 0x1, 0x94 } }
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/** nsICollection Interface
|
||||
* this may be ordered or not. a list or array, the implementation is opaque
|
||||
*/
|
||||
class nsICollection : public nsISupports {
|
||||
public:
|
||||
|
||||
static const nsIID& IID() { static nsIID iid = NS_ICOLLECTION_IID; return iid; }
|
||||
|
||||
/** AddItem will take an ISupports and keep track of it
|
||||
* @param aItem is the Item to be added WILL BE ADDREFFED
|
||||
*/
|
||||
virtual nsresult AddItem(nsISupports *aItem)=0;
|
||||
|
||||
/** RemoveItem will take an nsISupports and remove it from the collection
|
||||
* @param aItem is the item to be removed WILL BE RELEASED
|
||||
*/
|
||||
virtual nsresult RemoveItem(nsISupports *aItem)=0;
|
||||
|
||||
/** Clear will clear all items from list
|
||||
*/
|
||||
virtual nsresult Clear()=0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* nsICollection_h___ */
|
||||
|
||||
65
mozilla/xpcom/ds/nsIEnumerator.h
Normal file
65
mozilla/xpcom/ds/nsIEnumerator.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsIEnumerator_h___
|
||||
#define nsIEnumerator_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
// {646F4FB0-B1F2-11d1-AA29-000000000000}
|
||||
#define NS_IENUMERATOR_IID \
|
||||
{0x646f4fb0, 0xb1f2, 0x11d1, \
|
||||
{ 0xaa, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
|
||||
|
||||
|
||||
class nsIEnumerator : public nsISupports {
|
||||
public:
|
||||
|
||||
static const nsIID& IID() { static nsIID iid = NS_IENUMERATOR_IID; return iid; }
|
||||
|
||||
/** First will reset the list. will return NS_FAILED if no items
|
||||
*/
|
||||
NS_IMETHOD First()=0;
|
||||
|
||||
/** Last will reset the list to the end. will return NS_FAILED if no items
|
||||
*/
|
||||
NS_IMETHOD Last()=0;
|
||||
|
||||
/** Next will advance the list. will return failed if allready at end
|
||||
*/
|
||||
NS_IMETHOD Next()=0;
|
||||
|
||||
/** Prev will decrement the list. will return failed if allready at beginning
|
||||
*/
|
||||
NS_IMETHOD Prev()=0;
|
||||
|
||||
/** CurrentItem will return the CurrentItem item it will fail if the list is empty
|
||||
* @param aItem return value
|
||||
*/
|
||||
NS_IMETHOD CurrentItem(nsISupports **aItem)=0;
|
||||
|
||||
/** return if the collection is at the end. that is the beginning following a call to Prev
|
||||
* and it is the end of the list following a call to next
|
||||
* @param aItem return value
|
||||
*/
|
||||
NS_IMETHOD IsDone()=0;
|
||||
|
||||
};
|
||||
|
||||
#endif // __nsIEnumerator_h
|
||||
|
||||
77
mozilla/xpcom/ds/nsISupportsArray.h
Normal file
77
mozilla/xpcom/ds/nsISupportsArray.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsISupportsArray_h___
|
||||
#define nsISupportsArray_h___
|
||||
|
||||
#include "nsCom.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
// {791eafa0-b9e6-11d1-8031-006008159b5a}
|
||||
#define NS_ISUPPORTSARRAY_IID \
|
||||
{0x791eafa0, 0xb9e6, 0x11d1, \
|
||||
{0x80, 0x31, 0x00, 0x60, 0x08, 0x15, 0x9b, 0x5a}}
|
||||
|
||||
// Enumerator callback function. Return PR_FALSE to stop
|
||||
typedef PRBool (*nsISupportsArrayEnumFunc)(nsISupports* aElement, void *aData);
|
||||
|
||||
class nsISupportsArray : public nsISupports {
|
||||
public:
|
||||
static const nsIID& IID() { static nsIID iid = NS_ISUPPORTSARRAY_IID; return iid; }
|
||||
|
||||
NS_IMETHOD_(nsISupportsArray&) operator=(const nsISupportsArray& other) = 0;
|
||||
NS_IMETHOD_(PRBool) operator==(const nsISupportsArray& other) const = 0;
|
||||
NS_IMETHOD_(PRBool) Equals(const nsISupportsArray* other) const = 0;
|
||||
|
||||
NS_IMETHOD_(PRInt32) Count(void) const = 0;
|
||||
|
||||
NS_IMETHOD_(nsISupports*) ElementAt(PRInt32 aIndex) const = 0;
|
||||
NS_IMETHOD_(nsISupports*) operator[](PRInt32 aIndex) const = 0;
|
||||
|
||||
NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement, PRInt32 aStartIndex = 0) const = 0;
|
||||
NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement) const = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRInt32 aIndex) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRInt32 aIndex) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElement(nsISupports* aElement) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) RemoveElementAt(PRInt32 aIndex) = 0;
|
||||
NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRInt32 aStartIndex = 0) = 0;
|
||||
NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements) = 0;
|
||||
|
||||
NS_IMETHOD_(void) Clear(void) = 0;
|
||||
|
||||
NS_IMETHOD_(void) Compact(void) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) const = 0;
|
||||
NS_IMETHOD_(PRBool) EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) const = 0;
|
||||
|
||||
private:
|
||||
// Copy constructors are not allowed
|
||||
// XXX test wether this has to be here nsISupportsArray(const nsISupportsArray& other);
|
||||
};
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult);
|
||||
|
||||
|
||||
#endif // nsISupportsArray_h___
|
||||
382
mozilla/xpcom/ds/nsSupportsArray.cpp
Normal file
382
mozilla/xpcom/ds/nsSupportsArray.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "nsISupportsArray.h"
|
||||
|
||||
static NS_DEFINE_IID(kISupportsArrayIID, NS_ISUPPORTSARRAY_IID);
|
||||
|
||||
static const PRInt32 kGrowArrayBy = 8;
|
||||
static const PRInt32 kAutoArraySize = 4;
|
||||
|
||||
class SupportsArrayImpl : public nsISupportsArray {
|
||||
public:
|
||||
SupportsArrayImpl(void);
|
||||
~SupportsArrayImpl(void);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD_(nsISupportsArray&) operator=(const nsISupportsArray& aOther);
|
||||
NS_IMETHOD_(PRBool) operator==(const nsISupportsArray& aOther) const { return Equals(&aOther); }
|
||||
NS_IMETHOD_(PRBool) Equals(const nsISupportsArray* aOther) const;
|
||||
|
||||
NS_IMETHOD_(PRInt32) Count(void) const { return mCount; }
|
||||
|
||||
NS_IMETHOD_(nsISupports*) ElementAt(PRInt32 aIndex) const;
|
||||
NS_IMETHOD_(nsISupports*) operator[](PRInt32 aIndex) const { return ElementAt(aIndex); }
|
||||
|
||||
NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement, PRInt32 aStartIndex = 0) const;
|
||||
NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement) const;
|
||||
|
||||
NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRInt32 aIndex);
|
||||
|
||||
NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRInt32 aIndex);
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElement(nsISupports* aElement) {
|
||||
return InsertElementAt(aElement, mCount);
|
||||
}
|
||||
|
||||
NS_IMETHOD_(PRBool) RemoveElementAt(PRInt32 aIndex);
|
||||
NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRInt32 aStartIndex = 0);
|
||||
NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement);
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements);
|
||||
|
||||
NS_IMETHOD_(void) Clear(void);
|
||||
|
||||
NS_IMETHOD_(void) Compact(void);
|
||||
|
||||
NS_IMETHOD_(PRBool) EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) const;
|
||||
NS_IMETHOD_(PRBool) EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) const;
|
||||
|
||||
protected:
|
||||
void DeleteArray(void);
|
||||
|
||||
nsISupports** mArray;
|
||||
PRInt32 mArraySize;
|
||||
PRInt32 mCount;
|
||||
nsISupports* mAutoArray[kAutoArraySize];
|
||||
|
||||
private:
|
||||
// Copy constructors are not allowed
|
||||
SupportsArrayImpl(const nsISupportsArray& other);
|
||||
};
|
||||
|
||||
|
||||
SupportsArrayImpl::SupportsArrayImpl()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mArray = &(mAutoArray[0]);
|
||||
mArraySize = kAutoArraySize;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
SupportsArrayImpl::~SupportsArrayImpl()
|
||||
{
|
||||
DeleteArray();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(SupportsArrayImpl, kISupportsArrayIID);
|
||||
|
||||
void SupportsArrayImpl::DeleteArray(void)
|
||||
{
|
||||
Clear();
|
||||
if (mArray != &(mAutoArray[0])) {
|
||||
delete[] mArray;
|
||||
mArray = &(mAutoArray[0]);
|
||||
mArraySize = kAutoArraySize;
|
||||
}
|
||||
}
|
||||
|
||||
nsISupportsArray& SupportsArrayImpl::operator=(const nsISupportsArray& aOther)
|
||||
{
|
||||
PRInt32 otherCount = aOther.Count();
|
||||
|
||||
if (otherCount > mArraySize) {
|
||||
DeleteArray();
|
||||
mArraySize = otherCount;
|
||||
mArray = new nsISupports*[mArraySize];
|
||||
}
|
||||
else {
|
||||
Clear();
|
||||
}
|
||||
mCount = otherCount;
|
||||
while (0 <= --otherCount) {
|
||||
mArray[otherCount] = aOther.ElementAt(otherCount);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::Equals(const nsISupportsArray* aOther) const
|
||||
{
|
||||
if (0 != aOther) {
|
||||
const SupportsArrayImpl* other = (const SupportsArrayImpl*)aOther;
|
||||
if (mCount == other->mCount) {
|
||||
PRInt32 index = mCount;
|
||||
while (0 <= --index) {
|
||||
if (mArray[index] != other->mArray[index]) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
nsISupports* SupportsArrayImpl::ElementAt(PRInt32 aIndex) const
|
||||
{
|
||||
if ((0 <= aIndex) && (aIndex < mCount)) {
|
||||
nsISupports* element = mArray[aIndex];
|
||||
NS_ADDREF(element);
|
||||
return element;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRInt32 SupportsArrayImpl::IndexOf(const nsISupports* aPossibleElement, PRInt32 aStartIndex) const
|
||||
{
|
||||
if ((0 <= aStartIndex) && (aStartIndex < mCount)) {
|
||||
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
||||
const nsISupports** ep = (start + aStartIndex);
|
||||
const nsISupports** end = (start + mCount);
|
||||
while (ep < end) {
|
||||
if (aPossibleElement == *ep) {
|
||||
return (ep - start);
|
||||
}
|
||||
ep++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRInt32 SupportsArrayImpl::LastIndexOf(const nsISupports* aPossibleElement) const
|
||||
{
|
||||
if (0 < mCount) {
|
||||
const nsISupports** start = (const nsISupports**)mArray; // work around goofy compiler behavior
|
||||
const nsISupports** ep = (start + mCount);
|
||||
while (start <= --ep) {
|
||||
if (aPossibleElement == *ep) {
|
||||
return (ep - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::InsertElementAt(nsISupports* aElement, PRInt32 aIndex)
|
||||
{
|
||||
if ((0 <= aIndex) && (aIndex <= mCount)) {
|
||||
if (mArraySize < (mCount + 1)) { // need to grow the array
|
||||
mArraySize += kGrowArrayBy;
|
||||
nsISupports** oldArray = mArray;
|
||||
mArray = new nsISupports*[mArraySize];
|
||||
if (0 == mArray) { // ran out of memory
|
||||
mArray = oldArray;
|
||||
mArraySize -= kGrowArrayBy;
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (0 != oldArray) { // need to move old data
|
||||
if (0 < aIndex) {
|
||||
::memcpy(mArray, oldArray, aIndex * sizeof(nsISupports*));
|
||||
}
|
||||
PRInt32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memcpy(mArray + aIndex + 1, oldArray + aIndex, slide * sizeof(nsISupports*));
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRInt32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex + 1, mArray + aIndex, slide * sizeof(nsISupports*));
|
||||
}
|
||||
}
|
||||
|
||||
mArray[aIndex] = aElement;
|
||||
NS_ADDREF(aElement);
|
||||
mCount++;
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::ReplaceElementAt(nsISupports* aElement, PRInt32 aIndex)
|
||||
{
|
||||
if ((0 <= aIndex) && (aIndex < mCount)) {
|
||||
NS_ADDREF(aElement); // addref first in case it's the same object!
|
||||
NS_RELEASE(mArray[aIndex]);
|
||||
mArray[aIndex] = aElement;
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::RemoveElementAt(PRInt32 aIndex)
|
||||
{
|
||||
if ((0 <= aIndex) && (aIndex < mCount)) {
|
||||
NS_RELEASE(mArray[aIndex]);
|
||||
mCount--;
|
||||
PRInt32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memmove(mArray + aIndex, mArray + aIndex + 1,
|
||||
slide * sizeof(nsISupports*));
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::RemoveElement(const nsISupports* aElement, PRInt32 aStartIndex)
|
||||
{
|
||||
if ((0 <= aStartIndex) && (aStartIndex < mCount)) {
|
||||
nsISupports** ep = mArray;
|
||||
nsISupports** end = ep + mCount;
|
||||
while (ep < end) {
|
||||
if (*ep == aElement) {
|
||||
return RemoveElementAt(PRInt32(ep - mArray));
|
||||
}
|
||||
ep++;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::RemoveLastElement(const nsISupports* aElement)
|
||||
{
|
||||
if (0 < mCount) {
|
||||
nsISupports** ep = (mArray + mCount);
|
||||
while (mArray <= --ep) {
|
||||
if (*ep == aElement) {
|
||||
return RemoveElementAt(PRInt32(ep - mArray));
|
||||
}
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::AppendElements(nsISupportsArray* aElements)
|
||||
{
|
||||
SupportsArrayImpl* elements = (SupportsArrayImpl*)aElements;
|
||||
|
||||
if (elements && (0 < elements->mCount)) {
|
||||
if (mArraySize < (mCount + elements->mCount)) { // need to grow the array
|
||||
PRInt32 count = mCount + elements->mCount;
|
||||
PRInt32 oldSize = mArraySize;
|
||||
while (mArraySize < count) { // ick
|
||||
mArraySize += kGrowArrayBy;
|
||||
}
|
||||
nsISupports** oldArray = mArray;
|
||||
mArray = new nsISupports*[mArraySize];
|
||||
if (0 == mArray) { // ran out of memory
|
||||
mArray = oldArray;
|
||||
mArraySize = oldSize;
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (0 != oldArray) { // need to move old data
|
||||
if (0 < mCount) {
|
||||
::memcpy(mArray, oldArray, mCount);
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 index = 0;
|
||||
while (index < elements->mCount) {
|
||||
NS_ADDREF(elements->mArray[index]);
|
||||
mArray[mCount++] = elements->mArray[index++];
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
void SupportsArrayImpl::Clear(void)
|
||||
{
|
||||
while (0 <= --mCount) {
|
||||
NS_RELEASE(mArray[mCount]);
|
||||
}
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
void SupportsArrayImpl::Compact(void)
|
||||
{
|
||||
if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
|
||||
nsISupports** oldArray = mArray;
|
||||
PRInt32 oldArraySize = mArraySize;
|
||||
if (mCount <= kAutoArraySize) {
|
||||
mArray = &(mAutoArray[0]);
|
||||
mArraySize = kAutoArraySize;
|
||||
}
|
||||
else {
|
||||
mArray = new nsISupports*[mCount];
|
||||
mArraySize = mCount;
|
||||
}
|
||||
if (0 == mArray) {
|
||||
mArray = oldArray;
|
||||
mArraySize = oldArraySize;
|
||||
return;
|
||||
}
|
||||
::memcpy(mArray, oldArray, mCount * sizeof(nsISupports*));
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) const
|
||||
{
|
||||
PRInt32 index = -1;
|
||||
PRBool running = PR_TRUE;
|
||||
|
||||
while (running && (++index < mCount)) {
|
||||
running = (*aFunc)(mArray[index], aData);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
PRBool SupportsArrayImpl::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) const
|
||||
{
|
||||
PRInt32 index = mCount;
|
||||
PRBool running = PR_TRUE;
|
||||
|
||||
while (running && (0 <= --index)) {
|
||||
running = (*aFunc)(mArray[index], aData);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
|
||||
{
|
||||
if (aInstancePtrResult == 0) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
SupportsArrayImpl *it = new SupportsArrayImpl();
|
||||
|
||||
if (0 == it) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return it->QueryInterface(kISupportsArrayIID, (void **) aInstancePtrResult);
|
||||
}
|
||||
|
||||
74
mozilla/xpcom/ds/nsVector.h
Normal file
74
mozilla/xpcom/ds/nsVector.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* -*- 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 nsVector_h__
|
||||
#define nsVector_h__
|
||||
|
||||
#include "plvector.h"
|
||||
#include "nsCom.h"
|
||||
|
||||
class nsVector : public PLVector {
|
||||
public:
|
||||
// Construction
|
||||
nsVector(PRUint32 initialSize = 0, PRInt32 initialGrowBy = 0) {
|
||||
PL_VectorInitialize(this, initialSize, initialGrowBy);
|
||||
}
|
||||
~nsVector(void) { PL_VectorFinalize(this); }
|
||||
|
||||
// Attributes
|
||||
PRUint32 GetSize(void) const { return PL_VectorGetSize(this); }
|
||||
PRUint32 GetUpperBound(void) const { return GetSize() - 1; }
|
||||
PRBool SetSize(PRUint32 nNewSize, PRInt32 nGrowBy = PL_VECTOR_GROW_DEFAULT) {
|
||||
return PL_VectorSetSize(this, nNewSize, nGrowBy);
|
||||
}
|
||||
PRBool IsValidIndex(PRUint32 index) { return PL_VectorIsValidIndex(this, index); }
|
||||
|
||||
// Operations
|
||||
// Clean up
|
||||
void Compact(void) { PL_VectorCompact(this); }
|
||||
void RemoveAll(void) { SetSize(0); }
|
||||
void Copy(nsVector* src, PRUint32 len, PRUint32 dstPos = 0, PRUint32 srcPos = 0) {
|
||||
PL_VectorCopy(this, dstPos, src, srcPos, len);
|
||||
}
|
||||
|
||||
// Accessing elements
|
||||
void* Get(PRUint32 index) const { return PL_VectorGet(this, index); }
|
||||
void Set(PRUint32 index, void* newElement) { PL_VectorSet(this, index, newElement); }
|
||||
void*& ElementAt(PRUint32 index) { return *PL_VectorGetAddr(this, index); }
|
||||
|
||||
// Potentially growing the array
|
||||
PRInt32 Add(void* newElement) { return PL_VectorAdd(this, newElement); }
|
||||
|
||||
// overloaded operator helpers
|
||||
void* operator[](PRUint32 index) const { return Get(index); }
|
||||
void*& operator[](PRUint32 index) { return ElementAt(index); }
|
||||
|
||||
// Operations that move elements around
|
||||
void Insert(PRUint32 index, void* newElement, PRInt32 count = 1) {
|
||||
PL_VectorInsert(this, index, newElement, count);
|
||||
}
|
||||
void Remove(PRUint32 index, PRInt32 count = 1) {
|
||||
PL_VectorRemove(this, index, count);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void AssertValid(void) const { PL_VectorAssertValid((PLVector*)this); }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
318
mozilla/xpcom/ds/plvector.c
Normal file
318
mozilla/xpcom/ds/plvector.c
Normal file
@@ -0,0 +1,318 @@
|
||||
/* -*- 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 "plvector.h"
|
||||
#include "prmem.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef XP_WIN16
|
||||
#define SIZE_T_MAX 0xFF80 /* a little less than 64K, the max alloc size on win16. */
|
||||
#define MAX_ARR_ELEMS SIZE_T_MAX/sizeof(void*)
|
||||
#endif
|
||||
|
||||
PR_IMPLEMENT(PLVector*)
|
||||
PL_NewVector(PRUint32 initialSize, PRInt32 initialGrowBy)
|
||||
{
|
||||
PLVector* v = (PLVector*)PR_Malloc(sizeof(PLVector*));
|
||||
if (v == NULL)
|
||||
return NULL;
|
||||
PL_VectorInitialize(v, initialSize, initialGrowBy);
|
||||
return v;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorDestroy(PLVector* v)
|
||||
{
|
||||
PL_VectorFinalize(v);
|
||||
PR_Free(v);
|
||||
}
|
||||
|
||||
/* Initializes an existing vector */
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorInitialize(PLVector* v, PRUint32 initialSize, PRInt32 initialGrowBy)
|
||||
{
|
||||
v->data = NULL;
|
||||
v->size = v->maxSize = v->growBy = 0;
|
||||
if (initialSize > 0 || initialGrowBy > 0)
|
||||
PL_VectorSetSize(v, initialSize, initialGrowBy);
|
||||
}
|
||||
|
||||
/* Destroys the elements, but doesn't free the vector */
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorFinalize(PLVector* v)
|
||||
{
|
||||
/* This implementation doesn't do anything to delete the elements
|
||||
in the vector -- that's up to the caller. (Don't shoot me,
|
||||
I just copied the code from libmsg.) */
|
||||
PR_Free(v->data);
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(PRBool)
|
||||
PL_VectorSetSize(PLVector* v, PRUint32 newSize, PRInt32 growBy)
|
||||
{
|
||||
if (growBy != -1)
|
||||
v->growBy = growBy; /* set new size */
|
||||
|
||||
if (newSize == 0) {
|
||||
/* shrink to nothing */
|
||||
PR_Free(v->data);
|
||||
v->data = NULL;
|
||||
v->size = v->maxSize = 0;
|
||||
}
|
||||
else if (v->data == NULL) {
|
||||
/* create one with exact size */
|
||||
#ifdef SIZE_T_MAX
|
||||
PR_ASSERT(newSize <= SIZE_T_MAX/sizeof(void*)); /* no overflow */
|
||||
#endif
|
||||
v->data = (void**)PR_Malloc(newSize * sizeof(void *));
|
||||
if (v->data == NULL) {
|
||||
v->size = 0;
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
memset(v->data, 0, newSize * sizeof(void *)); /* zero fill */
|
||||
|
||||
v->size = v->maxSize = newSize;
|
||||
}
|
||||
else if (newSize <= v->maxSize) {
|
||||
/* it fits */
|
||||
if (newSize > v->size) {
|
||||
/* initialize the new elements */
|
||||
|
||||
memset(&v->data[v->size], 0, (newSize-v->size) * sizeof(void *));
|
||||
}
|
||||
v->size = newSize;
|
||||
}
|
||||
else {
|
||||
/* otherwise, grow array */
|
||||
PRUint32 newMax;
|
||||
void** newData;
|
||||
PRInt32 growBy = v->growBy;
|
||||
if (growBy == 0) {
|
||||
/* heuristically determine growth when growBy == 0
|
||||
(this avoids heap fragmentation in many situations) */
|
||||
growBy = PR_MIN(1024, PR_MAX(4, v->size / 8));
|
||||
}
|
||||
#ifdef MAX_ARR_ELEMS
|
||||
if (v->size + growBy > MAX_ARR_ELEMS)
|
||||
growBy = MAX_ARR_ELEMS - v->size;
|
||||
#endif
|
||||
if (newSize < v->maxSize + growBy)
|
||||
newMax = v->maxSize + growBy; /* granularity */
|
||||
else
|
||||
newMax = newSize; /* no slush */
|
||||
|
||||
#ifdef SIZE_T_MAX
|
||||
if (newMax >= SIZE_T_MAX/sizeof(void*))
|
||||
return PR_FALSE;
|
||||
PR_ASSERT(newMax <= SIZE_T_MAX/sizeof(void*)); /* no overflow */
|
||||
#endif
|
||||
PR_ASSERT(newMax >= v->maxSize); /* no wrap around */
|
||||
newData = (void**)PR_Malloc(newMax * sizeof(void*));
|
||||
|
||||
if (newData != NULL) {
|
||||
/* copy new data from old */
|
||||
memcpy(newData, v->data, v->size * sizeof(void*));
|
||||
|
||||
/* construct remaining elements */
|
||||
PR_ASSERT(newSize > v->size);
|
||||
|
||||
memset(&newData[v->size], 0, (newSize-v->size) * sizeof(void*));
|
||||
|
||||
/* get rid of old stuff (note: no destructors called) */
|
||||
PR_Free(v->data);
|
||||
v->data = newData;
|
||||
v->size = newSize;
|
||||
v->maxSize = newMax;
|
||||
}
|
||||
else {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(PRBool)
|
||||
PL_VectorIsValidIndex(PLVector* v, PRUint32 index)
|
||||
{
|
||||
return (index < v->size) ? PR_TRUE : PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorCompact(PLVector* v)
|
||||
{
|
||||
if (v->size != v->maxSize) {
|
||||
/* shrink to desired size */
|
||||
#ifdef SIZE_T_MAX
|
||||
PR_ASSERT(v->size <= SIZE_T_MAX/sizeof(void *)); /* no overflow */
|
||||
#endif
|
||||
void ** newData = NULL;
|
||||
if (v->size != 0) {
|
||||
newData = (void **)PR_Malloc(v->size * sizeof(void *));
|
||||
/* copy new data from old */
|
||||
memcpy(newData, v->data, v->size * sizeof(void *));
|
||||
}
|
||||
|
||||
/* get rid of old stuff (note: no destructors called) */
|
||||
PR_Free(v->data);
|
||||
v->data = newData;
|
||||
v->maxSize = v->size;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* becomes Copy */
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorSplice(PLVector* v, PRUint32 startIndex, PLVector* newVector)
|
||||
{
|
||||
PRUint32 i;
|
||||
PR_ASSERT(newVector != NULL);
|
||||
|
||||
if (PL_VectorGetSize(newVector) > 0) {
|
||||
PL_VectorInsert(v, startIndex, PL_VectorGet(newVector, 0),
|
||||
PL_VectorGetSize(newVector));
|
||||
for (i = 0; i < PL_VectorGetSize(newVector); i++)
|
||||
PL_VectorSet(v, startIndex + i, PL_VectorGet(newVector, i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorCopy(PLVector* dstVector, PRUint32 dstPosition,
|
||||
PLVector* srcVector, PRUint32 srcPosition, PRUint32 length)
|
||||
{
|
||||
PR_ASSERT(0); /* XXX not implemented yet */
|
||||
#if 0
|
||||
PL_VectorSetSize(dstVector, PR_MAX(PL_VectorGetSize(dstVector),
|
||||
PL_VectorGetSize(srcVector)),
|
||||
PL_VECTOR_GROW_DEFAULT);
|
||||
|
||||
if (v->data)
|
||||
PR_Free(v->data);
|
||||
v->size = oldA->v->size;
|
||||
v->maxSize = oldA->v->maxSize;
|
||||
v->growBy = oldA->v->growBy;
|
||||
v->data = (void**)PR_Malloc(v->size * sizeof(void *));
|
||||
if (v->data == NULL) {
|
||||
v->size = 0;
|
||||
}
|
||||
else {
|
||||
memcpy(v->data, oldA->v->data, v->size * sizeof(void *));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PR_IMPLEMENT(PLVector*)
|
||||
PL_VectorClone(PLVector* v)
|
||||
{
|
||||
PLVector* newVec = PL_NewVector(v->size, v->growBy);
|
||||
PL_VectorCopy(newVec, 0, v, 0, v->size);
|
||||
return newVec;
|
||||
}
|
||||
|
||||
/* Accessing elements */
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorSet(PLVector* v, PRUint32 index, void* newElement)
|
||||
{
|
||||
if (index >= v->size) {
|
||||
if (!PL_VectorSetSize(v, index+1, PL_VECTOR_GROW_DEFAULT))
|
||||
return;
|
||||
}
|
||||
v->data[index] = newElement;
|
||||
}
|
||||
|
||||
/* Adds at the end */
|
||||
PR_IMPLEMENT(PRUint32)
|
||||
PL_VectorAdd(PLVector* v, void* newElement)
|
||||
{
|
||||
PRUint32 index = v->size;
|
||||
#ifdef XP_WIN16
|
||||
if (index >= SIZE_T_MAX / 4L) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
PL_VectorSet(v, index, newElement);
|
||||
return index;
|
||||
}
|
||||
|
||||
/* Inserts new element count times at index */
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorInsert(PLVector* v, PRUint32 index, void* newElement, PRUint32 count)
|
||||
{
|
||||
PR_ASSERT(count > 0); /* zero or negative size not allowed */
|
||||
|
||||
if (index >= v->size) {
|
||||
/* adding after the end of the array */
|
||||
if (!PL_VectorSetSize(v, index + count, PL_VECTOR_GROW_DEFAULT))
|
||||
return; /* grow so index is valid */
|
||||
}
|
||||
else {
|
||||
/* inserting in the middle of the array */
|
||||
PRUint32 nOldSize = v->size;
|
||||
if (!PL_VectorSetSize(v, v->size + count, PL_VECTOR_GROW_DEFAULT))
|
||||
return; /* grow it to new size */
|
||||
/* shift old data up to fill gap */
|
||||
memmove(&v->data[index+count], &v->data[index],
|
||||
(nOldSize-index) * sizeof(void *));
|
||||
|
||||
/* re-init slots we copied from */
|
||||
memset(&v->data[index], 0, count * sizeof(void *));
|
||||
}
|
||||
|
||||
/* insert new value in the gap */
|
||||
PR_ASSERT(index + count <= v->size);
|
||||
while (count--)
|
||||
v->data[index++] = newElement;
|
||||
}
|
||||
|
||||
/* Removes count elements at index */
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorRemove(PLVector* v, PRUint32 index, PRUint32 count)
|
||||
{
|
||||
PRUint32 moveCount;
|
||||
PR_ASSERT(count >= 0);
|
||||
PR_ASSERT(index + count <= v->size);
|
||||
|
||||
/* just remove a range */
|
||||
moveCount = v->size - (index + count);
|
||||
|
||||
if (moveCount)
|
||||
memmove(&v->data[index], &v->data[index + count],
|
||||
moveCount * sizeof(void *));
|
||||
v->size -= count;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
PR_IMPLEMENT(void)
|
||||
PL_VectorAssertValid(PLVector* v)
|
||||
{
|
||||
if (v->data == NULL) {
|
||||
PR_ASSERT(v->size == 0);
|
||||
PR_ASSERT(v->maxSize == 0);
|
||||
}
|
||||
else {
|
||||
PR_ASSERT(v->size >= 0);
|
||||
PR_ASSERT(v->maxSize >= 0);
|
||||
PR_ASSERT(v->size <= v->maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
100
mozilla/xpcom/ds/plvector.h
Normal file
100
mozilla/xpcom/ds/plvector.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* -*- 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 plvector_h__
|
||||
#define plvector_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "prlog.h"
|
||||
|
||||
PR_BEGIN_EXTERN_C
|
||||
|
||||
/* Vectors are extensible arrays */
|
||||
|
||||
typedef struct PLVector {
|
||||
void** data; /* the actual array of data */
|
||||
PRUint32 size; /* # of elements (upperBound - 1) */
|
||||
PRUint32 maxSize; /* max allocated */
|
||||
PRInt32 growBy; /* grow amount */
|
||||
} PLVector;
|
||||
|
||||
PR_EXTERN(PLVector*)
|
||||
PL_NewVector(PRUint32 initialSize, PRInt32 initialGrowBy);
|
||||
|
||||
PR_EXTERN(void)
|
||||
PL_VectorDestroy(PLVector* v);
|
||||
|
||||
/* Initializes an existing vector */
|
||||
PR_EXTERN(void)
|
||||
PL_VectorInitialize(PLVector* v, PRUint32 initialSize, PRInt32 initialGrowBy);
|
||||
|
||||
/* Destroys the elements, but doesn't free the vector */
|
||||
PR_EXTERN(void)
|
||||
PL_VectorFinalize(PLVector* v);
|
||||
|
||||
#define PL_VectorGetSize(v) ((v)->size)
|
||||
|
||||
#define PL_VECTOR_GROW_DEFAULT (-1)
|
||||
|
||||
PR_EXTERN(PRBool)
|
||||
PL_VectorSetSize(PLVector* v, PRUint32 newSize, PRInt32 growBy);
|
||||
|
||||
PR_EXTERN(PRBool)
|
||||
PL_VectorIsValidIndex(PLVector* v, PRUint32 index);
|
||||
|
||||
PR_EXTERN(void)
|
||||
PL_VectorCompact(PLVector* v);
|
||||
|
||||
PR_EXTERN(void)
|
||||
PL_VectorCopy(PLVector* dstVector, PRUint32 dstPosition,
|
||||
PLVector* srcVector, PRUint32 srcPosition, PRUint32 length);
|
||||
|
||||
PR_EXTERN(PLVector*)
|
||||
PL_VectorClone(PLVector* v);
|
||||
|
||||
/* Accessing elements */
|
||||
|
||||
#define PL_VectorGetAddr(v, index) (PR_ASSERT((index) < (v)->size), &(v)->data[index])
|
||||
|
||||
#define PL_VectorGet(v, index) (*PL_VectorGetAddr(v, index))
|
||||
|
||||
PR_EXTERN(void)
|
||||
PL_VectorSet(PLVector* v, PRUint32 index, void* newElement);
|
||||
|
||||
/* Adds at the end */
|
||||
PR_EXTERN(PRUint32)
|
||||
PL_VectorAdd(PLVector* v, void* newElement);
|
||||
|
||||
/* Inserts new element count times at index */
|
||||
PR_EXTERN(void)
|
||||
PL_VectorInsert(PLVector* v, PRUint32 index, void* newElement, PRUint32 count);
|
||||
|
||||
/* Removes count elements at index */
|
||||
PR_EXTERN(void)
|
||||
PL_VectorRemove(PLVector* v, PRUint32 index, PRUint32 count);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
PR_EXTERN(void)
|
||||
PL_VectorAssertValid(PLVector* v);
|
||||
|
||||
#endif
|
||||
|
||||
PR_END_EXTERN_C
|
||||
|
||||
#endif /* plvector_h__ */
|
||||
54
mozilla/xpcom/glue/nsCOMPtr.cpp
Normal file
54
mozilla/xpcom/glue/nsCOMPtr.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "nsCOMPtr.h"
|
||||
|
||||
void
|
||||
nsCOMPtr_base::assign_with_AddRef( nsISupports* rawPtr )
|
||||
{
|
||||
if ( rawPtr )
|
||||
NSCAP_ADDREF(rawPtr);
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = rawPtr;
|
||||
}
|
||||
|
||||
void
|
||||
nsCOMPtr_base::assign_with_QueryInterface( nsISupports* rawPtr, const nsIID& iid, nsresult* result )
|
||||
{
|
||||
nsresult status = NS_OK;
|
||||
if ( !rawPtr || !NS_SUCCEEDED( status = rawPtr->QueryInterface(iid, NSCAP_REINTERPRET_CAST(void**, &rawPtr)) ) )
|
||||
rawPtr = 0;
|
||||
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
|
||||
mRawPtr = rawPtr;
|
||||
|
||||
if ( result )
|
||||
*result = status;
|
||||
}
|
||||
|
||||
void**
|
||||
nsCOMPtr_base::begin_assignment()
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = 0;
|
||||
return NSCAP_REINTERPRET_CAST(void**, &mRawPtr);
|
||||
}
|
||||
668
mozilla/xpcom/glue/nsCOMPtr.h
Normal file
668
mozilla/xpcom/glue/nsCOMPtr.h
Normal file
@@ -0,0 +1,668 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsCOMPtr_h___
|
||||
#define nsCOMPtr_h___
|
||||
|
||||
|
||||
|
||||
// Wrapping includes can speed up compiles (see "Large Scale C++ Software Design")
|
||||
#ifndef nsDebug_h___
|
||||
#include "nsDebug.h"
|
||||
// for |NS_PRECONDITION|
|
||||
#endif
|
||||
|
||||
#ifndef nsISupports_h___
|
||||
#include "nsISupports.h"
|
||||
// for |nsresult|, |NS_ADDREF|, et al
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
TO DO...
|
||||
|
||||
+ make alternative function for |getter_AddRefs| (or something)
|
||||
+ make constructor for |nsQueryInterface| explicit (suddenly construct/assign from raw pointer becomes illegal)
|
||||
+ Improve internal documentation
|
||||
+ mention *&
|
||||
+ alternatives for comparison
|
||||
+ do_QueryInterface
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* USER MANUAL
|
||||
|
||||
See also:
|
||||
<http://www.meer.net/ScottCollins/doc/nsCOMPtr.html>, or
|
||||
<http://www.mozilla.org/projects/xpcom/nsCOMPtr.html>
|
||||
|
||||
What is |nsCOMPtr|?
|
||||
|
||||
|nsCOMPtr| is a `smart-pointer'. It is a template class that acts, syntactically,
|
||||
just like an ordinary pointer in C or C++, i.e., you can apply |*| or |->| to it to
|
||||
`get to' what it points at. |nsCOMPtr| is smart in that, unlike a raw COM
|
||||
interface pointer, |nsCOMPtr| manages |AddRef|, |Release|, and |QueryInterface|
|
||||
_for_ you.
|
||||
|
||||
For instance, here is a typical snippet of code (at its most compact) where you assign
|
||||
a COM interface pointer into a member variable:
|
||||
|
||||
NS_IF_RELEASE(mFoop); // If I have one already, I must release it before over-writing it.
|
||||
if ( mFooP = aPtr ) // Now it's safe to assign it in, and, if it's not NULL
|
||||
mFooP->AddRef(); // I must |AddRef| it, since I'll be holding on to it.
|
||||
|
||||
If our member variable |mFooP| were a |nsCOMPtr|, however, the snippet above
|
||||
would look like this:
|
||||
|
||||
mFoop = aPtr; // Note: automatically |Release|s the old and |AddRef|s the new
|
||||
|
||||
|nsCOMPtr| helps you write code that is leak-proof, exception safe, and significantly
|
||||
less verbose than you would with raw COM interface pointers. With |nsCOMPtr|, you
|
||||
may never have to call |AddRef|, |Release|, or |QueryInterface| by hand.
|
||||
|
||||
|
||||
You still have to understand COM. You still have to know which functions return
|
||||
interface pointers that have already been |AddRef|ed and which don't. You still
|
||||
have to ensure your program logic doesn't produce circularly referencing garbage.
|
||||
|nsCOMPtr| is not a panacea. It is, however, helpful, easy to use, well-tested,
|
||||
and polite. It doesn't require that a function author cooperate with you, nor does
|
||||
your use force others to use it.
|
||||
|
||||
|
||||
Where should I use |nsCOMPtr|?
|
||||
|
||||
...
|
||||
|
||||
|
||||
Where _shouldn't_ I use |nsCOMPtr|?
|
||||
|
||||
In public interfaces... [[others]]
|
||||
|
||||
|
||||
How does a |nsCOMPtr| differ from a raw pointer?
|
||||
|
||||
A |nsCOMPtr| differs, syntactically, from a raw COM interface pointer in three
|
||||
ways:
|
||||
|
||||
+ It's declared differently, e.g.,
|
||||
|
||||
// instead of saying // you say
|
||||
IFoo* fooP; nsCOMPtr<IFoo> fooP;
|
||||
|
||||
|
||||
+ You can't call |AddRef| or |Release| through it,
|
||||
|
||||
fooP->AddRef(); // OK fooP->AddRef(); // Error: no permission
|
||||
fooP->Release(); // OK fooP->Release(); // Error: no permission
|
||||
|
||||
|
||||
+ You can't just apply an |&| to it to pass it to the typical `getter' function
|
||||
|
||||
AcquireFoo(&fooP); AcquireFoo( getter_AddRefs(fooP) );
|
||||
GetFoo(&fooP); GetFoo( getter_doesnt_AddRef(fooP) );
|
||||
|
||||
|
||||
How do I use |nsCOMPtr|?
|
||||
|
||||
Typically, you can use a |nsCOMPtr| exactly as you would a standard COM
|
||||
interface pointer:
|
||||
|
||||
IFoo* fooP; nsCOMPtr<IFoo> fooP;
|
||||
// ... // ...
|
||||
fooP->SomeFunction(x, y, z); fooP->SomeFunction(x, y, z);
|
||||
AnotherFunction(fooP); AnotherFunction(fooP);
|
||||
|
||||
if ( fooP ) if ( fooP )
|
||||
// ... // ...
|
||||
|
||||
if ( fooP == barP ) if ( fooP == barP )
|
||||
// ... // ...
|
||||
|
||||
There are some differences, though. In particular, you can't call |AddRef| or |Release|
|
||||
through a |nsCOMPtr| directly, nor would you need to. |AddRef| is called for you
|
||||
whenever you assign a COM interface pointer _into_ a |nsCOMPtr|. |Release| is
|
||||
called on the old value, and also when the |nsCOMPtr| goes out of scope. Trying
|
||||
to call |AddRef| or |Release| yourself will generate a compile-time error.
|
||||
|
||||
fooP->AddRef(); // fooP->AddRef(); // ERROR: no permission
|
||||
fooP->Release(); // fooP->Release(); // ERROR: no permission
|
||||
|
||||
The final difference is that a bare |nsCOMPtr| (or rather a pointer to it) can't
|
||||
be supplied as an argument to a function that `fills in' a COM interface pointer.
|
||||
Rather it must be wrapped with a utility call that says whether the function calls
|
||||
|AddRef| before returning, e.g.,
|
||||
|
||||
...->QueryInterface(riid, &fooP) ...->QueryInterface(riid, getter_AddRefs(fooP))
|
||||
|
||||
LookupFoo(&fooP); LookupFoo( getter_doesnt_AddRef(fooP) );
|
||||
|
||||
Don't worry. It's a compile-time error if you forget to wrap it.
|
||||
|
||||
Compare the raw-pointer way...
|
||||
|
||||
IFoo* foo = 0;
|
||||
nsresult status = CreateIFoo(&foo);
|
||||
if ( NS_SUCCEEDED(status) )
|
||||
{
|
||||
IBar* bar = 0;
|
||||
if ( NS_SUCCEEDED(status = foo->QueryInterface(riid, &bar)) )
|
||||
{
|
||||
IFooBar* foobar = 0;
|
||||
if ( NS_SUCCEEDED(status = CreateIFooBar(foo, bar, &foobar)) )
|
||||
{
|
||||
foobar->DoTheReallyHardThing();
|
||||
foobar->Release();
|
||||
}
|
||||
bar->Release();
|
||||
}
|
||||
foo->Release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
To the smart-pointer way...
|
||||
|
||||
nsCOMPtr<IFoo> fooP;
|
||||
nsresult status = CreateIFoo( getter_AddRefs(fooP) );
|
||||
if ( NS_SUCCEEDED(status) )
|
||||
if ( nsCOMPtr<IBar> barP( fooP ) )
|
||||
{
|
||||
nsCOMPtr<IFooBar> fooBarP;
|
||||
if ( NS_SUCCEEDED(status = CreateIFooBar(fooP, barP, getter_AddRefs(fooBarP))) )
|
||||
fooBarP->DoTheReallyHardThing();
|
||||
}
|
||||
|
||||
|
||||
Is there an easy way to convert my current code?
|
||||
|
||||
...
|
||||
|
||||
|
||||
What do I have to beware of?
|
||||
|
||||
VC++ < 6.0 _can't_ handle the following situation
|
||||
|
||||
class nsIFoo; // forward declare some class
|
||||
// ...
|
||||
nsCOMPtr<nsIFoo> bar; // ERROR: incomplete type nsIFoo, etc.
|
||||
|
||||
Instead, you must make sure that you actually defined the underlying interface class, e.g.,
|
||||
|
||||
#include "nsIFoo.h" // fully defines |class nsIFoo|
|
||||
// ...
|
||||
nsCOMPtr<nsIFoo> bar; // no problem
|
||||
|
||||
Why is this? It's because VC++ tries to instantiate every member of the template
|
||||
as soon as it sees the template declarations. Bad compiler. No cookie!
|
||||
[[Thanks to mjudge, waterson, and pinkerton on this one.]]
|
||||
|
||||
|
||||
Why does |getter_AddRefs| have such a funny name? I.e., why doesn't it follow our
|
||||
naming conventions?
|
||||
|
||||
|getter_AddRefs| and |getter_doesnt_AddRef| use underscores for the same
|
||||
reason our special macros do, quoting from our coding conventions "...to make them
|
||||
stick out like a sore thumb". Note also that since |AddRef| is one word,
|
||||
|getter_AddRefs| and |getter_doesnt_AddRef| couldn't have the right spacing if only inter-
|
||||
caps were used.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
WARNING:
|
||||
This file defines several macros for internal use only. These macros begin with the
|
||||
prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use
|
||||
only for cross-platform compatibility, and are subject to change without notice.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Set up some |#define|s to turn off a couple of troublesome C++ features.
|
||||
Interestingly, none of the compilers barf on template stuff.
|
||||
|
||||
Ideally, we would want declarations like these in a configuration file
|
||||
that everybody would get. Deciding exactly how to do that should
|
||||
be part of the process of moving from experimental to production.
|
||||
|
||||
Update: ramiro is working on getting these into the configuration system.
|
||||
*/
|
||||
|
||||
#if defined(__GNUG__) && (__GNUC_MINOR__ <= 90) && !defined(SOLARIS)
|
||||
#define NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
|
||||
#if (defined(LINUX) || defined(__bsdi__)) && (__GNUC_MINOR__ <= 7)
|
||||
#define NSCAP_NEED_UNUSED_VIRTUAL_IMPLEMENTATIONS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(SOLARIS) && !defined(__GNUG__)
|
||||
#define NSCAP_NO_BOOL
|
||||
#define NSCAP_NO_EXPLICIT
|
||||
#define NSCAP_NO_NEW_CASTS
|
||||
#define NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER<1100)
|
||||
#define NSCAP_NO_EXPLICIT
|
||||
#define NSCAP_NO_BOOL
|
||||
#endif
|
||||
|
||||
#if defined(IRIX)
|
||||
#define NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
#define NSCAP_NO_EXPLICIT
|
||||
#define NSCAP_NO_NEW_CASTS
|
||||
#define NSCAP_NO_BOOL
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NSCAP_NO_EXPLICIT
|
||||
#define explicit
|
||||
#endif
|
||||
|
||||
#ifndef NSCAP_NO_NEW_CASTS
|
||||
#define NSCAP_REINTERPRET_CAST(T,x) reinterpret_cast<T>(x)
|
||||
#else
|
||||
#define NSCAP_REINTERPRET_CAST(T,x) ((T)(x))
|
||||
#endif
|
||||
|
||||
#ifndef NSCAP_NO_BOOL
|
||||
typedef bool NSCAP_BOOL;
|
||||
#else
|
||||
typedef PRBool NSCAP_BOOL;
|
||||
#endif
|
||||
|
||||
#ifdef NSCAP_FEATURE_DEBUG_MACROS
|
||||
#define NSCAP_ADDREF(ptr) NS_ADDREF(ptr)
|
||||
#define NSCAP_RELEASE(ptr) NS_RELEASE(ptr)
|
||||
#else
|
||||
#define NSCAP_ADDREF(ptr) (ptr)->AddRef()
|
||||
#define NSCAP_RELEASE(ptr) (ptr)->Release()
|
||||
#endif
|
||||
|
||||
/*
|
||||
WARNING:
|
||||
VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined
|
||||
in an order that satisfies:
|
||||
|
||||
nsDerivedSafe < nsCOMPtr
|
||||
nsDontAddRef < nsCOMPtr
|
||||
nsCOMPtr < nsGetterAddRefs
|
||||
|
||||
The other compilers probably won't complain, so please don't reorder these
|
||||
classes, on pain of breaking 4.2 compatibility.
|
||||
*/
|
||||
|
||||
|
||||
template <class T>
|
||||
class nsDerivedSafe : public T
|
||||
/*
|
||||
No client should ever see or have to type the name of this class. It is the
|
||||
artifact that makes it a compile-time error to call |AddRef| and |Release|
|
||||
on a |nsCOMPtr|.
|
||||
|
||||
See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al.
|
||||
*/
|
||||
{
|
||||
private:
|
||||
#ifndef NSCAP_NO_MEMBER_USING_DECLARATIONS
|
||||
using T::AddRef;
|
||||
using T::Release;
|
||||
#else
|
||||
nsrefcnt AddRef();
|
||||
nsrefcnt Release();
|
||||
#endif
|
||||
|
||||
void operator delete( void* ); // NOT TO BE IMPLEMENTED
|
||||
// declaring |operator delete| private makes calling delete on an interface pointer a compile error
|
||||
|
||||
nsDerivedSafe& operator=( const nsDerivedSafe& ); // NOT TO BE IMPLEMENTED
|
||||
// you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one
|
||||
};
|
||||
|
||||
#if defined(NSCAP_NO_MEMBER_USING_DECLARATIONS) && defined(NSCAP_NEED_UNUSED_VIRTUAL_IMPLEMENTATIONS)
|
||||
template <class T>
|
||||
nsrefcnt
|
||||
nsDerivedSafe<T>::AddRef()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
nsrefcnt
|
||||
nsDerivedSafe<T>::Release()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct nsDontQueryInterface
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
explicit
|
||||
nsDontQueryInterface( T* aRawPtr )
|
||||
: mRawPtr(aRawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
T* mRawPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsDontQueryInterface<T>
|
||||
dont_QueryInterface( T* aRawPtr )
|
||||
{
|
||||
return nsDontQueryInterface<T>(aRawPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct nsQueryInterface
|
||||
{
|
||||
// explicit
|
||||
nsQueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
|
||||
: mRawPtr(aRawPtr),
|
||||
mErrorPtr(error)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsISupports* mRawPtr;
|
||||
nsresult* mErrorPtr;
|
||||
};
|
||||
|
||||
inline
|
||||
nsQueryInterface
|
||||
do_QueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
|
||||
{
|
||||
return nsQueryInterface(aRawPtr, error);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
struct nsDontAddRef
|
||||
/*
|
||||
...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_
|
||||
|AddRef|ing it. You would rarely use this directly, but rather through the
|
||||
machinery of |getter_AddRefs| in the argument list to functions that |AddRef|
|
||||
their results before returning them to the caller.
|
||||
|
||||
See also |getter_AddRefs()| and |class nsGetterAddRefs|.
|
||||
*/
|
||||
{
|
||||
explicit
|
||||
nsDontAddRef( T* aRawPtr )
|
||||
: mRawPtr(aRawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
T* mRawPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsDontAddRef<T>
|
||||
dont_AddRef( T* aRawPtr )
|
||||
/*
|
||||
...makes typing easier, because it deduces the template type, e.g.,
|
||||
you write |dont_AddRef(fooP)| instead of |nsDontAddRef<IFoo>(fooP)|.
|
||||
|
||||
Like the class it is shorthand for, you would rarely use this directly,
|
||||
but rather through |getter_AddRefs|.
|
||||
*/
|
||||
{
|
||||
return nsDontAddRef<T>(aRawPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class nsCOMPtr_base
|
||||
{
|
||||
public:
|
||||
|
||||
nsCOMPtr_base( nsISupports* rawPtr = 0 )
|
||||
: mRawPtr(rawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
~nsCOMPtr_base()
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
}
|
||||
|
||||
NS_EXPORT void assign_with_AddRef( nsISupports* );
|
||||
NS_EXPORT void assign_with_QueryInterface( nsISupports*, const nsIID&, nsresult* );
|
||||
NS_EXPORT void** begin_assignment();
|
||||
|
||||
protected:
|
||||
nsISupports* mRawPtr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
class nsCOMPtr : private nsCOMPtr_base
|
||||
/*
|
||||
...
|
||||
*/
|
||||
{
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
nsCOMPtr()
|
||||
// : nsCOMPtr_base(0)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsQueryInterface& aSmartPtr )
|
||||
// : nsCOMPtr_base(0)
|
||||
{
|
||||
assign_with_QueryInterface(aSmartPtr.mRawPtr, T::IID(), aSmartPtr.mErrorPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsDontAddRef<T>& aSmartPtr )
|
||||
: nsCOMPtr_base(aSmartPtr.mRawPtr)
|
||||
{
|
||||
// nothing else to do here
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsDontQueryInterface<T>& aSmartPtr )
|
||||
: nsCOMPtr_base(aSmartPtr.mRawPtr)
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_ADDREF(mRawPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr( const nsCOMPtr<T>& aSmartPtr )
|
||||
: nsCOMPtr_base(aSmartPtr.mRawPtr)
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_ADDREF(mRawPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsQueryInterface& rhs )
|
||||
{
|
||||
assign_with_QueryInterface(rhs.mRawPtr, T::IID(), rhs.mErrorPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsDontAddRef<T>& rhs )
|
||||
{
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = rhs.mRawPtr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsDontQueryInterface<T>& rhs )
|
||||
{
|
||||
assign_with_AddRef(rhs.mRawPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsCOMPtr<T>&
|
||||
operator=( const nsCOMPtr& rhs )
|
||||
{
|
||||
assign_with_AddRef(rhs.mRawPtr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsDerivedSafe<T>*
|
||||
get() const
|
||||
// returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
|
||||
{
|
||||
return NSCAP_REINTERPRET_CAST(nsDerivedSafe<T>*, mRawPtr);
|
||||
}
|
||||
|
||||
nsDerivedSafe<T>*
|
||||
operator->() const
|
||||
// returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
|
||||
{
|
||||
NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator->().");
|
||||
return get();
|
||||
}
|
||||
|
||||
nsDerivedSafe<T>&
|
||||
operator*() const
|
||||
// returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
|
||||
{
|
||||
NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsCOMPtr with operator*().");
|
||||
return *get();
|
||||
}
|
||||
|
||||
operator nsDerivedSafe<T>*() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
#if 0
|
||||
private:
|
||||
friend class nsGetterAddRefs<T>;
|
||||
|
||||
/*
|
||||
In a perfect world, the following member function, |StartAssignment|, would be private.
|
||||
It is and should be only accessed by the closely related class |nsGetterAddRefs<T>|.
|
||||
|
||||
Unfortunately, some compilers---most notably VC++5.0---fail to grok the
|
||||
friend declaration above or in any alternate acceptable form. So, physically
|
||||
it will be public (until our compilers get smarter); but it is not to be
|
||||
considered part of the logical public interface.
|
||||
*/
|
||||
#endif
|
||||
|
||||
T**
|
||||
StartAssignment()
|
||||
{
|
||||
return NSCAP_REINTERPRET_CAST(T**, begin_assignment());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
class nsGetterAddRefs
|
||||
/*
|
||||
...
|
||||
|
||||
This class is designed to be used for anonymous temporary objects in the
|
||||
argument list of calls that return COM interface pointers, e.g.,
|
||||
|
||||
nsCOMPtr<IFoo> fooP;
|
||||
...->QueryInterface(iid, nsGetterAddRefs<IFoo>(fooP))
|
||||
...->QueryInterface(iid, getter_AddRefs(fooP))
|
||||
|
||||
When initialized with a |nsCOMPtr|, as in the example above, it returns
|
||||
a |void**| (or |T**| if needed) that the outer call (|QueryInterface| in this
|
||||
case) can fill in. When this temporary object goes out of scope, just after
|
||||
the call returns, its destructor assigned the resulting interface pointer, i.e.,
|
||||
|QueryInterface|s result, into the |nsCOMPtr| it was initialized with.
|
||||
|
||||
See also |nsGetterDoesntAddRef|.
|
||||
*/
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
nsGetterAddRefs( nsCOMPtr<T>& aSmartPtr )
|
||||
: mTargetSmartPtr(aSmartPtr)
|
||||
{
|
||||
// nothing else to do
|
||||
}
|
||||
|
||||
operator void**()
|
||||
{
|
||||
// NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
|
||||
return NSCAP_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment());
|
||||
}
|
||||
|
||||
T*&
|
||||
operator*()
|
||||
{
|
||||
// NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
|
||||
return *(mTargetSmartPtr.StartAssignment());
|
||||
}
|
||||
|
||||
operator T**()
|
||||
{
|
||||
// NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
|
||||
return mTargetSmartPtr.StartAssignment();
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<T>& mTargetSmartPtr;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsGetterAddRefs<T>
|
||||
getter_AddRefs( nsCOMPtr<T>& aSmartPtr )
|
||||
/*
|
||||
Used around a |nsCOMPtr| when
|
||||
...makes the class |nsGetterAddRefs<T>| invisible.
|
||||
*/
|
||||
{
|
||||
return nsGetterAddRefs<T>(aSmartPtr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !defined(nsCOMPtr_h___)
|
||||
169
mozilla/xpcom/glue/nsDebug.cpp
Normal file
169
mozilla/xpcom/glue/nsDebug.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 "nsDebug.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#elif defined(XP_MAC)
|
||||
#define TEMP_MAC_HACK
|
||||
|
||||
//------------------------
|
||||
#ifdef TEMP_MAC_HACK
|
||||
#include <MacTypes.h>
|
||||
#include <Processes.h>
|
||||
|
||||
// TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON
|
||||
// LOGGING ON MACINTOSH
|
||||
// At this moment, NSPR's logging is a no-op on Macintosh.
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#undef PR_LOG
|
||||
#define PR_LOG(module,level,args) dprintf args
|
||||
static void dprintf(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
Str255 buffer;
|
||||
|
||||
va_start(ap, format);
|
||||
buffer[0] = vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
DebugStr(buffer);
|
||||
}
|
||||
#endif // TEMP_MAC_HACK
|
||||
//------------------------
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the nsDebug methods. Note that this code is
|
||||
* always compiled in, in case some other module that uses it is
|
||||
* compiled with debugging even if this library is not.
|
||||
*/
|
||||
|
||||
static PRLogModuleInfo* gDebugLog;
|
||||
|
||||
static void InitLog(void)
|
||||
{
|
||||
if (0 == gDebugLog) {
|
||||
gDebugLog = PR_NewLogModule("nsDebug");
|
||||
gDebugLog->level = PR_LOG_DEBUG;
|
||||
}
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Abort(const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Abort: at file %s, line %d", aFile, aLine));
|
||||
PR_LogFlush();
|
||||
#if defined(_WIN32)
|
||||
long* __p = (long*) 0x7;
|
||||
*__p = 0x7;
|
||||
#elif defined(XP_MAC)
|
||||
ExitToShell();
|
||||
#elif defined(XP_UNIX)
|
||||
::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Break(const char* aFile, PRIntn aLine)
|
||||
{
|
||||
#ifndef TEMP_MAC_HACK
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Break: at file %s, line %d", aFile, aLine));
|
||||
PR_LogFlush();
|
||||
//XXX this works on win32 only for now. For all the other platforms call Abort
|
||||
#if defined(_WIN32)
|
||||
::DebugBreak();
|
||||
#else
|
||||
Abort(aFile, aLine);
|
||||
#endif
|
||||
#endif // TEMP_MAC_HACK
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::PreCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("PreCondition: \"%s\" (%s) at file %s, line %d", aStr, aExpr,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::PostCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("PostCondition: \"%s\" (%s) at file %s, line %d", aStr, aExpr,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Assertion(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Assertion: \"%s\" (%s) at file %s, line %d", aStr, aExpr,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::NotYetImplemented(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("NotYetImplemented: \"%s\" at file %s, line %d", aMessage,
|
||||
aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::NotReached(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("NotReached: \"%s\" at file %s, line %d", aMessage, aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Error(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Error: \"%s\" at file %s, line %d", aMessage, aFile, aLine));
|
||||
Break(aFile, aLine);
|
||||
}
|
||||
|
||||
NS_COM void nsDebug::Warning(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine)
|
||||
{
|
||||
InitLog();
|
||||
PR_LOG(gDebugLog, PR_LOG_ERROR,
|
||||
("Warning: \"%s\" at file %s, line %d", aMessage, aFile, aLine));
|
||||
}
|
||||
179
mozilla/xpcom/glue/nsDebug.h
Normal file
179
mozilla/xpcom/glue/nsDebug.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
* 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 nsDebug_h___
|
||||
#define nsDebug_h___
|
||||
|
||||
#include "nsCom.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define NS_DEBUG
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Namespace for debugging methods. Note that your code must use the
|
||||
* macros defined later in this file so that the debug code can be
|
||||
* conditionally compiled out.
|
||||
*/
|
||||
class nsDebug {
|
||||
public:
|
||||
// XXX add in log controls here
|
||||
// XXX probably want printf type arguments
|
||||
|
||||
/**
|
||||
* Abort the executing program. This works on all architectures.
|
||||
*/
|
||||
static NS_COM void Abort(const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Break the executing program into the debugger.
|
||||
*/
|
||||
static NS_COM void Break(const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a pre-condition message to the debug log
|
||||
*/
|
||||
static NS_COM void PreCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a post-condition message to the debug log
|
||||
*/
|
||||
static NS_COM void PostCondition(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log an assertion message to the debug log
|
||||
*/
|
||||
static NS_COM void Assertion(const char* aStr, const char* aExpr,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a not-yet-implemented message to the debug log
|
||||
*/
|
||||
static NS_COM void NotYetImplemented(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a not-reached message to the debug log
|
||||
*/
|
||||
static NS_COM void NotReached(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log an error message to the debug log. This call returns.
|
||||
*/
|
||||
static NS_COM void Error(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
|
||||
/**
|
||||
* Log a warning message to the debug log.
|
||||
*/
|
||||
static NS_COM void Warning(const char* aMessage,
|
||||
const char* aFile, PRIntn aLine);
|
||||
};
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
/**
|
||||
* Test a precondition for truth. If the expression is not true then
|
||||
* trigger a program failure.
|
||||
*/
|
||||
#define NS_PRECONDITION(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::PreCondition(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Test an assertion for truth. If the expression is not true then
|
||||
* trigger a program failure.
|
||||
*/
|
||||
#define NS_ASSERTION(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::Assertion(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Test an assertion for truth. If the expression is not true then
|
||||
* trigger a program failure. The expression will still be
|
||||
* executed in release mode.
|
||||
*/
|
||||
#define NS_VERIFY(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::Assertion(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Test a post-condition for truth. If the expression is not true then
|
||||
* trigger a program failure.
|
||||
*/
|
||||
#define NS_POSTCONDITION(expr,str) \
|
||||
if (!(expr)) \
|
||||
nsDebug::PostCondition(str, #expr, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* This macros triggers a program failure if executed. It indicates that
|
||||
* an attempt was made to execute some unimplimented functionality.
|
||||
*/
|
||||
#define NS_NOTYETIMPLEMENTED(str) \
|
||||
nsDebug::NotYetImplemented(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* This macros triggers a program failure if executed. It indicates that
|
||||
* an attempt was made to execute some unimplimented functionality.
|
||||
*/
|
||||
#define NS_NOTREACHED(str) \
|
||||
nsDebug::NotReached(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Log an error message.
|
||||
*/
|
||||
#define NS_ERROR(str) \
|
||||
nsDebug::Error(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Log a warning message.
|
||||
*/
|
||||
#define NS_WARNING(str) \
|
||||
nsDebug::Warning(str, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Trigger an abort
|
||||
*/
|
||||
#define NS_ABORT() \
|
||||
nsDebug::Abort(__FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* Cause a break
|
||||
*/
|
||||
#define NS_BREAK() \
|
||||
nsDebug::Break(__FILE__, __LINE__)
|
||||
|
||||
#else /* NS_DEBUG */
|
||||
|
||||
#define NS_PRECONDITION(expr,str) {}
|
||||
#define NS_ASSERTION(expr,str) {}
|
||||
#define NS_VERIFY(expr,str) expr
|
||||
#define NS_POSTCONDITION(expr,str) {}
|
||||
#define NS_NOTYETIMPLEMENTED(str) {}
|
||||
#define NS_NOTREACHED(str) {}
|
||||
#define NS_ERROR(str) {}
|
||||
#define NS_WARNING(str) {}
|
||||
#define NS_ABORT() {}
|
||||
#define NS_BREAK() {}
|
||||
|
||||
#endif /* ! NS_DEBUG */
|
||||
|
||||
#endif /* nsDebug_h___ */
|
||||
30
mozilla/xpcom/libxpt/Makefile.in
Normal file
30
mozilla/xpcom/libxpt/Makefile.in
Normal file
@@ -0,0 +1,30 @@
|
||||
#!gmake
|
||||
# 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.
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = public src
|
||||
|
||||
DIRS += tests
|
||||
|
||||
DIRS += tools
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user