Compare commits
2 Commits
XPCOM_M4_B
...
regalloc_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c43d4984f | ||
|
|
cfe021ff88 |
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal file
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "BitSet.h"
|
||||
|
||||
// Return the next bit after index set to true or -1 if none.
|
||||
//
|
||||
Int32 BitSet::nextOne(Int32 pos) const
|
||||
{
|
||||
++pos;
|
||||
|
||||
if (pos < 0 || Uint32(pos) >= universeSize)
|
||||
return -1;
|
||||
|
||||
Uint32 offset = getWordOffset(pos);
|
||||
Uint8 index = getBitOffset(pos);
|
||||
Word* ptr = &word[offset];
|
||||
Word currentWord = *ptr++ >> index;
|
||||
|
||||
if (currentWord != Word(0)) {
|
||||
while ((currentWord & Word(1)) == 0) {
|
||||
++index;
|
||||
currentWord >>= 1;
|
||||
}
|
||||
return (offset << nBitsInWordLog2) + index;
|
||||
}
|
||||
|
||||
Word* limit = &word[getSizeInWords(universeSize)];
|
||||
while (ptr < limit) {
|
||||
++offset;
|
||||
currentWord = *ptr++;
|
||||
if (currentWord != Word(0)) {
|
||||
index = 0;
|
||||
while ((currentWord & Word(1)) == 0) {
|
||||
++index;
|
||||
currentWord >>= 1;
|
||||
}
|
||||
return (offset << nBitsInWordLog2) + index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return the next bit after index set to false or -1 if none.
|
||||
//
|
||||
Int32 BitSet::nextZero(Int32 pos) const
|
||||
{
|
||||
++pos;
|
||||
|
||||
if (pos < 0 || Uint32(pos) >= universeSize)
|
||||
return -1;
|
||||
|
||||
Uint32 offset = getWordOffset(pos);
|
||||
Uint8 index = getBitOffset(pos);
|
||||
Word* ptr = &word[offset];
|
||||
Word currentWord = *ptr++ >> index;
|
||||
|
||||
if (currentWord != Word(~0)) {
|
||||
for (; index < nBitsInWord; ++index) {
|
||||
if ((currentWord & Word(1)) == 0) {
|
||||
Int32 ret = (offset << nBitsInWordLog2) + index;
|
||||
return (Uint32(ret) < universeSize) ? ret : -1;
|
||||
}
|
||||
currentWord >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Word* limit = &word[getSizeInWords(universeSize)];
|
||||
while (ptr < limit) {
|
||||
++offset;
|
||||
currentWord = *ptr++;
|
||||
if (currentWord != Word(~0)) {
|
||||
for (index = 0; index < nBitsInWord; ++index) {
|
||||
if ((currentWord & Word(1)) == 0) {
|
||||
Int32 ret = (offset << nBitsInWordLog2) + index;
|
||||
return (Uint32(ret) < universeSize) ? ret : -1;
|
||||
}
|
||||
currentWord >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
|
||||
// Print the set.
|
||||
//
|
||||
void BitSet::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("[ "));
|
||||
|
||||
for (Int32 i = firstOne(); i != -1; i = nextOne(i)) {
|
||||
Int32 currentBit = i;
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", currentBit));
|
||||
|
||||
Int32 nextBit = nextOne(currentBit);
|
||||
if (nextBit != currentBit + 1) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" "));
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((nextBit != -1) && (nextBit == (currentBit + 1))) {
|
||||
currentBit = nextBit;
|
||||
nextBit = nextOne(nextBit);
|
||||
}
|
||||
|
||||
if (currentBit > (i+1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("-%d ", currentBit));
|
||||
else
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" %d ", currentBit));
|
||||
|
||||
i = currentBit;
|
||||
}
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("]\n"));
|
||||
}
|
||||
|
||||
#endif // DEBUG_LOG
|
||||
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal file
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BITSET_H_
|
||||
#define _BITSET_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "LogModule.h"
|
||||
#include "Pool.h"
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// BitSet -
|
||||
|
||||
class BitSet
|
||||
{
|
||||
private:
|
||||
|
||||
#if (PR_BITS_PER_WORD == 64)
|
||||
typedef Uint64 Word;
|
||||
#elif (PR_BITS_PER_WORD == 32)
|
||||
typedef Uint32 Word;
|
||||
#endif
|
||||
|
||||
static const nBitsInWord = PR_BITS_PER_WORD;
|
||||
static const nBytesInWord = PR_BYTES_PER_WORD;
|
||||
static const nBitsInWordLog2 = PR_BITS_PER_WORD_LOG2;
|
||||
static const nBytesInWordLog2 = PR_BYTES_PER_WORD_LOG2;
|
||||
|
||||
// Return the number of Word need to store the universe.
|
||||
static Uint32 getSizeInWords(Uint32 sizeOfUniverse) {return (sizeOfUniverse + (nBitsInWord - 1)) >> nBitsInWordLog2;}
|
||||
// Return the given element offset in its containing Word.
|
||||
static Uint32 getBitOffset(Uint32 element) {return element & (nBitsInWord - 1);}
|
||||
// Return the Word offset for the given element int the universe.
|
||||
static Uint32 getWordOffset(Uint32 element) {return element >> nBitsInWordLog2;}
|
||||
// Return the mask for the given bit index.
|
||||
static Word getMask(Uint8 index) {return Word(1) << index;}
|
||||
|
||||
private:
|
||||
|
||||
Uint32 universeSize; // Size of the universe
|
||||
Word* word; // universe memory.
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
BitSet(const BitSet&);
|
||||
|
||||
// Check if the given set's universe is of the same size than this universe.
|
||||
void checkUniverseCompatibility(const BitSet& set) const {assert(set.universeSize == universeSize);}
|
||||
// Check if pos is valid for this set's universe.
|
||||
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
|
||||
|
||||
public:
|
||||
|
||||
// Create a bitset of universeSize bits.
|
||||
BitSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {word = new(pool) Word[getSizeInWords(universeSize)]; clear();}
|
||||
|
||||
// Return the size of this bitset.
|
||||
Uint32 getSize() const {return universeSize;}
|
||||
|
||||
// Clear the bitset.
|
||||
void clear() {memset(word, 0x00, getSizeInWords(universeSize) << nBytesInWordLog2);}
|
||||
// Clear the bit at index.
|
||||
void clear(Uint32 index) {checkMember(index); word[getWordOffset(index)] &= ~getMask(index);}
|
||||
// Set the bitset.
|
||||
void set() {memset(word, 0xFF, getSizeInWords(universeSize) << nBytesInWordLog2);}
|
||||
// Set the bit at index.
|
||||
void set(Uint32 index) {checkMember(index); word[getWordOffset(index)] |= getMask(index);}
|
||||
// Return true if the bit at index is set.
|
||||
bool test(Uint32 index) const {checkMember(index); return (word[getWordOffset(index)] & getMask(index)) != 0;}
|
||||
// Union with the given bitset.
|
||||
inline void or(const BitSet& set);
|
||||
// Intersection with the given bitset.
|
||||
inline void and(const BitSet& set);
|
||||
// Difference with the given bitset.
|
||||
inline void difference(const BitSet& set);
|
||||
// Copy set.
|
||||
inline BitSet& operator = (const BitSet& set);
|
||||
// Return true if the bitset are identical.
|
||||
friend bool operator == (const BitSet& set1, const BitSet& set2);
|
||||
// Return true if the bitset are different.
|
||||
friend bool operator != (const BitSet& set1, const BitSet& set2);
|
||||
|
||||
// Logical operators.
|
||||
BitSet& operator |= (const BitSet& set) {or(set); return *this;}
|
||||
BitSet& operator &= (const BitSet& set) {and(set); return *this;}
|
||||
BitSet& operator -= (const BitSet& set) {difference(set); return *this;}
|
||||
|
||||
// Return the first bit at set to true or -1 if none.
|
||||
Int32 firstOne() const {return nextOne(-1);}
|
||||
// Return the next bit after index set to true or -1 if none.
|
||||
Int32 nextOne(Int32 pos) const;
|
||||
// Return the first bit at set to false or -1 if none.
|
||||
Int32 firstZero() const {return nextZero(-1);}
|
||||
// Return the next bit after index set to false or -1 if none.
|
||||
Int32 nextZero(Int32 pos) const;
|
||||
|
||||
// Iterator to conform with the set API.
|
||||
typedef Int32 iterator;
|
||||
// Return true if the walk is ordered.
|
||||
static bool isOrdered() {return true;}
|
||||
// Return the iterator for the first element of this set.
|
||||
iterator begin() const {return firstOne();}
|
||||
// Return the next iterator.
|
||||
iterator advance(iterator pos) const {return nextOne(pos);}
|
||||
// Return true if the iterator is at the end of the set.
|
||||
bool done(iterator pos) const {return pos == -1;}
|
||||
// Return the element corresponding to the given iterator.
|
||||
Uint32 get(iterator pos) const {return pos;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the set.
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// Union with the given bitset.
|
||||
//
|
||||
inline void BitSet::or(const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Word* src = set.word;
|
||||
Word* dst = word;
|
||||
Word* limit = &src[getSizeInWords(universeSize)];
|
||||
|
||||
while (src < limit)
|
||||
*dst++ |= *src++;
|
||||
}
|
||||
|
||||
// Intersection with the given bitset.
|
||||
//
|
||||
inline void BitSet::and(const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Word* src = set.word;
|
||||
Word* dst = word;
|
||||
Word* limit = &src[getSizeInWords(universeSize)];
|
||||
|
||||
while (src < limit)
|
||||
*dst++ &= *src++;
|
||||
}
|
||||
|
||||
// Difference with the given bitset.
|
||||
//
|
||||
inline void BitSet::difference(const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Word* src = set.word;
|
||||
Word* dst = word;
|
||||
Word* limit = &src[getSizeInWords(universeSize)];
|
||||
|
||||
while (src < limit)
|
||||
*dst++ &= ~*src++;
|
||||
}
|
||||
|
||||
// Copy the given set into this set.
|
||||
//
|
||||
inline BitSet& BitSet::operator = (const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
if (this != &set)
|
||||
memcpy(word, set.word, getSizeInWords(universeSize) << nBytesInWordLog2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Return true if the given set is identical to this set.
|
||||
inline bool operator == (const BitSet& set1, const BitSet& set2)
|
||||
{
|
||||
set1.checkUniverseCompatibility(set2);
|
||||
|
||||
if (&set1 == &set2)
|
||||
return true;
|
||||
|
||||
return memcmp(set1.word, set2.word, BitSet::getSizeInWords(set1.universeSize) << BitSet::nBytesInWordLog2) == 0;
|
||||
}
|
||||
|
||||
inline bool operator != (const BitSet& set1, const BitSet& set2) {return !(set1 == set2);}
|
||||
|
||||
#endif // _BITSET_H
|
||||
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal file
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _COALESCING_H_
|
||||
#define _COALESCING_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "InterferenceGraph.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "SparseSet.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
|
||||
#if 1
|
||||
// Performing an ultra conservative coalescing meens that when we look at
|
||||
// candidates (source,destination) for coalescing we need to make sure
|
||||
// that the combined interference of the source and destination register
|
||||
// will not exceed the total number of register available for the register
|
||||
// class.
|
||||
#define ULTRA_CONSERVATIVE_COALESCING
|
||||
#else
|
||||
// If we are not doing an ultra conservative coalescing we have to make sure
|
||||
// that the total number of neighbor whose degree is greater than the total
|
||||
// number of register is not greater than the total number of register.
|
||||
#undef ULTRA_CONSERVATIVE_COALESCING
|
||||
#endif
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct Coalescing
|
||||
{
|
||||
static bool coalesce(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Coalescing<RegisterPressure>::coalesce(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
|
||||
// Initialize the lookup table
|
||||
//
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* newRange = new RegisterName[2 * rangeCount];
|
||||
RegisterName* coalescedRange = &newRange[rangeCount];
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
init(coalescedRange, rangeCount);
|
||||
|
||||
SparseSet interferences(pool, rangeCount);
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
bool removedInstructions = false;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.lndList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
|
||||
// Walk the nodes in the loop nesting depth list.
|
||||
for (Int32 n = nNodes - 1; n >= 0; n--) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
|
||||
InstructionList::iterator it = instructions.begin();
|
||||
while (!instructions.done(it)) {
|
||||
Instruction& instruction = instructions.get(it);
|
||||
it = instructions.advance(it);
|
||||
|
||||
if ((instruction.getFlags() & ifCopy) != 0) {
|
||||
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
|
||||
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
|
||||
|
||||
RegisterName source = findRoot(name2range[instruction.getInstructionUseBegin()[0].getRegisterName()], coalescedRange);
|
||||
RegisterName destination = findRoot(name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()], coalescedRange);
|
||||
|
||||
if (source == destination) {
|
||||
instruction.remove();
|
||||
} else if (!iGraph.interfere(source, destination)) {
|
||||
InterferenceVector* sourceVector = iGraph.getInterferenceVector(source);
|
||||
InterferenceVector* destinationVector = iGraph.getInterferenceVector(destination);
|
||||
|
||||
#ifdef ULTRA_CONSERVATIVE_COALESCING
|
||||
interferences.clear();
|
||||
|
||||
InterferenceVector* vector;
|
||||
for (vector = sourceVector; vector != NULL; vector = vector->next) {
|
||||
RegisterName* neighbors = vector->neighbors;
|
||||
for (Uint32 i = 0; i < vector->count; i++)
|
||||
interferences.set(findRoot(neighbors[i], coalescedRange));
|
||||
}
|
||||
for (vector = destinationVector; vector != NULL; vector = vector->next) {
|
||||
RegisterName* neighbors = vector->neighbors;
|
||||
for (Uint32 i = 0; i < vector->count; i++)
|
||||
interferences.set(findRoot(neighbors[i], coalescedRange));
|
||||
}
|
||||
|
||||
Uint32 count = interferences.getSize();
|
||||
#else // ULTRA_CONSERVATIVE_COALESCING
|
||||
trespass("not implemented");
|
||||
Uint32 count = 0;
|
||||
#endif // ULTRA_CONSERVATIVE_COALESCING
|
||||
|
||||
if (count < 6 /* FIX: should get the number from the class */) {
|
||||
// Update the interferences vector.
|
||||
if (sourceVector == NULL) {
|
||||
iGraph.setInterferenceVector(source, destinationVector);
|
||||
sourceVector = destinationVector;
|
||||
} else if (destinationVector == NULL)
|
||||
iGraph.setInterferenceVector(destination, sourceVector);
|
||||
else {
|
||||
InterferenceVector* last = NULL;
|
||||
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next)
|
||||
last = v;
|
||||
assert(last);
|
||||
last->next = destinationVector;
|
||||
iGraph.setInterferenceVector(destination, sourceVector);
|
||||
}
|
||||
// Update the interference matrix.
|
||||
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next) {
|
||||
RegisterName* neighbors = v->neighbors;
|
||||
for (Uint32 i = 0; i < v->count; i++) {
|
||||
RegisterName neighbor = findRoot(neighbors[i], coalescedRange);
|
||||
iGraph.setInterference(neighbor, source);
|
||||
iGraph.setInterference(neighbor, destination);
|
||||
}
|
||||
}
|
||||
|
||||
instruction.remove();
|
||||
coalescedRange[source] = destination;
|
||||
removedInstructions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAllocator.rangeCount = compress(registerAllocator.name2range, coalescedRange, registerAllocator.nameCount, rangeCount);
|
||||
delete newRange;
|
||||
|
||||
return removedInstructions;
|
||||
}
|
||||
|
||||
#endif // _COALESCING_H_
|
||||
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal file
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef NEW_LAURENTM_CODE
|
||||
|
||||
#include "Coloring.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "FastBitSet.h"
|
||||
#include "FastBitMatrix.h"
|
||||
#include "CpuInfo.h"
|
||||
|
||||
bool Coloring::
|
||||
assignRegisters(FastBitMatrix& interferenceMatrix)
|
||||
{
|
||||
PRUint32 *stackPtr = new(pool) PRUint32[vRegManager.count()];
|
||||
|
||||
return select(interferenceMatrix, stackPtr, simplify(interferenceMatrix, stackPtr));
|
||||
}
|
||||
|
||||
PRInt32 Coloring::
|
||||
getLowestSpillCostRegister(FastBitSet& bitset)
|
||||
{
|
||||
PRInt32 lowest = bitset.firstOne();
|
||||
if (lowest != -1)
|
||||
{
|
||||
Flt32 cost = vRegManager.getVirtualRegister(lowest).spillInfo.spillCost;
|
||||
for (PRInt32 r = bitset.nextOne(lowest); r != -1; r = bitset.nextOne(r))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
|
||||
if (!vReg.spillInfo.infiniteSpillCost && (vReg.spillInfo.spillCost < cost))
|
||||
{
|
||||
cost = vReg.spillInfo.spillCost;
|
||||
lowest = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lowest;
|
||||
}
|
||||
|
||||
PRUint32* Coloring::
|
||||
simplify(FastBitMatrix interferenceMatrix, PRUint32* stackPtr)
|
||||
{
|
||||
// first we construct the sets low and high. low contains all nodes of degree
|
||||
// inferior to the number of register available on the processor. All the
|
||||
// nodes with an high degree and a finite spill cost are placed in high.
|
||||
// Nodes of high degree and infinite spill cost are not included in either sets.
|
||||
|
||||
PRUint32 nRegisters = vRegManager.count();
|
||||
FastBitSet low(pool, nRegisters);
|
||||
FastBitSet high(pool, nRegisters);
|
||||
FastBitSet stack(pool, nRegisters);
|
||||
|
||||
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
|
||||
|
||||
if (vReg.getClass() == vrcStackSlot)
|
||||
{
|
||||
stack.set(i);
|
||||
vReg.colorRegister(nRegisters);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vReg.colorInfo.interferenceDegree < NUMBER_OF_REGISTERS)
|
||||
low.set(i);
|
||||
else // if (!vReg.spillInfo.infiniteSpillCost)
|
||||
high.set(i);
|
||||
|
||||
// Set coloring info.
|
||||
vReg.spillInfo.willSpill = false;
|
||||
|
||||
switch(vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
vReg.colorRegister(LAST_GREGISTER + 1);
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
vReg.colorRegister(LAST_FPREGISTER + 1);
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(false); // Cannot happen.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// push the stack registers
|
||||
PRInt32 j;
|
||||
for (j = stack.firstOne(); j != -1; j = stack.nextOne(j))
|
||||
*stackPtr++ = j;
|
||||
|
||||
// simplify
|
||||
while (true)
|
||||
{
|
||||
PRInt32 r;
|
||||
while ((r = getLowestSpillCostRegister(low)) != -1)
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
|
||||
|
||||
/* update low and high */
|
||||
FastBitSet inter(interferenceMatrix.getRow(r), nRegisters);
|
||||
for (j = inter.firstOne(); j != -1; j = inter.nextOne(j))
|
||||
{
|
||||
VirtualRegister& neighbor = vRegManager.getVirtualRegister(j);
|
||||
// if the new interference degree of one of his neighbor becomes
|
||||
// NUMBER_OF_REGISTERS - 1 then it is added to the set 'low'.
|
||||
|
||||
PRUint32 maxInterference = 0;
|
||||
switch (neighbor.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
maxInterference = NUMBER_OF_GREGISTERS;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
maxInterference = NUMBER_OF_FPREGISTERS;
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(false);
|
||||
}
|
||||
if ((vRegManager.getVirtualRegister(j).colorInfo.interferenceDegree-- == maxInterference))
|
||||
{
|
||||
high.clear(j);
|
||||
low.set(j);
|
||||
}
|
||||
vReg.colorInfo.interferenceDegree--;
|
||||
interferenceMatrix.clear(r, j);
|
||||
interferenceMatrix.clear(j, r);
|
||||
}
|
||||
low.clear(r);
|
||||
|
||||
// Push this register.
|
||||
*stackPtr++ = r;
|
||||
}
|
||||
if ((r = getLowestSpillCostRegister(high)) != -1)
|
||||
{
|
||||
high.clear(r);
|
||||
low.set(r);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return stackPtr;
|
||||
}
|
||||
|
||||
bool Coloring::
|
||||
select(FastBitMatrix& interferenceMatrix, PRUint32* stackBase, PRUint32* stackPtr)
|
||||
{
|
||||
PRUint32 nRegisters = vRegManager.count();
|
||||
FastBitSet usedRegisters(NUMBER_OF_REGISTERS + 1); // usedRegisters if used for both GR & FPR.
|
||||
FastBitSet preColoredRegisters(NUMBER_OF_REGISTERS + 1);
|
||||
FastBitSet usedStack(nRegisters + 1);
|
||||
bool success = true;
|
||||
Int32 lastUsedSSR = -1;
|
||||
|
||||
// select
|
||||
while (stackPtr != stackBase)
|
||||
{
|
||||
// Pop one register.
|
||||
PRUint32 r = *--stackPtr;
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
|
||||
|
||||
FastBitSet neighbors(interferenceMatrix.getRow(r), nRegisters);
|
||||
|
||||
if (vReg.getClass() == vrcStackSlot)
|
||||
// Stack slots coloring.
|
||||
{
|
||||
usedStack.clear();
|
||||
|
||||
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
|
||||
usedStack.set(vRegManager.getVirtualRegister(i).getColor());
|
||||
|
||||
Int32 color = usedStack.firstZero();
|
||||
vReg.colorRegister(color);
|
||||
if (color > lastUsedSSR)
|
||||
lastUsedSSR = color;
|
||||
}
|
||||
else
|
||||
// Integer & Floating point register coloring.
|
||||
{
|
||||
usedRegisters.clear();
|
||||
preColoredRegisters.clear();
|
||||
|
||||
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
|
||||
{
|
||||
VirtualRegister& nvReg = vRegManager.getVirtualRegister(i);
|
||||
usedRegisters.set(nvReg.getColor());
|
||||
if (nvReg.isPreColored())
|
||||
preColoredRegisters.set(nvReg.getPreColor());
|
||||
}
|
||||
if (vReg.hasSpecialInterference)
|
||||
usedRegisters |= vReg.specialInterference;
|
||||
|
||||
PRInt8 c = -1;
|
||||
PRInt8 maxColor = 0;
|
||||
PRInt8 firstColor = 0;
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
firstColor = FIRST_GREGISTER;
|
||||
maxColor = LAST_GREGISTER;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
firstColor = FIRST_FPREGISTER;
|
||||
maxColor = LAST_FPREGISTER;
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(false);
|
||||
}
|
||||
|
||||
if (vReg.isPreColored())
|
||||
{
|
||||
c = vReg.getPreColor();
|
||||
if (usedRegisters.test(c))
|
||||
c = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (c = usedRegisters.nextZero(firstColor - 1); (c >= 0) && (c <= maxColor) && (preColoredRegisters.test(c));
|
||||
c = usedRegisters.nextZero(c)) {}
|
||||
}
|
||||
|
||||
if ((c >= 0) && (c <= maxColor))
|
||||
{
|
||||
vReg.colorRegister(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
VirtualRegister& stackRegister = vRegManager.newVirtualRegister(vrcStackSlot);
|
||||
vReg.equivalentRegister[vrcStackSlot] = &stackRegister;
|
||||
vReg.spillInfo.willSpill = true;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (success)
|
||||
{
|
||||
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
if (vReg.getColor() > LAST_GREGISTER)
|
||||
PR_ASSERT(false);
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
#if NUMBER_OF_FPREGISTERS != 0
|
||||
if (vReg.getColor() > LAST_FPREGISTER)
|
||||
PR_ASSERT(false);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vRegManager.nUsedStackSlots = lastUsedSSR + 1;
|
||||
return success;
|
||||
}
|
||||
#endif // NEW_LAURENTM_CODE
|
||||
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal file
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "InterferenceGraph.h"
|
||||
#include "SparseSet.h"
|
||||
#include "Spilling.h"
|
||||
#include "Splits.h"
|
||||
|
||||
UT_EXTERN_LOG_MODULE(RegAlloc);
|
||||
|
||||
template <class RegisterPressure>
|
||||
class Coloring
|
||||
{
|
||||
private:
|
||||
static RegisterName* simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack);
|
||||
static bool select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr);
|
||||
|
||||
public:
|
||||
static bool color(RegisterAllocator& registerAllocator);
|
||||
static void finalColoring(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Coloring<RegisterPressure>::finalColoring(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
RegisterName* color = registerAllocator.color;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
usePtr->setRegisterName(color[name2range[usePtr->getRegisterName()]]);
|
||||
#ifdef DEBUG
|
||||
RegisterID rid = usePtr->getRegisterID();
|
||||
setColoredRegister(rid);
|
||||
usePtr->setRegisterID(rid);
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
definePtr->setRegisterName(color[name2range[definePtr->getRegisterName()]]);
|
||||
#ifdef DEBUG
|
||||
RegisterID rid = definePtr->getRegisterID();
|
||||
setColoredRegister(rid);
|
||||
definePtr->setRegisterID(rid);
|
||||
#endif // DEBUG
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Coloring<RegisterPressure>::select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr)
|
||||
{
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* color = new RegisterName[rangeCount];
|
||||
registerAllocator.color = color;
|
||||
|
||||
for (Uint32 r = 1; r < rangeCount; r++)
|
||||
color[r] = RegisterName(6); // FIX;
|
||||
|
||||
// Color the preColored registers.
|
||||
//
|
||||
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
|
||||
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
|
||||
if (machinePtr->id != invalidID) {
|
||||
color[name2range[getName(machinePtr->id)]] = machinePtr->color;
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill preColor range %d as %d\n", name2range[getName(machinePtr->id)], machinePtr->color));
|
||||
}
|
||||
|
||||
SpillCost* cost = registerAllocator.spillCost;
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet& spill = *new(pool) SparseSet(pool, rangeCount);
|
||||
registerAllocator.willSpill = &spill;
|
||||
SparseSet neighborColors(pool, 6); // FIX
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
|
||||
bool coloringFailed = false;
|
||||
while (coloringStackPtr > coloringStack) {
|
||||
RegisterName range = *--coloringStackPtr;
|
||||
|
||||
if (!cost[range].infinite && cost[range].cost < 0) {
|
||||
coloringFailed = true;
|
||||
spill.set(range);
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, will spill.\n", range));
|
||||
} else {
|
||||
neighborColors.clear();
|
||||
|
||||
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
|
||||
for (Int32 i = vector->count - 1; i >= 0; --i) {
|
||||
RegisterName neighborColor = color[vector->neighbors[i]];
|
||||
if (neighborColor < 6) // FIX
|
||||
neighborColors.set(neighborColor);
|
||||
}
|
||||
|
||||
if (neighborColors.getSize() == 6) { // FIX
|
||||
coloringFailed = true;
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, ", range));
|
||||
|
||||
if (!Splits<RegisterPressure>::findSplit(registerAllocator, color, range)) {
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will spill.\n"));
|
||||
spill.set(range);
|
||||
} else
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will split.\n"));
|
||||
} else {
|
||||
for (Uint32 i = 0; i < 6; i++) // FIX
|
||||
if (!neighborColors.test(i)) {
|
||||
fprintf(stdout, "\twill color %d as %d\n", range, i);
|
||||
color[range] = RegisterName(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
if (coloringFailed) {
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring failed:\n"));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill spill: "));
|
||||
spill.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
} else {
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring succeeded:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++)
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\trange %d colored as %d\n", i, color[i]));
|
||||
}
|
||||
#endif
|
||||
|
||||
return !coloringFailed;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
RegisterName* Coloring<RegisterPressure>::simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack)
|
||||
{
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
SpillCost* spillCost = registerAllocator.spillCost;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
|
||||
Uint32* degree = new Uint32[rangeCount];
|
||||
for (RegisterName i = RegisterName(1); i < rangeCount; i = RegisterName(i + 1)) {
|
||||
InterferenceVector* vector = iGraph.getInterferenceVector(i);
|
||||
degree[i] = (vector != NULL) ? vector->count : 0;
|
||||
}
|
||||
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet low(pool, rangeCount);
|
||||
SparseSet high(pool, rangeCount);
|
||||
SparseSet highInfinite(pool, rangeCount);
|
||||
SparseSet preColored(pool, rangeCount);
|
||||
|
||||
// Get the precolored registers.
|
||||
//
|
||||
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
|
||||
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
|
||||
if (machinePtr->id != invalidID)
|
||||
preColored.set(name2range[getName(machinePtr->id)]);
|
||||
|
||||
// Insert the live ranges in the sets.
|
||||
//
|
||||
for (Uint32 range = 1; range < rangeCount; range++)
|
||||
if (!preColored.test(range))
|
||||
if (degree[range] < 6) // FIX
|
||||
low.set(range);
|
||||
else if (!spillCost[range].infinite)
|
||||
high.set(range);
|
||||
else
|
||||
highInfinite.set(range);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring sets:\n\tlow = "));
|
||||
low.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thigh = "));
|
||||
high.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thighInfinite = "));
|
||||
highInfinite.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tpreColored = "));
|
||||
preColored.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
RegisterName* coloringStackPtr = coloringStack;
|
||||
|
||||
while (low.getSize() != 0 || high.getSize() != 0) {
|
||||
while (low.getSize() != 0) {
|
||||
RegisterName range = RegisterName(low.getOne());
|
||||
low.clear(range);
|
||||
*coloringStackPtr++ = range;
|
||||
|
||||
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
|
||||
for (Int32 i = (vector->count - 1); i >= 0; --i) {
|
||||
RegisterName neighbor = vector->neighbors[i];
|
||||
degree[neighbor]--;
|
||||
|
||||
if (degree[neighbor] < 6) // FIX
|
||||
if (high.test(neighbor)) {
|
||||
high.clear(neighbor);
|
||||
low.set(neighbor);
|
||||
} else if (highInfinite.test(neighbor)) {
|
||||
highInfinite.clear(neighbor);
|
||||
low.set(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (high.getSize() != 0) {
|
||||
RegisterName best = RegisterName(high.getOne());
|
||||
double bestCost = spillCost[best].cost;
|
||||
double bestDegree = degree[best];
|
||||
|
||||
// Choose the next best candidate.
|
||||
//
|
||||
for (SparseSet::iterator i = high.begin(); !high.done(i); i = high.advance(i)) {
|
||||
RegisterName range = RegisterName(high.get(i));
|
||||
double thisCost = spillCost[range].cost;
|
||||
double thisDegree = degree[range];
|
||||
|
||||
if (thisCost * bestDegree < bestCost * thisDegree) {
|
||||
best = range;
|
||||
bestCost = thisCost;
|
||||
bestDegree = thisDegree;
|
||||
}
|
||||
}
|
||||
|
||||
high.clear(best);
|
||||
low.set(best);
|
||||
}
|
||||
}
|
||||
assert(highInfinite.getSize() == 0);
|
||||
|
||||
delete degree;
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring stack:\n\t"));
|
||||
for (RegisterName* sp = coloringStack; sp < coloringStackPtr; ++sp)
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("%d ", *sp));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\n"));
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
return coloringStackPtr;
|
||||
}
|
||||
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Coloring<RegisterPressure>::color(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
RegisterName* coloringStack = new RegisterName[registerAllocator.rangeCount];
|
||||
return select(registerAllocator, coloringStack, simplify(registerAllocator, coloringStack));
|
||||
}
|
||||
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal file
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
|
||||
#include "DominatorGraph.h"
|
||||
|
||||
DominatorGraph::DominatorGraph(ControlGraph& controlGraph) : controlGraph(controlGraph)
|
||||
{
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
GtoV = new Uint32[nNodes + 1];
|
||||
VtoG = new Uint32[nNodes + 1];
|
||||
|
||||
Uint32 v = 1;
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
VtoG[v] = n;
|
||||
GtoV[n] = v++;
|
||||
}
|
||||
|
||||
// Initialize all the 1-based arrays.
|
||||
//
|
||||
parent = new Uint32[v];
|
||||
semi = new Uint32[v];
|
||||
vertex = new Uint32[v];
|
||||
label = new Uint32[v];
|
||||
size = new Uint32[v];
|
||||
ancestor = new Uint32[v];
|
||||
child = new Uint32[v];
|
||||
dom = new Uint32[v];
|
||||
bucket = new DGLinkedList*[v];
|
||||
|
||||
memset(semi, '\0', v * sizeof(Uint32));
|
||||
memset(bucket, '\0', v * sizeof(DGLinkedList*));
|
||||
|
||||
vCount = v;
|
||||
|
||||
build();
|
||||
|
||||
delete parent;
|
||||
delete semi;
|
||||
delete vertex;
|
||||
delete label;
|
||||
delete size;
|
||||
delete ancestor;
|
||||
delete child;
|
||||
delete dom;
|
||||
delete bucket;
|
||||
}
|
||||
|
||||
Uint32 DominatorGraph::DFS(Uint32 vx, Uint32 n)
|
||||
{
|
||||
semi[vx] = ++n;
|
||||
vertex[n] = label[vx] = vx;
|
||||
ancestor[vx] = child[vx] = 0;
|
||||
size[vx] = 1;
|
||||
|
||||
|
||||
ControlNode& node = *controlGraph.dfsList[VtoG[vx]];
|
||||
ControlEdge* successorEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorPtr = node.getSuccessorsBegin(); successorPtr < successorEnd; successorPtr++) {
|
||||
Uint32 w = GtoV[successorPtr->getTarget().dfsNum];
|
||||
if (semi[w] == 0) {
|
||||
parent[w] = vx;
|
||||
n = DFS(w, n);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void DominatorGraph::LINK(Uint32 vx, Uint32 w)
|
||||
{
|
||||
Uint32 s = w;
|
||||
|
||||
while (semi[label[w]] < semi[label[child[s]]]) {
|
||||
if (size[s] + size[child[child[s]]] >= (size[child[s]] << 1)) {
|
||||
ancestor[child[s]] = s;
|
||||
child[s] = child[child[s]];
|
||||
} else {
|
||||
size[child[s]] = size[s];
|
||||
s = ancestor[s] = child[s];
|
||||
}
|
||||
}
|
||||
label[s] = label[w];
|
||||
size[vx] += size[w];
|
||||
if(size[vx] < (size[w] << 1)) {
|
||||
Uint32 t = s;
|
||||
s = child[vx];
|
||||
child[vx] = t;
|
||||
}
|
||||
while( s != 0 ) {
|
||||
ancestor[s] = vx;
|
||||
s = child[s];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DominatorGraph::COMPRESS(Uint32 vx)
|
||||
{
|
||||
if(ancestor[ancestor[vx]] != 0) {
|
||||
COMPRESS(ancestor[vx]);
|
||||
if(semi[label[ancestor[vx]]] < semi[label[vx]])
|
||||
label[vx] = label[ancestor[vx]];
|
||||
ancestor[vx] = ancestor[ancestor[vx]];
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 DominatorGraph::EVAL(Uint32 vx)
|
||||
{
|
||||
if(ancestor[vx] == 0)
|
||||
return label[vx];
|
||||
COMPRESS(vx);
|
||||
return (semi[label[ancestor[vx]]] >= semi[label[vx]]) ? label[vx] : label[ancestor[vx]];
|
||||
}
|
||||
|
||||
void DominatorGraph::build()
|
||||
{
|
||||
Uint32 n = DFS(GtoV[0], 0);
|
||||
size[0] = label[0] = semi[0];
|
||||
|
||||
for (Uint32 i = n; i >= 2; i--) {
|
||||
Uint32 w = vertex[i];
|
||||
|
||||
ControlNode& node = *controlGraph.dfsList[VtoG[w]];
|
||||
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
||||
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
|
||||
Uint32 vx = GtoV[predecessors.get(p).getSource().dfsNum];
|
||||
Uint32 u = EVAL(vx);
|
||||
|
||||
if(semi[u] < semi[w])
|
||||
semi[w] = semi[u];
|
||||
}
|
||||
|
||||
DGLinkedList* elem = new DGLinkedList();
|
||||
elem->next = bucket[vertex[semi[w]]];
|
||||
elem->index = w;
|
||||
bucket[vertex[semi[w]]] = elem;
|
||||
|
||||
LINK(parent[w], w);
|
||||
|
||||
elem = bucket[parent[w]];
|
||||
while(elem != NULL) {
|
||||
Uint32 vx = elem->index;
|
||||
Uint32 u = EVAL(vx);
|
||||
dom[vx] = (semi[u] < semi[vx]) ? u : parent[w];
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
|
||||
memset(size, '\0', n * sizeof(Uint32));
|
||||
Pool& pool = controlGraph.pool;
|
||||
nodes = new(pool) DGNode[n];
|
||||
|
||||
for(Uint32 j = 2; j <= n; j++) {
|
||||
Uint32 w = vertex[j];
|
||||
Uint32 d = dom[w];
|
||||
if(d != vertex[semi[w]]) {
|
||||
d = dom[d];
|
||||
dom[w] = d;
|
||||
}
|
||||
size[d]++;
|
||||
}
|
||||
dom[GtoV[0]] = 0;
|
||||
|
||||
for (Uint32 k = 1; k <= n; k++) {
|
||||
DGNode& node = nodes[VtoG[k]];
|
||||
Uint32 count = size[k];
|
||||
node.successorsEnd = node.successorsBegin = (count) ? new(pool) Uint32[count] : (Uint32*) 0;
|
||||
}
|
||||
|
||||
for (Uint32 l = 2; l <= n; l++)
|
||||
*(nodes[VtoG[dom[l]]].successorsEnd)++ = VtoG[l];
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
void DominatorGraph::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Dominator Graph:\n"));
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
for (Uint32 i = 0; i < nNodes; i++) {
|
||||
DGNode& node = nodes[i];
|
||||
if (node.successorsBegin != node.successorsEnd) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tN%d dominates ", i));
|
||||
for (Uint32* successorsPtr = node.successorsBegin; successorsPtr < node.successorsEnd; successorsPtr++)
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d ", *successorsPtr));
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DOMINATOR_GRAPH_H_
|
||||
#define _DOMINATOR_GRAPH_H_
|
||||
|
||||
#include "LogModule.h"
|
||||
|
||||
class ControlGraph;
|
||||
|
||||
struct DGNode
|
||||
{
|
||||
Uint32* successorsBegin;
|
||||
Uint32* successorsEnd;
|
||||
};
|
||||
|
||||
struct DGLinkedList
|
||||
{
|
||||
DGLinkedList* next;
|
||||
Uint32 index;
|
||||
};
|
||||
|
||||
class DominatorGraph
|
||||
{
|
||||
private:
|
||||
|
||||
ControlGraph& controlGraph;
|
||||
|
||||
Uint32 vCount;
|
||||
|
||||
Uint32* VtoG;
|
||||
Uint32* GtoV;
|
||||
Uint32* parent;
|
||||
Uint32* semi;
|
||||
Uint32* vertex;
|
||||
Uint32* label;
|
||||
Uint32* size;
|
||||
Uint32* ancestor;
|
||||
Uint32* child;
|
||||
Uint32* dom;
|
||||
DGLinkedList** bucket;
|
||||
DGNode* nodes;
|
||||
|
||||
private:
|
||||
|
||||
void build();
|
||||
|
||||
Uint32 DFS(Uint32 vx, Uint32 n);
|
||||
void LINK(Uint32 vx, Uint32 w);
|
||||
void COMPRESS(Uint32 vx);
|
||||
Uint32 EVAL(Uint32 vx);
|
||||
|
||||
public:
|
||||
|
||||
DominatorGraph(ControlGraph& controlGraph);
|
||||
|
||||
Uint32* getSuccessorsBegin(Uint32 n) const {return nodes[n].successorsBegin;}
|
||||
Uint32* getSuccessorsEnd(Uint32 n) const {return nodes[n].successorsEnd;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
#endif // _DOMINATOR_GRAPH_H_
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
/* -*- 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
|
||||
@@ -16,4 +16,5 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
/* Nothing to do here. Add xpcom-specific defines here if necessary */
|
||||
#include "Fundamentals.h"
|
||||
#include "HashSet.h"
|
||||
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal file
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _HASH_SET_H_
|
||||
#define _HASH_SET_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include <string.h>
|
||||
|
||||
struct HashSetElement
|
||||
{
|
||||
Uint32 index;
|
||||
HashSetElement* next;
|
||||
};
|
||||
|
||||
class HashSet
|
||||
{
|
||||
private:
|
||||
|
||||
static const hashSize = 64;
|
||||
|
||||
// Return the hash code for the given element index.
|
||||
static Uint32 getHashCode(Uint32 index) {return index & (hashSize - 1);} // Could be better !
|
||||
|
||||
private:
|
||||
|
||||
Pool& allocationPool;
|
||||
HashSetElement** bucket;
|
||||
HashSetElement* free;
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
HashSet(const HashSet&);
|
||||
// No copy operator.
|
||||
void operator = (const HashSet&);
|
||||
|
||||
public:
|
||||
|
||||
// Create a new HashSet.
|
||||
inline HashSet(Pool& pool, Uint32 universeSize);
|
||||
|
||||
// Clear the hashset.
|
||||
void clear();
|
||||
// Clear the element for the given index.
|
||||
void clear(Uint32 index);
|
||||
// Set the element for the given index.
|
||||
void set(Uint32 index);
|
||||
// Return true if the element at index is a member.
|
||||
bool test(Uint32 index) const;
|
||||
// Union with the given hashset.
|
||||
inline void or(const HashSet& set);
|
||||
// Intersection with the given hashset.
|
||||
inline void and(const HashSet& set);
|
||||
// Difference with the given hashset.
|
||||
inline void difference(const HashSet& set);
|
||||
|
||||
// Logical operators.
|
||||
HashSet& operator |= (const HashSet& set) {or(set); return *this;}
|
||||
HashSet& operator &= (const HashSet& set) {and(set); return *this;}
|
||||
HashSet& operator -= (const HashSet& set) {difference(set); return *this;}
|
||||
|
||||
// Iterator to conform with the set API.
|
||||
typedef HashSetElement* iterator;
|
||||
// Return the iterator for the first element of this set.
|
||||
iterator begin() const;
|
||||
// Return the next iterator.
|
||||
iterator advance(iterator pos) const;
|
||||
// Return true if the iterator is at the end of the set.
|
||||
bool done(iterator pos) const {return pos == NULL;}
|
||||
};
|
||||
|
||||
|
||||
inline HashSet::HashSet(Pool& pool, Uint32 /*universeSize*/)
|
||||
: allocationPool(pool), free(NULL)
|
||||
{
|
||||
bucket = new(pool) HashSetElement*[hashSize];
|
||||
memset(bucket, '\0', sizeof(HashSetElement*));
|
||||
}
|
||||
|
||||
#endif // _HASH_SET_H_
|
||||
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal file
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _INDEXED_POOL_H_
|
||||
#define _INDEXED_POOL_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IndexedPool<IndexedObjectSubclass> is an indexed pool of objects. The
|
||||
// template parameter 'IndexedObjectSubclass' must be a subclass of the struct
|
||||
// IndexedObject.
|
||||
//
|
||||
// When the indexed pool is ask to allocate and initialize a new object (using
|
||||
// the operator new(anIndexedPool) it will zero the memory used to store the
|
||||
// object and initialize the field 'index' of this object to its position in
|
||||
// the pool.
|
||||
//
|
||||
// An object allocated by the indexed pool can be freed by calling the method
|
||||
// IndexedPool::release(IndexedElement& objectIndex).
|
||||
//
|
||||
// example:
|
||||
//
|
||||
// IndexedPool<IndexedElement> elementPool;
|
||||
//
|
||||
// IndexedElement& element1 = *new(elementPool) IndexedElement();
|
||||
// IndexedElement& element2 = *new(elementPool) IndexedElement();
|
||||
//
|
||||
// indexedPool.release(element1);
|
||||
// IndexedElement& element3 = *new(elementPool) IndexedElement();
|
||||
//
|
||||
// At this point element1 is no longer a valid object, element2 is at
|
||||
// index 2 and element3 is at index 1.
|
||||
//
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IndexedObject -
|
||||
//
|
||||
|
||||
template<class Object>
|
||||
struct IndexedObject
|
||||
{
|
||||
Uint32 index; // Index in the pool.
|
||||
Object* next; // Used to link IndexedObject together.
|
||||
|
||||
Uint32 getIndex() {return index;}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IndexedPool<IndexedObject> -
|
||||
//
|
||||
|
||||
template <class IndexedObject>
|
||||
class IndexedPool
|
||||
{
|
||||
private:
|
||||
|
||||
static const blockSize = 4; // Size of one block.
|
||||
|
||||
Uint32 nBlocks; // Number of blocks in the pool.
|
||||
IndexedObject** block; // Array of block pointers.
|
||||
IndexedObject* freeObjects; // Chained list of free IndexedObjects.
|
||||
Uint32 nextIndex; // Index of the next free object in the last block.
|
||||
|
||||
private:
|
||||
|
||||
void allocateAnotherBlock();
|
||||
IndexedObject& newObject();
|
||||
|
||||
public:
|
||||
|
||||
IndexedPool() : nBlocks(0), block(NULL), freeObjects(NULL), nextIndex(1) {}
|
||||
~IndexedPool();
|
||||
|
||||
IndexedObject& get(Uint32 index) const;
|
||||
void release(IndexedObject& object);
|
||||
|
||||
void setSize(Uint32 size) {assert(size < nextIndex); nextIndex = size;}
|
||||
|
||||
// Return the universe size.
|
||||
Uint32 getSize() {return nextIndex;}
|
||||
|
||||
friend void* operator new(size_t, IndexedPool<IndexedObject>& pool); // Needs to call newObject().
|
||||
};
|
||||
|
||||
// Free all the memory allocated for this object.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
IndexedPool<IndexedObject>::~IndexedPool()
|
||||
{
|
||||
for (Uint32 n = 0; n < nBlocks; n++)
|
||||
free(&((IndexedObject **) &block[n][n*blockSize])[-(n + 1)]);
|
||||
}
|
||||
|
||||
// Release the given. This object will be iserted in the chained
|
||||
// list of free IndexedObjects. To minimize the fragmentation the chained list
|
||||
// is ordered by ascending indexes.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
void IndexedPool<IndexedObject>::release(IndexedObject& object)
|
||||
{
|
||||
Uint32 index = object.index;
|
||||
IndexedObject* list = freeObjects;
|
||||
|
||||
assert(&object == &get(index)); // Make sure that object is owned by this pool.
|
||||
|
||||
if (list == NULL) { // The list is empty.
|
||||
freeObjects = &object;
|
||||
object.next = NULL;
|
||||
} else { // The list contains at least 1 element.
|
||||
if (index < list->index) { // insert as first element.
|
||||
freeObjects = &object;
|
||||
object.next = list;
|
||||
} else { // Find this object's place.
|
||||
while ((list->next) != NULL && (list->next->index < index))
|
||||
list = list->next;
|
||||
|
||||
object.next = list->next;
|
||||
list->next = &object;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Sanity check to be sure that the list is correctly ordered.
|
||||
for (IndexedObject* obj = freeObjects; obj != NULL; obj = obj->next)
|
||||
if (obj->next != NULL)
|
||||
assert(obj->index < obj->next->index);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a new block of IndexedObjects. We will allocate the memory to
|
||||
// store IndexedPool::blockSize IndexedObject and the new Array of block
|
||||
// pointers.
|
||||
// The newly created IndexedObjects will not be initialized.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
void IndexedPool<IndexedObject>::allocateAnotherBlock()
|
||||
{
|
||||
void* memory = (void *) malloc((nBlocks + 1) * sizeof(Uint32) + blockSize * sizeof(IndexedObject));
|
||||
|
||||
memcpy(memory, block, nBlocks * sizeof(Uint32));
|
||||
|
||||
block = (IndexedObject **) memory;
|
||||
IndexedObject* objects = (IndexedObject *) &block[nBlocks + 1];
|
||||
|
||||
block[nBlocks] = &objects[-(nBlocks * blockSize)];
|
||||
nBlocks++;
|
||||
}
|
||||
|
||||
// Return the IndexedObject at the position 'index' in the pool.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
IndexedObject& IndexedPool<IndexedObject>::get(Uint32 index) const
|
||||
{
|
||||
Uint32 blockIndex = index / blockSize;
|
||||
assert(blockIndex < nBlocks);
|
||||
|
||||
return block[blockIndex][index];
|
||||
}
|
||||
|
||||
// Return the reference of an unused object in the pool.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
IndexedObject& IndexedPool<IndexedObject>::newObject()
|
||||
{
|
||||
if (freeObjects != NULL) {
|
||||
IndexedObject& newObject = *freeObjects;
|
||||
freeObjects = newObject.next;
|
||||
return newObject;
|
||||
}
|
||||
|
||||
Uint32 nextIndex = this->nextIndex++;
|
||||
Uint32 blockIndex = nextIndex / blockSize;
|
||||
|
||||
while (blockIndex >= nBlocks)
|
||||
allocateAnotherBlock();
|
||||
|
||||
IndexedObject& newObject = block[blockIndex][nextIndex];
|
||||
newObject.index = nextIndex;
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
// Return the address of the next unsused object in the given
|
||||
// indexed pool. The field index of the newly allocated object
|
||||
// will be initialized to the corresponding index of this object
|
||||
// in the pool.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
void* operator new(size_t size, IndexedPool<IndexedObject>& pool)
|
||||
{
|
||||
assert(size == sizeof(IndexedObject));
|
||||
return (void *) &pool.newObject();
|
||||
}
|
||||
|
||||
#endif // _INDEXED_POOL_H_
|
||||
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal file
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal file
@@ -0,0 +1,258 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _INTERFERENCE_GRAPH_H_
|
||||
#define _INTERFERENCE_GRAPH_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "Primitives.h"
|
||||
#include "Instruction.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "SparseSet.h"
|
||||
#include <string.h>
|
||||
|
||||
struct InterferenceVector
|
||||
{
|
||||
Uint32 count;
|
||||
InterferenceVector* next;
|
||||
RegisterName* neighbors;
|
||||
|
||||
InterferenceVector() : count(0), next(NULL) {}
|
||||
};
|
||||
|
||||
class RegisterAllocator;
|
||||
|
||||
template <class RegisterPressure>
|
||||
class InterferenceGraph
|
||||
{
|
||||
private:
|
||||
|
||||
RegisterAllocator& registerAllocator;
|
||||
|
||||
RegisterPressure::Set* interferences;
|
||||
InterferenceVector** vector;
|
||||
Uint32* offset;
|
||||
Uint32 rangeCount;
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
InterferenceGraph(const InterferenceGraph&);
|
||||
// No copy operator.
|
||||
void operator = (const InterferenceGraph&);
|
||||
|
||||
// Check if reg is a member of the universe.
|
||||
void checkMember(RegisterName name) {assert(name < rangeCount);}
|
||||
// Return the edge index for the interference between name1 and name2.
|
||||
Uint32 getEdgeIndex(RegisterName name1, RegisterName name2);
|
||||
|
||||
public:
|
||||
InterferenceGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
|
||||
|
||||
// Calculate the interferences.
|
||||
void build();
|
||||
// Return true if reg1 and reg2 interfere.
|
||||
bool interfere(RegisterName name1, RegisterName name2);
|
||||
// Return the interference vector for the given register or NULL if there is none.
|
||||
InterferenceVector* getInterferenceVector(RegisterName name) {return vector[name];}
|
||||
// Set the interference between name1 and name2.
|
||||
void setInterference(RegisterName name1, RegisterName name2);
|
||||
// Set the interference vector for the given register.
|
||||
void setInterferenceVector(RegisterName name, InterferenceVector* v) {vector[name] = v;}
|
||||
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the interferences.
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void InterferenceGraph<RegisterPressure>::build()
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
this->rangeCount = rangeCount;
|
||||
|
||||
// Initialize the structures.
|
||||
//
|
||||
offset = new(pool) Uint32[rangeCount + 1];
|
||||
vector = new(pool) InterferenceVector*[rangeCount];
|
||||
memset(vector, '\0', sizeof(InterferenceVector*) * rangeCount);
|
||||
|
||||
Uint32 o = 0;
|
||||
offset[0] = 0;
|
||||
for (Uint32 i = 1; i <= rangeCount; ++i) {
|
||||
offset[i] = o;
|
||||
o += i;
|
||||
}
|
||||
|
||||
interferences = new(pool) RegisterPressure::Set(pool, (rangeCount * rangeCount) / 2);
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
LivenessInfo<RegisterPressure> liveness = Liveness<RegisterPressure>::analysis(controlGraph, rangeCount, name2range);
|
||||
registerAllocator.liveness = liveness;
|
||||
SparseSet currentLive(pool, rangeCount);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
currentLive = liveness.liveOut[n];
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
// Handle the copy instruction to avoid unnecessary interference between the 2 registers.
|
||||
if ((instruction.getFlags() & ifCopy) != 0) {
|
||||
assert(useBegin != useEnd && useBegin[0].isRegister());
|
||||
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
|
||||
}
|
||||
|
||||
// Create the interferences.
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName define = name2range[definePtr->getRegisterName()];
|
||||
|
||||
for (SparseSet::iterator e = currentLive.begin(); !currentLive.done(e); e = currentLive.advance(e)) {
|
||||
RegisterName live = RegisterName(currentLive.get(e));
|
||||
|
||||
if ((live != define) && !interfere(live, define) && registerAllocator.canInterfere(live, define)) {
|
||||
|
||||
if (vector[define] == NULL)
|
||||
vector[define] = new(pool) InterferenceVector();
|
||||
vector[define]->count++;
|
||||
|
||||
if (vector[live] == NULL)
|
||||
vector[live] = new(pool) InterferenceVector();
|
||||
vector[live]->count++;
|
||||
|
||||
setInterference(live, define);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now update the liveness.
|
||||
//
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentLive.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
currentLive.set(name2range[usePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the memory to store the interferences.
|
||||
//
|
||||
for (Uint32 e = 0; e < rangeCount; e++)
|
||||
if (vector[e] != NULL) {
|
||||
InterferenceVector& v = *vector[e];
|
||||
v.neighbors = new(pool) RegisterName[v.count];
|
||||
v.count = 0;
|
||||
}
|
||||
|
||||
// Initialize the edges.
|
||||
//
|
||||
if (RegisterPressure::Set::isOrdered()) {
|
||||
RegisterName name1 = RegisterName(0);
|
||||
|
||||
for (RegisterPressure::Set::iterator i = interferences->begin(); !interferences->done(i); i = interferences->advance(i)) {
|
||||
Uint32 interferenceIndex = interferences->get(i);
|
||||
|
||||
while(interferenceIndex >= offset[name1 + 1])
|
||||
name1 = RegisterName(name1 + 1);
|
||||
|
||||
assert((interferenceIndex >= offset[name1]) && (interferenceIndex < offset[name1 + 1]));
|
||||
|
||||
RegisterName name2 = RegisterName(interferenceIndex - offset[name1]);
|
||||
|
||||
assert(interfere(name1, name2));
|
||||
|
||||
InterferenceVector& vector1 = *vector[name1];
|
||||
vector1.neighbors[vector1.count++] = name2;
|
||||
|
||||
InterferenceVector& vector2 = *vector[name2];
|
||||
vector2.neighbors[vector2.count++] = name1;
|
||||
}
|
||||
} else {
|
||||
trespass("not Implemented"); // FIX: need one more pass to initialize the vectors.
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
Uint32 InterferenceGraph<RegisterPressure>::getEdgeIndex(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
checkMember(name1); checkMember(name2);
|
||||
assert(name1 != name2); // This is not possible.
|
||||
return (name1 < name2) ? offset[name2] + name1 : offset[name1] + name2;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void InterferenceGraph<RegisterPressure>::setInterference(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
interferences->set(getEdgeIndex(name1, name2));
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool InterferenceGraph<RegisterPressure>::interfere(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
return interferences->test(getEdgeIndex(name1, name2));
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
template <class RegisterPressure>
|
||||
void InterferenceGraph<RegisterPressure>::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Vectors:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++) {
|
||||
if (vector[i] != NULL) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tvr%d: (", i));
|
||||
for (InterferenceVector* v = vector[i]; v != NULL; v = v->next)
|
||||
for (Uint32 j = 0; j < v->count; j++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", v->neighbors[j]));
|
||||
if (v->next != NULL || j != (v->count - 1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (","));
|
||||
}
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (")\n"));
|
||||
}
|
||||
}
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Matrix:\n"));
|
||||
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
|
||||
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && interfere(name1, name2)) ? '1' : '0'));
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
#endif // _INTERFERENCE_GRAPH_H_
|
||||
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal file
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIVE_RANGE_H_
|
||||
#define _LIVE_RANGE_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Primitives.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct LiveRange
|
||||
{
|
||||
static void build(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void LiveRange<RegisterPressure>::build(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
// Intialize the lookup table.
|
||||
//
|
||||
Uint32 nameCount = registerAllocator.nameCount;
|
||||
RegisterName* nameTable = new(registerAllocator.pool) RegisterName[2*nameCount];
|
||||
RegisterName* rangeName = &nameTable[nameCount];
|
||||
|
||||
init(rangeName, nameCount);
|
||||
|
||||
// Walk the graph.
|
||||
//
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
SparseSet destination(registerAllocator.pool, nameCount);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
|
||||
destination.clear();
|
||||
for (InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
||||
Instruction& phiNode = phiNodes.get(i);
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
|
||||
destination.set(findRoot(phiNode.getInstructionDefineBegin()[0].getRegisterName(), rangeName));
|
||||
}
|
||||
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
|
||||
RegisterName destinationName = phiNode.getInstructionDefineBegin()[0].getRegisterName();
|
||||
RegisterName destinationRoot = findRoot(destinationName, rangeName);
|
||||
|
||||
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
|
||||
assert(usePtr->isRegister());
|
||||
RegisterName sourceName = usePtr->getRegisterName();
|
||||
RegisterName sourceRoot = findRoot(sourceName, rangeName);
|
||||
|
||||
if (sourceRoot != destinationRoot && !destination.test(sourceRoot))
|
||||
rangeName[sourceRoot] = destinationRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAllocator.rangeCount = compress(registerAllocator.name2range, rangeName, nameCount, nameCount);
|
||||
}
|
||||
|
||||
#endif // _LIVE_RANGE_H_
|
||||
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal file
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIVE_RANGE_GRAPH_
|
||||
#define _LIVE_RANGE_GRAPH_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
class RegisterAllocator;
|
||||
|
||||
template <class RegisterPressure>
|
||||
class LiveRangeGraph
|
||||
{
|
||||
private:
|
||||
|
||||
RegisterAllocator& registerAllocator;
|
||||
|
||||
RegisterPressure::Set* edges;
|
||||
Uint32 rangeCount;
|
||||
|
||||
public:
|
||||
//
|
||||
//
|
||||
LiveRangeGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
|
||||
|
||||
//
|
||||
//
|
||||
void build();
|
||||
|
||||
//
|
||||
//
|
||||
void addEdge(RegisterName name1, RegisterName name2);
|
||||
|
||||
//
|
||||
//
|
||||
bool haveEdge(RegisterName name1, RegisterName name2);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
//
|
||||
//
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void LiveRangeGraph<RegisterPressure>::build()
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
this->rangeCount = rangeCount;
|
||||
|
||||
edges = new(pool) RegisterPressure::Set(pool, rangeCount * rangeCount);
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
LivenessInfo<RegisterPressure>& liveness = registerAllocator.liveness;
|
||||
SparseSet currentLive(pool, rangeCount);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
currentLive = liveness.liveOut[n];
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
if ((instruction.getFlags() & ifCopy) != 0) {
|
||||
assert(useBegin != useEnd && useBegin[0].isRegister());
|
||||
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName define = name2range[definePtr->getRegisterName()];
|
||||
|
||||
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
|
||||
RegisterName live = RegisterName(currentLive.get(l));
|
||||
if (define != live && registerAllocator.canInterfere(define, live))
|
||||
addEdge(define, live);
|
||||
}
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentLive.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
currentLive.set(name2range[usePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName use = name2range[usePtr->getRegisterName()];
|
||||
|
||||
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
|
||||
RegisterName live = RegisterName(currentLive.get(l));
|
||||
if (use != live && registerAllocator.canInterfere(use, live))
|
||||
addEdge(use, live);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void LiveRangeGraph<RegisterPressure>::addEdge(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
assert(name1 != name2);
|
||||
edges->set(name1 * rangeCount + name2);
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool LiveRangeGraph<RegisterPressure>::haveEdge(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
assert(name1 != name2);
|
||||
return edges->test(name1 * rangeCount + name2);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
template <class RegisterPressure>
|
||||
void LiveRangeGraph<RegisterPressure>::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Live ranges graph:\n"));
|
||||
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
|
||||
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && haveEdge(name1, name2)) ? '1' : '0'));
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
#endif // _LIVE_RANGE_GRAPH_
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
/* -*- 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
|
||||
@@ -16,12 +16,6 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
//
|
||||
// xpcom.Prefix
|
||||
//
|
||||
// Global prefix file for the xpcom project.
|
||||
//
|
||||
//
|
||||
#include "Fundamentals.h"
|
||||
#include "Liveness.h"
|
||||
|
||||
#include "MacPrefix.h"
|
||||
#include "xpcomConfig.h"
|
||||
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal file
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal file
@@ -0,0 +1,301 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIVENESS_H_
|
||||
#define _LIVENESS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// LivenessInfo -
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct LivenessInfo
|
||||
{
|
||||
RegisterPressure::Set* liveIn;
|
||||
RegisterPressure::Set* liveOut;
|
||||
DEBUG_LOG_ONLY(Uint32 size);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Liveness
|
||||
//
|
||||
// The liveness is defined by the following data-flow equations:
|
||||
//
|
||||
// LiveIn(n) = LocalLive(n) U (LiveOut(n) - Killed(n)).
|
||||
// LiveOut(n) = U LiveIn(s) (s a successor of n).
|
||||
//
|
||||
// where LocalLive(n) is the set of used registers in the block n, Killed(n)
|
||||
// is the set of defined registers in the block n, LiveIn(n) is the set of
|
||||
// live registers at the begining of the block n and LiveOut(n) is the set
|
||||
// of live registers at the end of the block n.
|
||||
//
|
||||
//
|
||||
// We will compute the liveness analysis in two stages:
|
||||
//
|
||||
// 1- Build LocalLive(n) (wich is an approximation of LiveIn(n)) and Killed(n)
|
||||
// for each block n.
|
||||
// 2- Perform a backward data-flow analysis to propagate the liveness information
|
||||
// through the entire control-flow graph.
|
||||
//
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct Liveness
|
||||
{
|
||||
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range);
|
||||
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 nameCount);
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
// Allocate the temporary sets.
|
||||
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
|
||||
|
||||
// Allocate the globals sets.
|
||||
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
|
||||
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
|
||||
|
||||
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
|
||||
//
|
||||
for (Uint32 n = 0; n < (nNodes - 1); n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLocalLive = liveIn[n];
|
||||
RegisterPressure::Set& currentKilled = killed[n];
|
||||
|
||||
// Find the instructions contributions to the sets LocalLive and Killed.
|
||||
//
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
Uint32 index = name2range[usePtr->getRegisterName()];
|
||||
|
||||
if (!currentKilled.test(index))
|
||||
currentLocalLive.set(index);
|
||||
}
|
||||
|
||||
// If a Virtualregister is 'defined' then we add it to the set Killed.
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentKilled.set(name2range[definePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
|
||||
// control-flow graph.
|
||||
//
|
||||
RegisterPressure::Set temp(pool, rangeCount);
|
||||
|
||||
bool changed;
|
||||
do {
|
||||
changed = false;
|
||||
|
||||
// For all nodes is this graph except the endNode.
|
||||
for (Int32 n = (nNodes - 2); n >= 0; n--) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLiveIn = liveIn[n];
|
||||
RegisterPressure::Set& currentLiveOut = liveOut[n];
|
||||
|
||||
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
|
||||
// temp will be the new LiveOut(n).
|
||||
Uint32 nSuccessors = node.nSuccessors();
|
||||
if (nSuccessors != 0) {
|
||||
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
|
||||
for (Uint32 s = 1; s < nSuccessors; s++)
|
||||
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
|
||||
} else
|
||||
temp.clear();
|
||||
|
||||
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
|
||||
// new LiveIn(n).
|
||||
if (currentLiveOut != temp) {
|
||||
currentLiveOut = temp;
|
||||
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
|
||||
temp |= currentLiveIn;
|
||||
|
||||
if (currentLiveIn != temp) {
|
||||
currentLiveIn = temp;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(changed);
|
||||
|
||||
LivenessInfo<RegisterPressure> liveness;
|
||||
liveness.liveIn = liveIn;
|
||||
liveness.liveOut = liveOut;
|
||||
DEBUG_LOG_ONLY(liveness.size = nNodes);
|
||||
return liveness;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 nameCount)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
// Allocate the temporary sets.
|
||||
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
RegisterPressure::Set* usedByPhiNodes = NULL;
|
||||
|
||||
// Allocate the globals sets.
|
||||
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
|
||||
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
|
||||
//
|
||||
for (Uint32 n = 0; n < (nNodes - 1); n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLocalLive = liveIn[n];
|
||||
RegisterPressure::Set& currentKilled = killed[n];
|
||||
|
||||
InstructionList& phiNodes = node.getPhiNodeInstructions();
|
||||
|
||||
if ((usedByPhiNodes == NULL) && !phiNodes.empty())
|
||||
usedByPhiNodes = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
InstructionDefine& define = phiNode.getInstructionDefineBegin()[0];
|
||||
currentKilled.set(define.getRegisterName());
|
||||
|
||||
typedef DoublyLinkedList<ControlEdge> ControlEdgeList;
|
||||
const ControlEdgeList& predecessors = node.getPredecessors();
|
||||
ControlEdgeList::iterator p = predecessors.begin();
|
||||
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++, p = predecessors.advance(p))
|
||||
if (usePtr->isRegister())
|
||||
usedByPhiNodes[predecessors.get(p).getSource().dfsNum].set(usePtr->getRegisterName());
|
||||
}
|
||||
|
||||
// Find the instructions contributions to the sets LocalLive and Killed.
|
||||
//
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
Uint32 index = usePtr->getRegisterName();
|
||||
|
||||
if (!currentKilled.test(index))
|
||||
currentLocalLive.set(index);
|
||||
}
|
||||
|
||||
// If a Virtualregister is 'defined' then we add it to the set Killed.
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentKilled.set(definePtr->getRegisterName());
|
||||
}
|
||||
}
|
||||
|
||||
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
|
||||
// control-flow graph.
|
||||
//
|
||||
RegisterPressure::Set temp(pool, nameCount);
|
||||
|
||||
bool changed;
|
||||
do {
|
||||
changed = false;
|
||||
|
||||
// For all nodes is this graph except the endNode.
|
||||
for (Int32 n = (nNodes - 2); n >= 0; n--) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLiveIn = liveIn[n];
|
||||
RegisterPressure::Set& currentLiveOut = liveOut[n];
|
||||
|
||||
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
|
||||
// temp will be the new LiveOut(n).
|
||||
Uint32 nSuccessors = node.nSuccessors();
|
||||
if (nSuccessors != 0) {
|
||||
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
|
||||
for (Uint32 s = 1; s < nSuccessors; s++)
|
||||
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
|
||||
} else
|
||||
temp.clear();
|
||||
|
||||
// Insert the phiNodes contribution.
|
||||
if (usedByPhiNodes != NULL)
|
||||
temp |= usedByPhiNodes[n];
|
||||
|
||||
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
|
||||
// new LiveIn(n).
|
||||
if (currentLiveOut != temp) {
|
||||
currentLiveOut = temp;
|
||||
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
|
||||
temp |= currentLiveIn;
|
||||
|
||||
if (currentLiveIn != temp) {
|
||||
currentLiveIn = temp;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(changed);
|
||||
|
||||
LivenessInfo<RegisterPressure> liveness;
|
||||
liveness.liveIn = liveIn;
|
||||
liveness.liveOut = liveOut;
|
||||
DEBUG_LOG_ONLY(liveness.size = nNodes);
|
||||
return liveness;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
template <class RegisterPressure>
|
||||
void LivenessInfo<RegisterPressure>::printPretty(LogModuleObject log)
|
||||
{
|
||||
for (Uint32 n = 0; n < size; n++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Node N%d:\n\tliveIn = ", n));
|
||||
liveIn[n].printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tliveOut = "));
|
||||
liveOut[n].printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
#endif // _LIVENESS_H_
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
#! gmake
|
||||
|
||||
DEPTH = ../..
|
||||
|
||||
MODULE_NAME = RegisterAllocator
|
||||
|
||||
include $(DEPTH)/config/config.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I$(DEPTH)/Utilities/General \
|
||||
-I$(DEPTH)/Utilities/zlib \
|
||||
-I$(DEPTH)/Runtime/ClassReader \
|
||||
-I$(DEPTH)/Runtime/NativeMethods \
|
||||
-I$(DEPTH)/Runtime/System \
|
||||
-I$(DEPTH)/Runtime/ClassInfo \
|
||||
-I$(DEPTH)/Runtime/FileReader \
|
||||
-I$(DEPTH)/Compiler/PrimitiveGraph \
|
||||
-I$(DEPTH)/Compiler/FrontEnd \
|
||||
-I$(DEPTH)/Compiler/Optimizer \
|
||||
-I$(DEPTH)/Compiler/CodeGenerator \
|
||||
-I$(DEPTH)/Compiler/CodeGenerator/md \
|
||||
-I$(DEPTH)/Compiler/CodeGenerator/md/$(CPU_ARCH) \
|
||||
-I$(DEPTH)/Compiler/RegisterAllocator \
|
||||
-I$(DEPTH)/Driver/StandAloneJava \
|
||||
-I$(DEPTH)/Debugger \
|
||||
$(NULL)
|
||||
|
||||
CXXSRCS = \
|
||||
RegisterAllocator.cpp \
|
||||
RegisterAllocatorTools.cpp \
|
||||
DominatorGraph.cpp \
|
||||
VirtualRegister.cpp \
|
||||
BitSet.cpp \
|
||||
SparseSet.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
libs:: $(MODULE)
|
||||
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal file
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal file
@@ -0,0 +1,392 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _PHI_NODE_REMOVER_H_
|
||||
#define _PHI_NODE_REMOVER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "DominatorGraph.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "Liveness.h"
|
||||
#include "Instruction.h"
|
||||
#include "InstructionEmitter.h"
|
||||
#include "SparseSet.h"
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterNameNode -
|
||||
|
||||
struct RegisterNameNode
|
||||
{
|
||||
RegisterNameNode* next;
|
||||
RegisterName newName;
|
||||
Uint32 nextPushed;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CopyData -
|
||||
|
||||
struct CopyData
|
||||
{
|
||||
RegisterName source;
|
||||
RegisterClassKind classKind;
|
||||
Uint32 useCount;
|
||||
bool isLiveOut;
|
||||
RegisterName sourceNameToUse;
|
||||
RegisterName temporaryName;
|
||||
RegisterNameNode* newName;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PhiNodeRemover<RegisterPressure> -
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct PhiNodeRemover
|
||||
{
|
||||
// Replace the phi nodes by copy instructions.
|
||||
static void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
|
||||
};
|
||||
|
||||
// Split some of the critical edges and return true if there are still some
|
||||
// in the graph after that.
|
||||
//
|
||||
static bool splitCriticalEdges(ControlGraph& /*cg*/)
|
||||
{
|
||||
// FIX: not implemented.
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void pushName(Pool& pool, RegisterNameNode** stack, SparseSet& pushed, Uint32* nodeListPointer, RegisterName oldName, RegisterName newName)
|
||||
{
|
||||
RegisterNameNode& newNode = *new(pool) RegisterNameNode();
|
||||
|
||||
if (pushed.test(oldName))
|
||||
(*stack)->newName = newName;
|
||||
else {
|
||||
newNode.newName = newName;
|
||||
newNode.nextPushed = *nodeListPointer;
|
||||
*nodeListPointer = oldName;
|
||||
newNode.next = *stack;
|
||||
*stack = &newNode;
|
||||
pushed.set(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void PhiNodeRemover<RegisterPressure>::replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
// Initialize the local variables.
|
||||
//
|
||||
|
||||
// When we insert the copies we will also need to create new VirtualRegisters for
|
||||
// the insertion of temporaries. The maximum number of temporary register will not
|
||||
// exceed the number of phiNodes in the primitive graph.
|
||||
Uint32 nameCount = vrManager.getSize();
|
||||
Uint32 maxNameCount = nameCount;
|
||||
for (Uint32 n = 0; n < nNodes; n++)
|
||||
maxNameCount += nodes[n]->getPhiNodes().length();
|
||||
|
||||
// If the CFG contains some critical edges (backward edge which source has more than one
|
||||
// outgoing edge and destination has more than one incomimg edge) then we need the liveness
|
||||
// information to be able to insert temporary copies.
|
||||
RegisterPressure::Set* liveOut = NULL;
|
||||
if (splitCriticalEdges(controlGraph))
|
||||
liveOut = Liveness<LowRegisterPressure>::analysis(controlGraph, nameCount).liveOut;
|
||||
|
||||
DominatorGraph dGraph(controlGraph);
|
||||
|
||||
SparseSet pushed(pool, maxNameCount);
|
||||
SparseSet destinationList(pool, maxNameCount);
|
||||
SparseSet workList(pool, maxNameCount);
|
||||
|
||||
CopyData* copyStats = new(pool) CopyData[maxNameCount];
|
||||
memset(copyStats, '\0', maxNameCount*sizeof(CopyData));
|
||||
|
||||
struct NodeStack {
|
||||
Uint32* next;
|
||||
Uint32* limit;
|
||||
Uint32 pushedList;
|
||||
};
|
||||
|
||||
// Allocate the node stack and initialize the node stack pointer.
|
||||
NodeStack* nodeStack = new(pool) NodeStack[nNodes + 1];
|
||||
NodeStack* nodeStackPtr = nodeStack;
|
||||
|
||||
// We start by the begin node.
|
||||
Uint32 startNode = 0;
|
||||
Uint32* next = &startNode;
|
||||
Uint32* limit = &startNode + 1;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (next == limit) {
|
||||
// If there are no more node in the sibling, we have to pop the current
|
||||
// frame from the stack and update the copyStats of the pushed nodes.
|
||||
//
|
||||
if (nodeStackPtr == nodeStack)
|
||||
// We are at the bottom of the stack and there are no more nodes
|
||||
// to look at. We are done !
|
||||
break;
|
||||
|
||||
--nodeStackPtr;
|
||||
// We are done with all the children of this node in the dominator tree.
|
||||
// We need to update the copy information of all the new names pushed
|
||||
// during the walk over this node.
|
||||
Uint32 pushedList = nodeStackPtr->pushedList;
|
||||
while (pushedList != 0) {
|
||||
Uint32 nextName = copyStats[pushedList].newName->nextPushed;
|
||||
copyStats[pushedList].newName = copyStats[pushedList].newName->next;
|
||||
pushedList = nextName;
|
||||
}
|
||||
|
||||
// restore the previous frame.
|
||||
next = nodeStackPtr->next;
|
||||
limit = nodeStackPtr->limit;
|
||||
} else {
|
||||
Uint32 currentNode = *next++;
|
||||
Uint32 pushedList = 0;
|
||||
|
||||
|
||||
// Initialize the sets.
|
||||
pushed.clear();
|
||||
destinationList.clear();
|
||||
|
||||
// STEP1:
|
||||
// Walk the instruction list and to replace all the instruction uses with their new name.
|
||||
// If the instruction is a phi node and its defined register is alive at the end of this
|
||||
// block then we push the defined register into the stack.
|
||||
//
|
||||
ControlNode& node = *nodes[currentNode];
|
||||
RegisterPressure::Set* currentLiveOut = (liveOut != NULL) ? &liveOut[currentNode] : (RegisterPressure::Set*) 0;
|
||||
|
||||
InstructionList& phiNodes = node.getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
|
||||
assert(usePtr->isRegister());
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
|
||||
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
|
||||
usePtr->setRegisterName(copyStats[name].newName->newName);
|
||||
}
|
||||
|
||||
if (currentLiveOut != NULL) {
|
||||
// This is a phi node and we have to push its defined name if it is live
|
||||
// at the end of the node. We only need to do this if the CFG has critical edges.
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
|
||||
RegisterName name = phiNode.getInstructionDefineBegin()[0].getRegisterName();
|
||||
|
||||
if (currentLiveOut->test(name))
|
||||
pushName(pool, &(copyStats[name].newName), pushed, &pushedList, name, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
|
||||
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
|
||||
usePtr->setRegisterName(copyStats[name].newName->newName);
|
||||
}
|
||||
}
|
||||
|
||||
// STEP2:
|
||||
// Look at this node's successors' phiNodes. We keep track of the number of time
|
||||
// a VR will be used by another copy instruction and insert each definition into the
|
||||
// destinationList. This is the only pass over this node's successors as we will
|
||||
// get all the information we need in the CopyData structures.
|
||||
//
|
||||
ControlEdge* successorEdgeEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorEdgePtr = node.getSuccessorsBegin(); successorEdgePtr < successorEdgeEnd; successorEdgePtr++) {
|
||||
Uint32 useIndex = successorEdgePtr->getIndex();
|
||||
ControlNode& successor = successorEdgePtr->getTarget();
|
||||
|
||||
// Look at its phi nodes. The phi nodes are at the top of the instruction list. We exit
|
||||
// as soon as we find an instruction which is not a phi node
|
||||
InstructionList& phiNodes = successor.getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
assert((phiNode.getInstructionUseBegin() + useIndex) < phiNode.getInstructionUseEnd());
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd());
|
||||
|
||||
InstructionUse& source = phiNode.getInstructionUseBegin()[useIndex];
|
||||
InstructionDefine& destination = phiNode.getInstructionDefineBegin()[0];
|
||||
|
||||
assert(source.isRegister() && destination.isRegister());
|
||||
|
||||
RegisterName sourceName = source.getRegisterName();
|
||||
RegisterName destinationName = destination.getRegisterName();
|
||||
|
||||
// Get the correct name for the source.
|
||||
if (copyStats[sourceName].newName != NULL)
|
||||
sourceName = copyStats[sourceName].newName->newName;
|
||||
|
||||
// Update the CopyData structures.
|
||||
if ((sourceName != rnInvalid) && (sourceName != destinationName)) {
|
||||
copyStats[destinationName].source = sourceName;
|
||||
copyStats[destinationName].classKind = destination.getRegisterClass();
|
||||
copyStats[destinationName].isLiveOut = (currentLiveOut != NULL) ? currentLiveOut->test(destinationName) : false;
|
||||
copyStats[destinationName].sourceNameToUse = destinationName;
|
||||
copyStats[sourceName].sourceNameToUse = sourceName;
|
||||
copyStats[sourceName].useCount++;
|
||||
destinationList.set(destinationName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// STEP3:
|
||||
// Insert into the worklist only the destination registers that will be not used in
|
||||
// another copy instruction in this block.
|
||||
//
|
||||
assert(workList.getSize() == 0);
|
||||
for (SparseSet::iterator d = destinationList.begin(); !destinationList.done(d); d = destinationList.advance(d)) {
|
||||
Uint32 dest = destinationList.get(d);
|
||||
if (copyStats[dest].useCount == 0)
|
||||
workList.set(dest);
|
||||
}
|
||||
|
||||
// STEP4:
|
||||
// Insert the copy instructions.
|
||||
//
|
||||
Uint32 destinationListSize = destinationList.getSize();
|
||||
InstructionList::iterator endOfTheNode = instructions.end();
|
||||
|
||||
// Find the right place to insert the copy instructions.
|
||||
if (destinationListSize != 0)
|
||||
while (instructions.get(endOfTheNode).getFlags() & ifControl)
|
||||
endOfTheNode = instructions.retreat(endOfTheNode);
|
||||
|
||||
while (destinationListSize != 0) {
|
||||
while(workList.getSize()) {
|
||||
RegisterName destinationName = RegisterName(workList.getOne());
|
||||
RegisterName sourceName = copyStats[destinationName].source;
|
||||
|
||||
workList.clear(destinationName);
|
||||
if (copyStats[destinationName].isLiveOut && !copyStats[destinationName].temporaryName) {
|
||||
// Lost copy problem.
|
||||
copyStats[destinationName].isLiveOut = false;
|
||||
|
||||
RegisterName sourceName = destinationName;
|
||||
RegisterClassKind classKind = copyStats[sourceName].classKind;
|
||||
RegisterName destinationName = getName(vrManager.newVirtualRegister(classKind));
|
||||
assert(destinationName < maxNameCount);
|
||||
|
||||
copyStats[destinationName].classKind = classKind;
|
||||
copyStats[sourceName].useCount = 0;
|
||||
|
||||
// We need to insert a copy to a temporary register to keep the
|
||||
// source register valid at the end of the node defining it.
|
||||
// This copy will be inserted right after the phi node defining it.
|
||||
RegisterName from = copyStats[sourceName].sourceNameToUse;
|
||||
Instruction* definingPhiNode = vrManager.getVirtualRegister(from).getDefiningInstruction();
|
||||
assert(definingPhiNode && (definingPhiNode->getFlags() & ifPhiNode) != 0);
|
||||
|
||||
RegisterID fromID = buildRegisterID(from, classKind);
|
||||
RegisterID toID = buildRegisterID(destinationName, classKind);
|
||||
Instruction& copy = emitter.newCopy(*definingPhiNode->getPrimitive(), fromID, toID);
|
||||
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
|
||||
definingPhiNode->getPrimitive()->getContainer()->getInstructions().addFirst(copy);
|
||||
|
||||
copyStats[sourceName].temporaryName = destinationName;
|
||||
copyStats[sourceName].sourceNameToUse = destinationName;
|
||||
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
|
||||
}
|
||||
|
||||
// Insert the copy instruction at the end of the current node.
|
||||
RegisterName from = copyStats[sourceName].sourceNameToUse;
|
||||
|
||||
RegisterClassKind classKind = copyStats[destinationName].classKind;
|
||||
RegisterID fromID = buildRegisterID(from, classKind);
|
||||
RegisterID toID = buildRegisterID(destinationName, classKind);
|
||||
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
|
||||
instructions.insertAfter(copy, endOfTheNode);
|
||||
endOfTheNode = instructions.advance(endOfTheNode);
|
||||
|
||||
copyStats[sourceName].useCount = 0;
|
||||
if (destinationList.test(sourceName) && copyStats[sourceName].isLiveOut)
|
||||
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
|
||||
copyStats[sourceName].isLiveOut = false;
|
||||
copyStats[sourceName].sourceNameToUse = destinationName;
|
||||
|
||||
if (destinationList.test(sourceName))
|
||||
workList.set(sourceName);
|
||||
destinationList.clear(destinationName);
|
||||
}
|
||||
|
||||
destinationListSize = destinationList.getSize();
|
||||
if (destinationListSize != 0) {
|
||||
RegisterName sourceName = RegisterName(destinationList.getOne());
|
||||
RegisterName destinationName;
|
||||
|
||||
if (!copyStats[sourceName].temporaryName) {
|
||||
// Cycle problem.
|
||||
RegisterClassKind classKind = copyStats[sourceName].classKind;
|
||||
destinationName = getName(vrManager.newVirtualRegister(classKind));
|
||||
assert(destinationName < maxNameCount);
|
||||
|
||||
copyStats[destinationName].classKind = classKind;
|
||||
copyStats[sourceName].temporaryName = destinationName;
|
||||
|
||||
// Insert the copy instruction at the end of the current node.
|
||||
RegisterName from = copyStats[sourceName].sourceNameToUse;
|
||||
|
||||
RegisterID fromID = buildRegisterID(from, classKind);
|
||||
RegisterID toID = buildRegisterID(destinationName, classKind);
|
||||
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
|
||||
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
|
||||
instructions.insertAfter(copy, endOfTheNode);
|
||||
endOfTheNode = instructions.advance(endOfTheNode);
|
||||
} else
|
||||
destinationName = copyStats[sourceName].temporaryName;
|
||||
|
||||
copyStats[sourceName].useCount = 0;
|
||||
copyStats[sourceName].isLiveOut = false;
|
||||
copyStats[sourceName].sourceNameToUse = destinationName;
|
||||
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
|
||||
|
||||
workList.set(sourceName);
|
||||
}
|
||||
}
|
||||
|
||||
nodeStackPtr->pushedList = pushedList;
|
||||
nodeStackPtr->next = next;
|
||||
nodeStackPtr->limit = limit;
|
||||
++nodeStackPtr;
|
||||
next = dGraph.getSuccessorsBegin(currentNode);
|
||||
limit = dGraph.getSuccessorsEnd(currentNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _PHI_NODE_REMOVER_H_
|
||||
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal file
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "LogModule.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
#include "PhiNodeRemover.h"
|
||||
#include "LiveRange.h"
|
||||
#include "Liveness.h"
|
||||
#include "InterferenceGraph.h"
|
||||
#include "LiveRangeGraph.h"
|
||||
#include "Coalescing.h"
|
||||
#include "Spilling.h"
|
||||
#include "Coloring.h"
|
||||
#include "Splits.h"
|
||||
|
||||
class Pool;
|
||||
class ControlGraph;
|
||||
class VirtualRegisterManager;
|
||||
class InstructionEmitter;
|
||||
|
||||
UT_DEFINE_LOG_MODULE(RegAlloc);
|
||||
|
||||
void RegisterAllocator::allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
|
||||
{
|
||||
// Insert the phi node instructions. We want to do this to have a single defined register per instruction.
|
||||
// If we keep the PhiNode (as a DataNode) and a PhiNode is of DoubleWordKind then we have to execute
|
||||
// some special code for the high word annotation.
|
||||
//
|
||||
RegisterAllocatorTools::insertPhiNodeInstructions(controlGraph, emitter);
|
||||
|
||||
// Perform some tests on the instruction graph.
|
||||
//
|
||||
DEBUG_ONLY(RegisterAllocatorTools::testTheInstructionGraph(controlGraph, vrManager));
|
||||
|
||||
// Replace the phi node instructions by their equivalent copy instructions.
|
||||
//
|
||||
PhiNodeRemover<LowRegisterPressure>::replacePhiNodes(controlGraph, vrManager, emitter);
|
||||
|
||||
// Do the register allocation.
|
||||
//
|
||||
RegisterAllocator registerAllocator(pool, controlGraph, vrManager, emitter);
|
||||
registerAllocator.doGraphColoring();
|
||||
}
|
||||
|
||||
void RegisterAllocator::doGraphColoring()
|
||||
{
|
||||
// Initialize the liverange map.
|
||||
//
|
||||
initLiveRanges();
|
||||
|
||||
// Build the live ranges. We do this to compress the number of RegisterNames
|
||||
// used in the insterference graph.
|
||||
//
|
||||
LiveRange<LowRegisterPressure>::build(*this);
|
||||
|
||||
// Remove unnecessary copies.
|
||||
//
|
||||
RegisterAllocatorTools::removeUnnecessaryCopies(*this);
|
||||
|
||||
for (Uint8 loop = 0; loop < 10; loop++) {
|
||||
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********* RegisterAllocator loop %d *********\n", loop));
|
||||
|
||||
while(true) {
|
||||
// Build the interference graph.
|
||||
//
|
||||
iGraph.build();
|
||||
|
||||
// Coalesce the copy instructions.
|
||||
//
|
||||
if (!Coalescing<LowRegisterPressure>::coalesce(*this))
|
||||
break;
|
||||
}
|
||||
|
||||
// Print the interference graph.
|
||||
//
|
||||
DEBUG_LOG_ONLY(iGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
|
||||
|
||||
// Calculate the spill costs.
|
||||
//
|
||||
Spilling<LowRegisterPressure>::calculateSpillCosts(*this);
|
||||
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSpillCosts(*this));
|
||||
|
||||
// Calculate the split costs.
|
||||
//
|
||||
Splits<LowRegisterPressure>::calculateSplitCosts(*this);
|
||||
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSplitCosts(*this));
|
||||
|
||||
// Build the live range graph.
|
||||
//
|
||||
lGraph.build();
|
||||
DEBUG_LOG_ONLY(lGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
|
||||
|
||||
// Color the graph. If it succeeds then we're done with the
|
||||
// register allocation.
|
||||
//
|
||||
if (Coloring<LowRegisterPressure>::color(*this)) {
|
||||
// Write the final colors in the instruction graph.
|
||||
//
|
||||
Coloring<LowRegisterPressure>::finalColoring(*this);
|
||||
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********** RegisterAllocator done **********\n"));
|
||||
DEBUG_LOG_ONLY(RegisterAllocatorTools::printInstructions(*this));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to spill some registers.
|
||||
//
|
||||
Spilling<LowRegisterPressure>::insertSpillCode(*this);
|
||||
|
||||
// Insert the split instructions.
|
||||
//
|
||||
Splits<LowRegisterPressure>::insertSplitCode(*this);
|
||||
|
||||
// Update the live ranges.
|
||||
//
|
||||
// FIX
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
RegisterAllocatorTools::updateInstructionGraph(*this);
|
||||
RegisterAllocatorTools::printInstructions(*this);
|
||||
#endif
|
||||
fprintf(stderr, "!!! Coloring failed after 10 loops !!!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
void RegisterAllocator::initLiveRanges()
|
||||
{
|
||||
Uint32 count = this->nameCount;
|
||||
RegisterName* name2range = new(pool) RegisterName[nameCount];
|
||||
for (RegisterName r = RegisterName(1); r < count; r = RegisterName(r + 1))
|
||||
name2range[r] = r;
|
||||
this->name2range = name2range;
|
||||
rangeCount = count;
|
||||
}
|
||||
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal file
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_ALLOCATOR_H_
|
||||
#define _REGISTER_ALLOCATOR_H_
|
||||
|
||||
class Pool;
|
||||
class ControlGraph;
|
||||
class InstructionEmitter;
|
||||
struct SpillCost;
|
||||
struct SplitCost;
|
||||
|
||||
#include "Liveness.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "RegisterPressure.h" // This should included by Backend.cpp
|
||||
#include "InterferenceGraph.h"
|
||||
#include "LiveRangeGraph.h"
|
||||
|
||||
//template <class RegisterPressure>
|
||||
class RegisterAllocator
|
||||
{
|
||||
public:
|
||||
|
||||
Pool& pool; //
|
||||
ControlGraph& controlGraph; //
|
||||
VirtualRegisterManager& vrManager; //
|
||||
InstructionEmitter& emitter; //
|
||||
|
||||
RegisterName* name2range; //
|
||||
RegisterName* color; //
|
||||
SpillCost* spillCost; //
|
||||
SparseSet* willSpill; //
|
||||
SplitCost* splitCost; //
|
||||
NameLinkedList** splitAround; //
|
||||
InterferenceGraph<LowRegisterPressure> iGraph; //
|
||||
LiveRangeGraph<LowRegisterPressure> lGraph; //
|
||||
LivenessInfo<LowRegisterPressure> liveness; //
|
||||
Uint32 nameCount; //
|
||||
Uint32 rangeCount; //
|
||||
bool splitFound; //
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
//
|
||||
void doGraphColoring();
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
//
|
||||
inline RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
|
||||
|
||||
//
|
||||
//
|
||||
bool canInterfere(RegisterName /*name1*/, RegisterName /*name2*/) const {return true;}
|
||||
|
||||
//
|
||||
//
|
||||
void initLiveRanges();
|
||||
|
||||
//
|
||||
//
|
||||
static void allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
inline RegisterAllocator::RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
|
||||
: pool(pool), controlGraph(controlGraph), vrManager(vrManager), emitter(emitter), iGraph(*this), lGraph(*this), nameCount(vrManager.getSize()) {}
|
||||
|
||||
#endif // _REGISTER_ALLOCATOR_H_
|
||||
|
||||
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal file
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "LogModule.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Primitives.h"
|
||||
#include "InstructionEmitter.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "Spilling.h"
|
||||
#include "Splits.h"
|
||||
#include "BitSet.h"
|
||||
|
||||
UT_EXTERN_LOG_MODULE(RegAlloc);
|
||||
|
||||
#ifdef DEBUG
|
||||
void RegisterAllocatorTools::testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
|
||||
{
|
||||
// Test the declared VirtualRegisters. The register allocator tries to condense the register universe.
|
||||
// Any gap in the VirtualRegister names will be a loss of efficiency !!!!
|
||||
|
||||
Uint32 nameCount = vrManager.getSize();
|
||||
BitSet registerSeen(controlGraph.pool, nameCount);
|
||||
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
registerSeen.set(usePtr->getRegisterName());
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
registerSeen.set(definePtr->getRegisterName());
|
||||
}
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& instruction = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
registerSeen.set(usePtr->getRegisterName());
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
registerSeen.set(definePtr->getRegisterName());
|
||||
}
|
||||
}
|
||||
|
||||
bool renameRegisters = false;
|
||||
for (BitSet::iterator i = registerSeen.nextZero(0); !registerSeen.done(i); i = registerSeen.nextZero(i)) {
|
||||
renameRegisters = true;
|
||||
fprintf(stderr,
|
||||
"WARNING: The VirtualRegister vr%d has been allocated during CodeGeneration but\n"
|
||||
" is never used nor defined by any instruction in the instruction graph\n"
|
||||
" PLEASE FIX \n",
|
||||
i);
|
||||
}
|
||||
if (renameRegisters) {
|
||||
Instruction** definingInstruction = new Instruction*[nameCount];
|
||||
memset(definingInstruction, '\0', nameCount * sizeof(Instruction*));
|
||||
RegisterName* newName = new RegisterName[nameCount];
|
||||
memset(newName, '\0', nameCount * sizeof(RegisterName));
|
||||
RegisterName nextName = RegisterName(1);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
usePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName name = definePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
definePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
}
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& instruction = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
usePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName name = definePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
definePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vrManager.setSize(nextName);
|
||||
|
||||
for (RegisterName r = RegisterName(1); r < nextName; r = RegisterName(r + 1))
|
||||
vrManager.getVirtualRegister(r).definingInstruction = definingInstruction[r];
|
||||
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("RegisterMap:\n"));
|
||||
for (Uint32 i = 1; i < nameCount; i++)
|
||||
if (newName[i] != 0)
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d becomes vr%d.\n", i, newName[i]));
|
||||
else
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d is dead.\n", i));
|
||||
|
||||
|
||||
delete newName;
|
||||
delete definingInstruction;
|
||||
}
|
||||
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void RegisterAllocatorTools::removeUnnecessaryCopies(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i);) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
i = instructions.advance(i);
|
||||
|
||||
if (instruction.getFlags() & ifCopy) {
|
||||
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
|
||||
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
|
||||
|
||||
RegisterName source = name2range[instruction.getInstructionUseBegin()[0].getRegisterName()];
|
||||
RegisterName destination = name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()];
|
||||
|
||||
if (source == destination)
|
||||
instruction.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocatorTools::updateInstructionGraph(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
|
||||
}
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& instruction = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocatorTools::insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
|
||||
|
||||
if (!phiNodes.empty()) {
|
||||
|
||||
// Set the index of the incoming edges.
|
||||
Uint32 index = 0;
|
||||
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
||||
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p))
|
||||
predecessors.get(p).setIndex(index++);
|
||||
|
||||
// Insert the phi node instruction in the instruction list.
|
||||
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
||||
PhiNode& phiNode = phiNodes.get(i);
|
||||
ValueKind kind = phiNode.getKind();
|
||||
|
||||
if (!isStorableKind(kind))
|
||||
continue;
|
||||
|
||||
RegisterClassKind classKind = rckGeneral; // FIX: get class kind from phi node kind.
|
||||
Uint32 nInputs = phiNode.nInputs();
|
||||
|
||||
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
|
||||
|
||||
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drLow);
|
||||
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
|
||||
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drLow);
|
||||
|
||||
node.addPhiNodeInstruction(phiNodeInstruction);
|
||||
|
||||
if (isDoublewordKind(kind)) {
|
||||
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
|
||||
|
||||
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drHigh);
|
||||
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
|
||||
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drHigh);
|
||||
|
||||
node.addPhiNodeInstruction(phiNodeInstruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
|
||||
void RegisterAllocatorTools::printSpillCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
SpillCost* cost = registerAllocator.spillCost;
|
||||
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Spill costs:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : ", i));
|
||||
if (cost[i].infinite)
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("infinite\n"));
|
||||
else
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%f\n", cost[i].cost));
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterAllocatorTools::printSplitCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
SplitCost* cost = registerAllocator.splitCost;
|
||||
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Split costs:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : loads = %f stores = %f\n", i, cost[i].loads, cost[i].stores));
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterAllocatorTools::printInstructions(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
|
||||
ControlNode** nodes = registerAllocator.controlGraph.dfsList;
|
||||
Uint32 nNodes = registerAllocator.controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d:\n", n));
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
|
||||
if (!phiNodes.empty()) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" PhiNodes:\n", n));
|
||||
for(InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
||||
phiNodes.get(i).printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
if (!instructions.empty())
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" Instructions:\n", n));
|
||||
}
|
||||
|
||||
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
instructions.get(i).printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal file
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
|
||||
//
|
||||
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
|
||||
// NETSCAPE COMMUNICATIONS CORPORATION
|
||||
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
|
||||
// Reserved. Use of this Source Code is subject to the terms of the
|
||||
// applicable license agreement from Netscape Communications Corporation.
|
||||
// The copyright notice(s) in this Source Code does not indicate actual or
|
||||
// intended publication of this Source Code.
|
||||
//
|
||||
// $Id: RegisterAllocatorTools.h,v 1.1.2.1 1999-03-02 16:12:05 fur%netscape.com Exp $
|
||||
//
|
||||
|
||||
#ifndef _REGISTER_ALLOCATOR_TOOLS_H_
|
||||
#define _REGISTER_ALLOCATOR_TOOLS_H_
|
||||
|
||||
#include "LogModule.h"
|
||||
#include "RegisterTypes.h"
|
||||
#include <string.h>
|
||||
|
||||
class RegisterAllocator;
|
||||
class ControlGraph;
|
||||
class InstructionEmitter;
|
||||
class VirtualRegisterManager;
|
||||
|
||||
struct RegisterAllocatorTools
|
||||
{
|
||||
//
|
||||
//
|
||||
static void insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter);
|
||||
|
||||
//
|
||||
//
|
||||
static void updateInstructionGraph(RegisterAllocator& registerAllocator);
|
||||
|
||||
//
|
||||
//
|
||||
static void removeUnnecessaryCopies(RegisterAllocator& registerAllocator);
|
||||
|
||||
#ifdef DEBUG
|
||||
//
|
||||
//
|
||||
static void testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
//
|
||||
//
|
||||
static void printInstructions(RegisterAllocator& registerAllocator);
|
||||
|
||||
//
|
||||
//
|
||||
static void printSpillCosts(RegisterAllocator& registerAllocator);
|
||||
|
||||
//
|
||||
//
|
||||
static void printSplitCosts(RegisterAllocator& registerAllocator);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
//
|
||||
// FIX: this should go in a class (LookupTable ?)
|
||||
//
|
||||
|
||||
inline RegisterName findRoot(RegisterName name, RegisterName* table)
|
||||
{
|
||||
RegisterName* stack = table;
|
||||
RegisterName* stackPtr = stack;
|
||||
|
||||
RegisterName newName;
|
||||
while((newName = table[name]) != name) {
|
||||
*--stackPtr = name;
|
||||
name = newName;
|
||||
}
|
||||
|
||||
while (stackPtr != stack)
|
||||
table[*stackPtr++] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
inline void init(RegisterName* table, Uint32 nameCount)
|
||||
{
|
||||
for (RegisterName r = RegisterName(0); r < nameCount; r = RegisterName(r + 1))
|
||||
table[r] = r;
|
||||
}
|
||||
|
||||
inline Uint32 compress(RegisterName* name2range, RegisterName* table, Uint32 nameCount, Uint32 tableSize)
|
||||
{
|
||||
RegisterName* liveRange = new RegisterName[tableSize];
|
||||
memset(liveRange, '\0', tableSize * sizeof(RegisterName));
|
||||
|
||||
// Update the lookup table.
|
||||
for (RegisterName r = RegisterName(1); r < tableSize; r = RegisterName(r + 1))
|
||||
findRoot(r, table);
|
||||
|
||||
// Count the liveranges.
|
||||
Uint32 liveRangeCount = 1;
|
||||
for (RegisterName s = RegisterName(1); s < tableSize; s = RegisterName(s + 1))
|
||||
if (table[s] == s)
|
||||
liveRange[s] = RegisterName(liveRangeCount++);
|
||||
|
||||
for (RegisterName t = RegisterName(1); t < nameCount; t = RegisterName(t + 1))
|
||||
name2range[t] = liveRange[table[name2range[t]]];
|
||||
|
||||
return liveRangeCount;
|
||||
}
|
||||
|
||||
inline double doLog10(Uint32 power)
|
||||
{
|
||||
double log = 1.0;
|
||||
while (power--)
|
||||
log *= 10.0;
|
||||
return log;
|
||||
}
|
||||
|
||||
#endif // _REGISTER_ALLOCATOR_TOOLS_H_
|
||||
@@ -16,27 +16,23 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __nsIID_h
|
||||
#define __nsIID_h
|
||||
#ifndef _REGISTER_ASSIGNER_H_
|
||||
#define _REGISTER_ASSIGNER_H_
|
||||
|
||||
/**
|
||||
* An "interface id" which can be used to uniquely identify a given
|
||||
* interface.
|
||||
*/
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
|
||||
typedef nsID nsIID;
|
||||
class FastBitMatrix;
|
||||
|
||||
/**
|
||||
* A macro shorthand for <tt>const nsIID&<tt>
|
||||
*/
|
||||
class RegisterAssigner
|
||||
{
|
||||
protected:
|
||||
VirtualRegisterManager& vRegManager;
|
||||
|
||||
public:
|
||||
RegisterAssigner(VirtualRegisterManager& vrMan) : vRegManager(vrMan) {}
|
||||
|
||||
virtual bool assignRegisters(FastBitMatrix& interferenceMatrix) = 0;
|
||||
};
|
||||
|
||||
#define REFNSIID const nsIID&
|
||||
|
||||
/**
|
||||
* Define an IID (obsolete)
|
||||
*/
|
||||
|
||||
#define NS_DEFINE_IID(_name, _iidspec) \
|
||||
const nsIID _name = _iidspec
|
||||
|
||||
#endif /* __nsIID_h */
|
||||
#endif /* _REGISTER_ASSIGNER_H_ */
|
||||
@@ -16,11 +16,10 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#ifndef _REGISTER_CLASS_H_
|
||||
#define _REGISTER_CLASS_H_
|
||||
|
||||
[object, uuid(6ccb17a0-e95e-11d1-beae-00805f8a66dc)]
|
||||
interface nsIBaseStream : nsISupports {
|
||||
|
||||
void Close();
|
||||
#include "Fundamentals.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
};
|
||||
#endif // _REGISTER_CLASS_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/*
|
||||
/* -*- 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
|
||||
@@ -16,16 +16,22 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __nsIServerProvider_h
|
||||
#define __nsIServerProvider_h
|
||||
#include "nsISupports.h"
|
||||
#ifndef _REGISTER_PRESSURE_H_
|
||||
#define _REGISTER_PRESSURE_H_
|
||||
|
||||
typedef nsID nsSID;
|
||||
#define NSSIDREF const nsSID&
|
||||
#include "BitSet.h"
|
||||
#include "HashSet.h"
|
||||
|
||||
class nsIServiceProvider: public nsISupports {
|
||||
public:
|
||||
NS_IMETHOD QueryService(NSSIDREF aSID, NSIIDREF sIID, (void **) pService);
|
||||
struct LowRegisterPressure
|
||||
{
|
||||
typedef BitSet Set;
|
||||
static const bool setIsOrdered = true;
|
||||
};
|
||||
|
||||
#endif /* __nsIServerProvider_h */
|
||||
struct HighRegisterPressure
|
||||
{
|
||||
typedef HashSet Set;
|
||||
static const bool setIsOrdered = false;
|
||||
};
|
||||
|
||||
#endif // _REGISTER_PRESSURE_H_
|
||||
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal file
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_TYPES_H_
|
||||
#define _REGISTER_TYPES_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterName -
|
||||
//
|
||||
|
||||
enum RegisterName {
|
||||
rnInvalid = 0,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterClassKind -
|
||||
//
|
||||
|
||||
enum RegisterClassKind {
|
||||
rckInvalid = 0,
|
||||
rckGeneral,
|
||||
rckStackSlot,
|
||||
|
||||
nRegisterClassKind
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterID -
|
||||
//
|
||||
|
||||
enum RegisterID {
|
||||
invalidID = 0
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterKind -
|
||||
//
|
||||
|
||||
enum RegisterKind {
|
||||
rkCallerSave = 0,
|
||||
rkCalleeSave,
|
||||
};
|
||||
|
||||
struct NameLinkedList {
|
||||
RegisterName name;
|
||||
NameLinkedList* next;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
const registerNameMask = 0x03ffffff;
|
||||
const coloredRegisterMask = 0x04000000;
|
||||
const machineRegisterMask = 0x08000000;
|
||||
const registerClassMask = 0xf0000000;
|
||||
|
||||
const registerNameShift = 0;
|
||||
const coloredRegisterShift = 26;
|
||||
const machineRegisterShift = 27;
|
||||
const registerClassShift = 28;
|
||||
|
||||
#else // DEBUG
|
||||
|
||||
const registerNameMask = 0x0fffffff;
|
||||
const registerClassMask = 0xf0000000;
|
||||
|
||||
const registerNameShift = 0;
|
||||
const registerClassShift = 28;
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
inline RegisterClassKind getClass(RegisterID registerID) {return RegisterClassKind((registerID & registerClassMask) >> registerClassShift);}
|
||||
inline RegisterName getName(RegisterID registerID) {return RegisterName((registerID & registerNameMask) >> registerNameShift);}
|
||||
inline void setClass(RegisterID& registerID, RegisterClassKind classKind) {registerID = RegisterID((registerID & ~registerClassMask) | ((classKind << registerClassShift) & registerClassMask));}
|
||||
inline void setName(RegisterID& registerID, RegisterName name) {assert((name & ~registerNameMask) == 0); registerID = RegisterID((registerID & ~registerNameMask) | ((name << registerNameShift) & registerNameMask));}
|
||||
inline RegisterID buildRegisterID(RegisterName name, RegisterClassKind classKind) {return RegisterID(((classKind << registerClassShift) & registerClassMask) | ((name << registerNameShift) & registerNameMask));}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
inline bool isMachineRegister(RegisterID rid) {return (rid & machineRegisterMask) != 0;}
|
||||
inline void setMachineRegister(RegisterID& rid) {rid = RegisterID(rid | machineRegisterMask);}
|
||||
inline bool isColoredRegister(RegisterID rid) {return (rid & coloredRegisterMask) != 0;}
|
||||
inline void setColoredRegister(RegisterID& rid) {rid = RegisterID(rid | coloredRegisterMask);}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
#endif // _REGISTER_TYPES_H_
|
||||
@@ -16,27 +16,17 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef __nsIID_h
|
||||
#define __nsIID_h
|
||||
#include "Fundamentals.h"
|
||||
#include "SSATools.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "Liveness.h"
|
||||
|
||||
/**
|
||||
* An "interface id" which can be used to uniquely identify a given
|
||||
* interface.
|
||||
*/
|
||||
void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
|
||||
{
|
||||
if (!controlGraph.hasBackEdges)
|
||||
return;
|
||||
|
||||
typedef nsID nsIID;
|
||||
|
||||
/**
|
||||
* A macro shorthand for <tt>const nsIID&<tt>
|
||||
*/
|
||||
|
||||
#define REFNSIID const nsIID&
|
||||
|
||||
/**
|
||||
* Define an IID (obsolete)
|
||||
*/
|
||||
|
||||
#define NS_DEFINE_IID(_name, _iidspec) \
|
||||
const nsIID _name = _iidspec
|
||||
|
||||
#endif /* __nsIID_h */
|
||||
Liveness liveness(controlGraph.pool);
|
||||
liveness.buildLivenessAnalysis(controlGraph, vrManager);
|
||||
}
|
||||
@@ -16,12 +16,14 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIFactory.idl"
|
||||
#ifndef _SSA_TOOLS_H_
|
||||
#define _SSA_TOOLS_H_
|
||||
|
||||
[object, uuid(56decae0-3406-11d2-8163-006008119d7a)]
|
||||
interface nsIShutdownListener : nsISupports {
|
||||
#include "Fundamentals.h"
|
||||
|
||||
void OnShutdown(in nsCID aClass, in nsISupports service);
|
||||
class ControlGraph;
|
||||
class VirtualRegisterManager;
|
||||
|
||||
};
|
||||
extern void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
|
||||
|
||||
#endif // _SSA_TOOLS_H_
|
||||
@@ -1,4 +1,4 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
/* -*- 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
|
||||
@@ -16,12 +16,22 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
//
|
||||
// xpcomDebug.Prefix
|
||||
//
|
||||
// Global prefix file for the xpcom project.
|
||||
//
|
||||
//
|
||||
#include "Fundamentals.h"
|
||||
#include "SparseSet.h"
|
||||
#include "BitSet.h"
|
||||
#include "Pool.h"
|
||||
|
||||
#include "MacPrefix_debug.h"
|
||||
#include "xpcomConfig.h"
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the set.
|
||||
//
|
||||
void SparseSet::printPretty(LogModuleObject log)
|
||||
{
|
||||
Pool pool;
|
||||
BitSet set(pool, universeSize);
|
||||
|
||||
for (Uint32 i = 0; i < count; i++)
|
||||
set.set(node[i].element);
|
||||
|
||||
set.printPretty(log);
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal file
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal file
@@ -0,0 +1,168 @@
|
||||
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
|
||||
//
|
||||
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
|
||||
// NETSCAPE COMMUNICATIONS CORPORATION
|
||||
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
|
||||
// Reserved. Use of this Source Code is subject to the terms of the
|
||||
// applicable license agreement from Netscape Communications Corporation.
|
||||
// The copyright notice(s) in this Source Code does not indicate actual or
|
||||
// intended publication of this Source Code.
|
||||
//
|
||||
// $Id: SparseSet.h,v 1.1.2.1 1999-03-02 16:12:07 fur%netscape.com Exp $
|
||||
//
|
||||
|
||||
#ifndef _SPARSE_SET_H_
|
||||
#define _SPARSE_SET_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "LogModule.h"
|
||||
#include "BitSet.h"
|
||||
|
||||
class SparseSet
|
||||
{
|
||||
private:
|
||||
|
||||
struct Node {
|
||||
Uint32 element;
|
||||
Uint32 stackIndex;
|
||||
};
|
||||
|
||||
Node* node;
|
||||
Uint32 count;
|
||||
Uint32 universeSize;
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
SparseSet(const SparseSet&);
|
||||
|
||||
// Check if the given set's universe is of the same size than this universe.
|
||||
void checkUniverseCompatibility(const SparseSet& set) const {assert(set.universeSize == universeSize);}
|
||||
// Check if pos is valid for this set's universe.
|
||||
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
|
||||
|
||||
public:
|
||||
|
||||
SparseSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {node = new(pool) Node[universeSize]; clear();}
|
||||
|
||||
// Clear the sparse set.
|
||||
void clear() {count = 0;}
|
||||
// Clear the element at index.
|
||||
inline void clear(Uint32 index);
|
||||
// Set the element at index.
|
||||
inline void set(Uint32 index);
|
||||
// Return true if the element at index is set.
|
||||
inline bool test(Uint32 index) const;
|
||||
// Union with the given sparse set.
|
||||
inline void or(const SparseSet& set);
|
||||
// Intersection with the given sparse set.
|
||||
inline void and(const SparseSet& set);
|
||||
// Difference with the given sparse set.
|
||||
inline void difference(const SparseSet& set);
|
||||
// Copy set.
|
||||
inline SparseSet& operator = (const SparseSet& set);
|
||||
inline SparseSet& operator = (const BitSet& set);
|
||||
// Return true if the sparse sets are identical.
|
||||
friend bool operator == (const SparseSet& set1, const SparseSet& set2);
|
||||
// Return true if the sparse sets are different.
|
||||
friend bool operator != (const SparseSet& set1, const SparseSet& set2);
|
||||
|
||||
// Logical operators.
|
||||
SparseSet& operator |= (const SparseSet& set) {or(set); return *this;}
|
||||
SparseSet& operator &= (const SparseSet& set) {and(set); return *this;}
|
||||
SparseSet& operator -= (const SparseSet& set) {difference(set); return *this;}
|
||||
|
||||
// Iterator to conform with the set API.
|
||||
typedef Int32 iterator;
|
||||
// Return the iterator for the first element of this set.
|
||||
iterator begin() const {return count - 1;}
|
||||
// Return the next iterator.
|
||||
iterator advance(iterator pos) const {return --pos;}
|
||||
// Return true if the iterator is at the end of the set.
|
||||
bool done(iterator pos) const {return pos < 0;}
|
||||
// Return the element for the given iterator;
|
||||
Uint32 get(iterator pos) const {return node[pos].element;}
|
||||
// Return one element of this set.
|
||||
Uint32 getOne() const {assert(count > 0); return node[0].element;}
|
||||
// Return the size of this set.
|
||||
Uint32 getSize() const {return count;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the set.
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
inline void SparseSet::clear(Uint32 element)
|
||||
{
|
||||
checkMember(element);
|
||||
Uint32 count = this->count;
|
||||
Node* node = this->node;
|
||||
|
||||
Uint32 stackIndex = node[element].stackIndex;
|
||||
|
||||
if ((stackIndex < count) && (node[stackIndex].element == element)) {
|
||||
Uint32 stackTop = node[count - 1].element;
|
||||
|
||||
node[stackIndex].element = stackTop;
|
||||
node[stackTop].stackIndex = stackIndex;
|
||||
this->count = count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SparseSet::set(Uint32 element)
|
||||
{
|
||||
checkMember(element);
|
||||
Uint32 count = this->count;
|
||||
Node* node = this->node;
|
||||
|
||||
Uint32 stackIndex = node[element].stackIndex;
|
||||
|
||||
if ((stackIndex >= count) || (node[stackIndex].element != element)) {
|
||||
node[count].element = element;
|
||||
node[element].stackIndex = count;
|
||||
this->count = count + 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SparseSet::test(Uint32 element) const
|
||||
{
|
||||
checkMember(element);
|
||||
Node* node = this->node;
|
||||
|
||||
Uint32 stackIndex = node[element].stackIndex;
|
||||
return ((stackIndex < count) && (node[stackIndex].element == element));
|
||||
}
|
||||
|
||||
inline SparseSet& SparseSet::operator = (const SparseSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Uint32 sourceCount = set.getSize();
|
||||
Node* node = this->node;
|
||||
|
||||
memcpy(node, set.node, sourceCount * sizeof(Node));
|
||||
|
||||
for (Uint32 i = 0; i < sourceCount; i++) {
|
||||
Uint32 element = node[i].element;
|
||||
node[element].stackIndex = i;
|
||||
}
|
||||
|
||||
count = sourceCount;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline SparseSet& SparseSet::operator = (const BitSet& set)
|
||||
{
|
||||
// FIX: there's room for optimization here.
|
||||
assert(universeSize == set.getSize());
|
||||
|
||||
clear();
|
||||
for (Int32 i = set.firstOne(); i != -1; i = set.nextOne(i))
|
||||
this->set(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // _SPARSE_SET_H_
|
||||
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal file
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef NEW_LAURENTM_CODE
|
||||
#define INCLUDE_EMITTER
|
||||
#include "CpuInfo.h"
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "InstructionEmitter.h"
|
||||
#include "Spilling.h"
|
||||
|
||||
|
||||
void Spilling::
|
||||
insertSpillCode(ControlNode** dfsList, Uint32 nNodes)
|
||||
{
|
||||
PRUint32 nVirtualRegisters = vRegManager.count();
|
||||
FastBitSet currentLive(vRegManager.pool, nVirtualRegisters);
|
||||
FastBitSet usedInThisInstruction(vRegManager.pool, nVirtualRegisters);
|
||||
RegisterFifo grNeedLoad(nVirtualRegisters);
|
||||
RegisterFifo fpNeedLoad(nVirtualRegisters);
|
||||
|
||||
for (PRInt32 n = nNodes - 1; n >= 0; n--)
|
||||
{
|
||||
PR_ASSERT(grNeedLoad.empty() & fpNeedLoad.empty());
|
||||
ControlNode& node = *dfsList[n];
|
||||
|
||||
currentLive = node.liveAtEnd;
|
||||
|
||||
PRUint32 nGeneralAlive = 0;
|
||||
PRUint32 nFloatingPointAlive = 0;
|
||||
|
||||
// Get the number of registers alive at the end of this node.
|
||||
for (PRInt32 j = currentLive.firstOne(); j != -1; j = currentLive.nextOne(j))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(j);
|
||||
if (vReg.spillInfo.willSpill)
|
||||
{
|
||||
currentLive.clear(j);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
nGeneralAlive++;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
nFloatingPointAlive++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if(node.dfsNum == 8) printf("\n________Begin Node %d________\n", node.dfsNum);
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i))
|
||||
{
|
||||
Instruction& instruction = instructions.get(i);
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* defPtr;
|
||||
|
||||
// if(node.dfsNum == 8) { printf("\n");
|
||||
// instruction.printPretty(stdout);
|
||||
// printf("\n"); }
|
||||
|
||||
// Handle definitions
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = defPtr->getVirtualRegister();
|
||||
currentLive.clear(vReg.getRegisterIndex());
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
nGeneralAlive--;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
nFloatingPointAlive--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for deaths
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = usePtr->getVirtualRegister();
|
||||
if (!currentLive.test(vReg.getRegisterIndex()))
|
||||
// This is the last use of this register.
|
||||
{
|
||||
currentLive.set(vReg.getRegisterIndex());
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
nGeneralAlive++;
|
||||
while (/*(nGeneralAlive > NUMBER_OF_GREGISTERS) &&*/ !grNeedLoad.empty())
|
||||
{
|
||||
PRUint32 toLoad = grNeedLoad.get();
|
||||
currentLive.clear(toLoad);
|
||||
nGeneralAlive--;
|
||||
|
||||
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
|
||||
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
|
||||
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
|
||||
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
|
||||
nReg.releaseSelf();
|
||||
}
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
nFloatingPointAlive++;
|
||||
while (/*(nFloatingPointAlive > NUMBER_OF_FPREGISTERS) &&*/ !fpNeedLoad.empty())
|
||||
{
|
||||
PRUint32 toLoad = fpNeedLoad.get();
|
||||
currentLive.clear(toLoad);
|
||||
nFloatingPointAlive--;
|
||||
|
||||
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
|
||||
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
|
||||
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
|
||||
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
|
||||
nReg.releaseSelf();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle uses
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = usePtr->getVirtualRegister();
|
||||
PRUint32 registerIndex = vReg.getRegisterIndex();
|
||||
|
||||
if (vReg.spillInfo.willSpill) {
|
||||
#if defined(GENERATE_FOR_X86)
|
||||
if (!instruction.switchUseToSpill((usePtr - useBegin), *vReg.equivalentRegister[vrcStackSlot]))
|
||||
#endif
|
||||
{
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
if (!grNeedLoad.test(registerIndex))
|
||||
{
|
||||
grNeedLoad.put(registerIndex);
|
||||
VirtualRegister& alias = vRegManager.newVirtualRegister(vrcInteger);
|
||||
if (vReg.isPreColored())
|
||||
alias.preColorRegister(vReg.getPreColor());
|
||||
/* if (vReg.hasSpecialInterference) {
|
||||
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
|
||||
alias.specialInterference = vReg.specialInterference;
|
||||
alias.hasSpecialInterference = true;
|
||||
} */
|
||||
vReg.setAlias(alias);
|
||||
vReg.retainSelf();
|
||||
}
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
if (!fpNeedLoad.test(registerIndex))
|
||||
{
|
||||
fpNeedLoad.put(registerIndex);
|
||||
VirtualRegister& alias = vRegManager.newVirtualRegister(vReg.getClass());
|
||||
if (vReg.isPreColored())
|
||||
alias.preColorRegister(vReg.getPreColor());
|
||||
/*if (vReg.hasSpecialInterference) {
|
||||
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
|
||||
alias.specialInterference = vReg.specialInterference;
|
||||
alias.hasSpecialInterference = true;
|
||||
} */
|
||||
vReg.setAlias(alias);
|
||||
vReg.retainSelf();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
usePtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
|
||||
usedInThisInstruction.set(registerIndex);
|
||||
vReg.spillInfo.lastUsingInstruction = &instruction;
|
||||
}
|
||||
currentLive.clear(registerIndex);
|
||||
} else { // will not spill
|
||||
currentLive.set(registerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle definitions
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = defPtr->getVirtualRegister();
|
||||
|
||||
if (vReg.spillInfo.willSpill)
|
||||
#if defined(GENERATE_FOR_X86)
|
||||
if (!instruction.switchDefineToSpill((defPtr - defBegin), *vReg.equivalentRegister[vrcStackSlot]))
|
||||
#endif
|
||||
{
|
||||
if (usedInThisInstruction.test(vReg.getRegisterIndex()))
|
||||
// this virtualRegister was used in this instruction and is also defined. We need to move
|
||||
// this virtual register to its alias first and then save it to memory.
|
||||
{
|
||||
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
|
||||
vReg.getAlias(), *vReg.equivalentRegister[vrcStackSlot]);
|
||||
defPtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
|
||||
}
|
||||
else
|
||||
{
|
||||
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
|
||||
vReg, *vReg.equivalentRegister[vrcStackSlot]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!grNeedLoad.empty())
|
||||
{
|
||||
PRUint32 nl = grNeedLoad.get();
|
||||
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
|
||||
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
|
||||
|
||||
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
|
||||
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
|
||||
nlReg.releaseSelf();
|
||||
}
|
||||
while (!fpNeedLoad.empty())
|
||||
{
|
||||
PRUint32 nl = fpNeedLoad.get();
|
||||
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
|
||||
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
|
||||
|
||||
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
|
||||
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
|
||||
nlReg.releaseSelf();
|
||||
}
|
||||
|
||||
// if(node.dfsNum == 8) printf("\n________End Node %d________\n", node.dfsNum);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal file
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SPILLING_H_
|
||||
#define _SPILLING_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "SparseSet.h"
|
||||
|
||||
template <class RegisterPressure>
|
||||
class Spilling
|
||||
{
|
||||
private:
|
||||
static void insertStoreAfter(Instruction& instruction, RegisterName name);
|
||||
static void insertLoadBefore(Instruction& instruction, RegisterName name);
|
||||
|
||||
public:
|
||||
static void calculateSpillCosts(RegisterAllocator& registerAllocator);
|
||||
static void insertSpillCode(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
struct SpillCost
|
||||
{
|
||||
double loads;
|
||||
double stores;
|
||||
double copies;
|
||||
double cost;
|
||||
bool infinite;
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::insertSpillCode(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet currentLive(pool, rangeCount);
|
||||
SparseSet needLoad(pool, rangeCount);
|
||||
SparseSet mustSpill(pool, rangeCount);
|
||||
SparseSet& willSpill = *registerAllocator.willSpill;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
|
||||
needLoad.clear();
|
||||
currentLive = liveOut[n];
|
||||
mustSpill = currentLive;
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i);) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
i = instructions.retreat(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
bool foundLiveDefine = false;
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
if (currentLive.test(name2range[definePtr->getRegisterName()])) {
|
||||
foundLiveDefine = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
foundLiveDefine = true;
|
||||
break;
|
||||
}
|
||||
if (defineBegin != defineEnd && !foundLiveDefine) {
|
||||
fprintf(stderr, "!!! Removed instruction because it was only defining unused registers !!!\n");
|
||||
instruction.remove();
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName range = name2range[definePtr->getRegisterName()];
|
||||
#ifdef DEBUG
|
||||
if (needLoad.test(range))
|
||||
if (!mustSpill.test(range) && registerAllocator.spillCost[range].infinite && willSpill.test(range)) {
|
||||
fprintf(stderr, "Tried to spill a register with infinite spill cost\n");
|
||||
abort();
|
||||
}
|
||||
#endif // DEBUG
|
||||
if (willSpill.test(range))
|
||||
insertStoreAfter(instruction, range);
|
||||
|
||||
needLoad.clear(range);
|
||||
}
|
||||
|
||||
if (instruction.getFlags() & ifCopy)
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
if (!currentLive.test(range))
|
||||
for (SparseSet::iterator r = needLoad.begin(); !needLoad.done(r); r = needLoad.advance(r)) {
|
||||
RegisterName load = RegisterName(needLoad.get(r));
|
||||
if (willSpill.test(load))
|
||||
insertLoadBefore(instruction, load);
|
||||
mustSpill.set(load);
|
||||
}
|
||||
needLoad.clear();
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentLive.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
currentLive.set(range);
|
||||
needLoad.set(range);
|
||||
}
|
||||
}
|
||||
|
||||
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
|
||||
RegisterName load = RegisterName(needLoad.get(l));
|
||||
if (willSpill.test(load))
|
||||
insertLoadBefore(instructions.first(), load);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::insertLoadBefore(Instruction& /*instruction*/, RegisterName name)
|
||||
{
|
||||
fprintf(stdout, "will insert load for range %d\n", name);
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::insertStoreAfter(Instruction& /*instruction*/, RegisterName name)
|
||||
{
|
||||
fprintf(stdout, "will insert store for range %d\n", name);
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::calculateSpillCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet live(pool, rangeCount);
|
||||
SparseSet needLoad(pool, rangeCount);
|
||||
SparseSet mustSpill(pool, rangeCount);
|
||||
|
||||
SparseSet alreadyStored(pool, rangeCount); // FIX: should get this from previous spilling.
|
||||
|
||||
SpillCost* cost = new SpillCost[rangeCount];
|
||||
memset(cost, '\0', rangeCount * sizeof(SpillCost));
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
double weight = doLog10(node.loopDepth);
|
||||
|
||||
needLoad.clear();
|
||||
live = liveOut[n];
|
||||
mustSpill = live;
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName range = name2range[definePtr->getRegisterName()];
|
||||
|
||||
if (needLoad.test(range))
|
||||
if (!mustSpill.test(range))
|
||||
cost[range].infinite = true;
|
||||
|
||||
if ((false /* !rematerializable(range) */ || !needLoad.test(range)) && !alreadyStored.test(range))
|
||||
cost[range].stores += weight;
|
||||
|
||||
needLoad.clear(range);
|
||||
}
|
||||
|
||||
if (instruction.getFlags() & ifCopy)
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
if (!live.test(name2range[usePtr->getRegisterName()])) {
|
||||
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
|
||||
Uint32 range = needLoad.get(l);
|
||||
cost[range].loads += weight;
|
||||
mustSpill.set(range);
|
||||
}
|
||||
needLoad.clear();
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
live.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
|
||||
live.set(range);
|
||||
needLoad.set(range);
|
||||
}
|
||||
|
||||
if (instruction.getFlags() & ifCopy) {
|
||||
assert(useBegin != useEnd && useBegin[0].isRegister());
|
||||
assert(defineBegin != defineEnd && defineBegin[0].isRegister());
|
||||
|
||||
RegisterName source = name2range[useBegin[0].getRegisterName()];
|
||||
RegisterName destination = name2range[defineBegin[0].getRegisterName()];
|
||||
|
||||
cost[source].copies += weight;
|
||||
cost[destination].copies += weight;
|
||||
}
|
||||
}
|
||||
|
||||
for (SparseSet::iterator s = needLoad.begin(); !needLoad.done(s); s = needLoad.advance(s))
|
||||
cost[needLoad.get(s)].loads += weight;
|
||||
}
|
||||
|
||||
for (Uint32 r = 0; r < rangeCount; r++) {
|
||||
SpillCost& c = cost[r];
|
||||
c.cost = 2 * (c.loads + c.stores) - c.copies;
|
||||
}
|
||||
|
||||
registerAllocator.spillCost = cost;
|
||||
}
|
||||
|
||||
#endif // _SPILLING_H_
|
||||
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal file
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal file
@@ -0,0 +1,239 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SPLITS_H_
|
||||
#define _SPLITS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
|
||||
UT_EXTERN_LOG_MODULE(RegAlloc);
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct Splits
|
||||
{
|
||||
static void calculateSplitCosts(RegisterAllocator& registerAllocator);
|
||||
static bool findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range);
|
||||
static void insertSplitCode(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
struct SplitCost
|
||||
{
|
||||
double loads;
|
||||
double stores;
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Splits<RegisterPressure>::insertSplitCode(RegisterAllocator& /*registerAllocator*/)
|
||||
{
|
||||
// FIX
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Splits<RegisterPressure>::findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range)
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
NameLinkedList** neighborsWithColor = new(pool) NameLinkedList*[6]; // FIX
|
||||
memset(neighborsWithColor, '\0', 6 * sizeof(NameLinkedList*));
|
||||
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
|
||||
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
|
||||
for (Int32 i = vector->count - 1; i >=0; --i) {
|
||||
RegisterName neighbor = vector->neighbors[i];
|
||||
RegisterName c = color[neighbor];
|
||||
|
||||
if (c < 6) { // FIX
|
||||
NameLinkedList* node = new(pool) NameLinkedList();
|
||||
node->name = neighbor;
|
||||
node->next = neighborsWithColor[c];
|
||||
neighborsWithColor[c] = node;
|
||||
}
|
||||
}
|
||||
|
||||
bool splitAroundName = true;
|
||||
|
||||
LiveRangeGraph<RegisterPressure>& lGraph = registerAllocator.lGraph;
|
||||
RegisterName bestColor = RegisterName(6); // FIX
|
||||
double bestCost = registerAllocator.spillCost[range].cost;
|
||||
SplitCost* splitCost = registerAllocator.splitCost;
|
||||
|
||||
for (RegisterName i = RegisterName(0); i < 6; i = RegisterName(i + 1)) { // FIX
|
||||
|
||||
double splitAroundNameCost = 0.0;
|
||||
bool canSplitAroundName = true;
|
||||
|
||||
SplitCost& sCost = splitCost[range];
|
||||
double addedCost = 2.0 * (sCost.stores + sCost.loads);
|
||||
|
||||
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
|
||||
RegisterName neighbor = node->name;
|
||||
if (lGraph.haveEdge(neighbor, range)) {
|
||||
canSplitAroundName = false;
|
||||
break;
|
||||
} else
|
||||
splitAroundNameCost += addedCost;
|
||||
}
|
||||
if (canSplitAroundName && splitAroundNameCost < bestCost) {
|
||||
bestCost = splitAroundNameCost;
|
||||
bestColor = i;
|
||||
splitAroundName = true;
|
||||
}
|
||||
|
||||
double splitAroundColorCost = 0.0;
|
||||
bool canSplitAroundColor = true;
|
||||
|
||||
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
|
||||
RegisterName neighbor = node->name;
|
||||
if (lGraph.haveEdge(range, neighbor)) {
|
||||
canSplitAroundColor = false;
|
||||
break;
|
||||
} else {
|
||||
SplitCost& sCost = splitCost[neighbor];
|
||||
double addedCost = 2.0 * (sCost.stores + sCost.loads);
|
||||
splitAroundColorCost += addedCost;
|
||||
}
|
||||
}
|
||||
if (canSplitAroundColor && splitAroundColorCost < bestCost) {
|
||||
bestCost = splitAroundColorCost;
|
||||
bestColor = i;
|
||||
splitAroundName = false;
|
||||
}
|
||||
}
|
||||
if (bestColor < RegisterName(6)) {
|
||||
color[range] = bestColor;
|
||||
registerAllocator.splitFound = true;
|
||||
|
||||
NameLinkedList** splitAround = registerAllocator.splitAround;
|
||||
|
||||
if (splitAroundName)
|
||||
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
|
||||
NameLinkedList* newNode = new(pool) NameLinkedList();
|
||||
newNode->name = node->name;
|
||||
newNode->next = splitAround[range];
|
||||
splitAround[range] = newNode;
|
||||
}
|
||||
else
|
||||
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
|
||||
NameLinkedList* newNode = new(pool) NameLinkedList();
|
||||
RegisterName neighbor = node->name;
|
||||
newNode->name = range;
|
||||
newNode->next = splitAround[neighbor];
|
||||
splitAround[neighbor] = newNode;
|
||||
}
|
||||
|
||||
trespass("Found a split");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Splits<RegisterPressure>::calculateSplitCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
SplitCost* splitCost = new(pool) SplitCost[rangeCount];
|
||||
memset(splitCost, '\0', rangeCount * sizeof(SplitCost));
|
||||
|
||||
SparseSet live(pool, rangeCount);
|
||||
RegisterPressure::Set* liveIn = registerAllocator.liveness.liveIn;
|
||||
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
double weight = doLog10(node.loopDepth);
|
||||
|
||||
live = liveOut[n];
|
||||
|
||||
ControlEdge* successorsEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++) {
|
||||
ControlNode& successor = successorsPtr->getTarget();
|
||||
|
||||
if (successor.getControlKind() != ckEnd) {
|
||||
RegisterPressure::Set& successorLiveIn = liveIn[successor.dfsNum];
|
||||
|
||||
for (SparseSet::iterator i = live.begin(); !live.done(i); i = live.advance(i)) {
|
||||
RegisterName name = RegisterName(live.get(i));
|
||||
if (!successorLiveIn.test(name))
|
||||
splitCost[name].loads += doLog10(successor.loopDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
splitCost[name2range[definePtr->getRegisterName()]].stores += weight;
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
if (!live.test(range)) {
|
||||
if (&instruction != &instructions.last())
|
||||
splitCost[range].loads += weight;
|
||||
else {
|
||||
ControlEdge* successorsEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++)
|
||||
splitCost[range].loads += doLog10(successorsPtr->getTarget().loopDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
live.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
live.set(name2range[usePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
|
||||
NameLinkedList** splitAround = new(pool) NameLinkedList*[rangeCount];
|
||||
memset(splitAround, '\0', rangeCount * sizeof(NameLinkedList*));
|
||||
registerAllocator.splitAround = splitAround;
|
||||
|
||||
registerAllocator.splitCost = splitCost;
|
||||
registerAllocator.splitFound = false;
|
||||
}
|
||||
|
||||
#endif // _SPLITS_H_
|
||||
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal file
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "HashTable.h"
|
||||
#include "Timer.h"
|
||||
#include "Pool.h"
|
||||
|
||||
static Pool pool; // Pool for the Timer class.
|
||||
static HashTable<TimerEntry*> timerEntries(pool); // Timers hashtable.
|
||||
|
||||
const nTimersInABlock = 128; // Number of timers in a block.
|
||||
static PRTime *timers = new(pool) PRTime[nTimersInABlock]; // A block of timers.
|
||||
static Uint8 nextTimer = 0; // nextAvailableTimer.
|
||||
|
||||
//
|
||||
// Calibrate the call to PR_Now().
|
||||
//
|
||||
static PRTime calibrate()
|
||||
{
|
||||
PRTime t = PR_Now();
|
||||
PRTime& a = *new(pool) PRTime();
|
||||
|
||||
// Call 10 times the PR_Now() function.
|
||||
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
|
||||
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
|
||||
t = (PR_Now() - t + 9) / 10;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static PRTime adjust = calibrate();
|
||||
|
||||
//
|
||||
// Return the named timer..
|
||||
//
|
||||
TimerEntry& Timer::getTimerEntry(const char* name)
|
||||
{
|
||||
if (!timerEntries.exists(name)) {
|
||||
TimerEntry* newEntry = new(pool) TimerEntry();
|
||||
newEntry->accumulator = 0;
|
||||
newEntry->running = false;
|
||||
timerEntries.add(name, newEntry);
|
||||
}
|
||||
|
||||
return *timerEntries[name];
|
||||
}
|
||||
|
||||
//
|
||||
// Return a reference to a new timer.
|
||||
//
|
||||
PRTime& Timer::getNewTimer()
|
||||
{
|
||||
if (nextTimer >= nTimersInABlock) {
|
||||
timers = new(pool) PRTime[nTimersInABlock];
|
||||
nextTimer = 0;
|
||||
}
|
||||
return timers[nextTimer++];
|
||||
}
|
||||
|
||||
static Uint32 timersAreFrozen = 0;
|
||||
|
||||
//
|
||||
// Start the named timer.
|
||||
//
|
||||
void Timer::start(const char* name)
|
||||
{
|
||||
if (timersAreFrozen)
|
||||
return;
|
||||
|
||||
freezeTimers();
|
||||
|
||||
TimerEntry& timer = getTimerEntry(name);
|
||||
PR_ASSERT(!timer.running);
|
||||
|
||||
timer.accumulator = 0;
|
||||
timer.running = true;
|
||||
timer.done = false;
|
||||
|
||||
unfreezeTimers();
|
||||
}
|
||||
|
||||
//
|
||||
// Stop the named timer.
|
||||
//
|
||||
void Timer::stop(const char* name)
|
||||
{
|
||||
if (timersAreFrozen)
|
||||
return;
|
||||
|
||||
freezeTimers();
|
||||
|
||||
TimerEntry& timer = getTimerEntry(name);
|
||||
PR_ASSERT(timer.running);
|
||||
timer.running = false;
|
||||
timer.done = true;
|
||||
|
||||
unfreezeTimers();
|
||||
}
|
||||
|
||||
//
|
||||
// Freeze all the running timers.
|
||||
//
|
||||
void Timer::freezeTimers()
|
||||
{
|
||||
PRTime when = PR_Now() - adjust;
|
||||
|
||||
if (timersAreFrozen == 0) {
|
||||
Vector<TimerEntry*> entries = timerEntries;
|
||||
Uint32 count = entries.size();
|
||||
|
||||
for (Uint32 i = 0; i < count; i++) {
|
||||
TimerEntry& entry = *entries[i];
|
||||
if (entry.running) {
|
||||
entry.accumulator += (when - *entry.startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
timersAreFrozen++;
|
||||
}
|
||||
|
||||
//
|
||||
// Unfreeze all the running timers.
|
||||
//
|
||||
void Timer::unfreezeTimers()
|
||||
{
|
||||
PR_ASSERT(timersAreFrozen != 0);
|
||||
timersAreFrozen--;
|
||||
|
||||
if (timersAreFrozen == 0) {
|
||||
Vector<TimerEntry *> entries = timerEntries;
|
||||
Uint32 count = entries.size();
|
||||
|
||||
PRTime& newStart = getNewTimer();
|
||||
|
||||
for (Uint32 i = 0; i < count; i++) {
|
||||
TimerEntry& entry = *entries[i];
|
||||
if (entry.running) {
|
||||
entry.startTime = &newStart;
|
||||
}
|
||||
}
|
||||
|
||||
newStart = PR_Now();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Print the named timer in the file f.
|
||||
//
|
||||
void Timer::print(FILE* f, const char *name)
|
||||
{
|
||||
if (timersAreFrozen)
|
||||
return;
|
||||
|
||||
freezeTimers();
|
||||
|
||||
TimerEntry& timer = getTimerEntry(name);
|
||||
|
||||
PR_ASSERT(timer.done);
|
||||
PRTime elapsed = timer.accumulator;
|
||||
|
||||
if (elapsed >> 32) {
|
||||
fprintf(f, "[timer %s out of range]\n", name);
|
||||
} else {
|
||||
fprintf(f, "[%dus in %s]\n", Uint32(elapsed), name);
|
||||
}
|
||||
fflush(f);
|
||||
|
||||
unfreezeTimers();
|
||||
}
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "HashTable.h"
|
||||
#include "prtime.h"
|
||||
|
||||
//
|
||||
// Naming convention:
|
||||
// As the class Timer contains only static methods, the timer's name should start with the
|
||||
// module name. Otherwise starting 2 timers with the same name will assert.
|
||||
//
|
||||
|
||||
#ifndef NO_TIMER
|
||||
|
||||
struct TimerEntry
|
||||
{
|
||||
PRTime *startTime; // Current time when we start the timer.
|
||||
PRTime accumulator; // Time spent in this timer.
|
||||
bool running; // True if the timer is running.
|
||||
bool done; // True if the timer was running and was stopped.
|
||||
};
|
||||
|
||||
class Timer
|
||||
{
|
||||
private:
|
||||
|
||||
// Return the named timer.
|
||||
static TimerEntry& getTimerEntry(const char* name);
|
||||
// Return a reference to a new Timer.
|
||||
static PRTime& getNewTimer();
|
||||
|
||||
public:
|
||||
|
||||
// Start the timer.
|
||||
static void start(const char* name);
|
||||
// Stop the timer.
|
||||
static void stop(const char* name);
|
||||
// Freeze all the running timers.
|
||||
static void freezeTimers();
|
||||
// Unfreeze all the running timers.
|
||||
static void unfreezeTimers();
|
||||
// Print the timer.
|
||||
static void print(FILE* f, const char *name);
|
||||
};
|
||||
|
||||
inline void startTimer(const char* name) {Timer::start(name);}
|
||||
inline void stopTimer(const char* name) {Timer::stop(name); Timer::print(stdout, name);}
|
||||
#define START_TIMER_SAFE Timer::freezeTimers();
|
||||
#define END_TIMER_SAFE Timer::unfreezeTimers();
|
||||
#define TIMER_SAFE(x) START_TIMER_SAFE x; END_TIMER_SAFE
|
||||
|
||||
#else /* NO_TIMER */
|
||||
|
||||
inline void startTimer(const char* /*name*/) {}
|
||||
inline void stopTimer(const char* /*name*/) {}
|
||||
#define START_TIMER_SAFE
|
||||
#define END_TIMER_SAFE
|
||||
#define TIMER_SAFE(x) x;
|
||||
|
||||
#endif /* NO_TIMER */
|
||||
#endif /* _TIMER_H_ */
|
||||
@@ -16,18 +16,25 @@
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsIBaseStream.idl"
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "Instruction.h"
|
||||
|
||||
[object, uuid(022396f0-93b5-11d1-895b-006008911b81)]
|
||||
interface nsIInputStream : nsIBaseStream {
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegister -
|
||||
|
||||
unsigned long GetLength();
|
||||
#ifdef MANUAL_TEMPLATES
|
||||
template class IndexedPool<VirtualRegister>;
|
||||
#endif
|
||||
|
||||
/* this is really an out char buf, but I don't know how to express
|
||||
* that in IDL */
|
||||
unsigned long Read(in string aBuf,
|
||||
in unsigned long aOffset,
|
||||
in unsigned long aCount,
|
||||
out unsigned long aReadCount);
|
||||
};
|
||||
// Set the defining instruction.
|
||||
//
|
||||
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
|
||||
{
|
||||
if (definingInstruction != NULL) {
|
||||
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
|
||||
return;
|
||||
}
|
||||
definingInstruction = &instruction;
|
||||
}
|
||||
|
||||
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal file
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VIRTUAL_REGISTER_H_
|
||||
#define _VIRTUAL_REGISTER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "IndexedPool.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "RegisterTypes.h"
|
||||
#include "RegisterClass.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegister - 24b
|
||||
|
||||
class Instruction;
|
||||
|
||||
class VirtualRegister : public IndexedObject<VirtualRegister>
|
||||
{
|
||||
public:
|
||||
|
||||
Instruction* definingInstruction; // Instruction defining this VR.
|
||||
|
||||
// Initialize a VR of the given classKind.
|
||||
VirtualRegister(RegisterClassKind /*classKind*/) : definingInstruction(NULL) {}
|
||||
|
||||
// Return the defining instruction for this VR.
|
||||
Instruction* getDefiningInstruction() const {return definingInstruction;}
|
||||
// Set the defining instruction.
|
||||
void setDefiningInstruction(Instruction& insn);
|
||||
};
|
||||
|
||||
// Return true if the VirtualRegisters are equals. The only way 2 VRs can be equal is if
|
||||
// they have the same index. If they have the same index then they are at the same
|
||||
// address in the indexed pool.
|
||||
//
|
||||
inline bool operator == (const VirtualRegister& regA, const VirtualRegister& regB) {return ®A == ®B;}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegisterManager -
|
||||
|
||||
struct PreColoredRegister
|
||||
{
|
||||
RegisterID id;
|
||||
RegisterName color;
|
||||
};
|
||||
|
||||
class VirtualRegisterManager
|
||||
{
|
||||
private:
|
||||
|
||||
IndexedPool<VirtualRegister> registerPool;
|
||||
PreColoredRegister machineRegister[6];
|
||||
|
||||
public:
|
||||
VirtualRegisterManager()
|
||||
{
|
||||
for (Uint32 i = 0; i < 6; i++)
|
||||
machineRegister[i].id = invalidID;
|
||||
}
|
||||
|
||||
// Return the VirtualRegister at the given index.
|
||||
VirtualRegister& getVirtualRegister(RegisterName name) const {return registerPool.get(name);}
|
||||
|
||||
// Return a new VirtualRegister.
|
||||
RegisterID newVirtualRegister(RegisterClassKind classKind)
|
||||
{
|
||||
VirtualRegister& vReg = *new(registerPool) VirtualRegister(classKind);
|
||||
RegisterID rid;
|
||||
|
||||
setName(rid, RegisterName(vReg.getIndex()));
|
||||
setClass(rid, classKind);
|
||||
return rid;
|
||||
}
|
||||
|
||||
RegisterID newMachineRegister(RegisterName name, RegisterClassKind classKind)
|
||||
{
|
||||
RegisterID rid = machineRegister[name].id;
|
||||
|
||||
if (rid == invalidID) {
|
||||
rid = newVirtualRegister(classKind);
|
||||
DEBUG_ONLY(setMachineRegister(rid));
|
||||
machineRegister[name].id = rid;
|
||||
machineRegister[name].color = name;
|
||||
}
|
||||
|
||||
return rid;
|
||||
}
|
||||
|
||||
PreColoredRegister* getMachineRegistersBegin() const {return (PreColoredRegister*) machineRegister;} // FIX
|
||||
PreColoredRegister* getMachineRegistersEnd() const {return (PreColoredRegister*) &machineRegister[6];} // FIX
|
||||
|
||||
// Return the VirtualRegister universe size.
|
||||
Uint32 getSize() {return registerPool.getSize();}
|
||||
|
||||
void setSize(Uint32 size) {registerPool.setSize(size);}
|
||||
};
|
||||
|
||||
#endif // _VIRTUAL_REGISTER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,162 +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 "nsDebug.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "plstr.h"
|
||||
|
||||
// XXX change to use nsIAllocator or whatever
|
||||
#define XPIDL_STRING_ALLOC(__size) new PRUnichar[(__size)]
|
||||
#define XPIDL_CSTRING_ALLOC(__size) new char[(__size)]
|
||||
#define XPIDL_FREE(__ptr) delete[] (__ptr)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLString
|
||||
|
||||
nsXPIDLString::nsXPIDLString()
|
||||
: mBufOwner(PR_FALSE),
|
||||
mBuf(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsXPIDLString::~nsXPIDLString()
|
||||
{
|
||||
if (mBufOwner && mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
}
|
||||
|
||||
|
||||
nsXPIDLString::operator const PRUnichar*()
|
||||
{
|
||||
return mBuf;
|
||||
}
|
||||
|
||||
|
||||
PRUnichar*
|
||||
nsXPIDLString::Copy(const PRUnichar* aString)
|
||||
{
|
||||
NS_ASSERTION(aString, "null ptr");
|
||||
if (! aString)
|
||||
return 0;
|
||||
|
||||
PRInt32 len = 0;
|
||||
|
||||
{
|
||||
const PRUnichar* p = aString;
|
||||
while (*p++)
|
||||
len++;
|
||||
}
|
||||
|
||||
PRUnichar* result = XPIDL_STRING_ALLOC(len + 1);
|
||||
if (result) {
|
||||
PRUnichar* q = result;
|
||||
while (*aString) {
|
||||
*q = *aString;
|
||||
q++;
|
||||
aString++;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PRUnichar**
|
||||
nsXPIDLString::StartAssignmentByValue()
|
||||
{
|
||||
if (mBufOwner && mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
|
||||
mBufOwner = PR_TRUE;
|
||||
return &mBuf;
|
||||
}
|
||||
|
||||
|
||||
const PRUnichar**
|
||||
nsXPIDLString::StartAssignmentByReference()
|
||||
{
|
||||
if (mBufOwner && mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
|
||||
mBufOwner = PR_FALSE;
|
||||
return (const PRUnichar**) &mBuf;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLCString
|
||||
|
||||
nsXPIDLCString::nsXPIDLCString()
|
||||
: mBufOwner(PR_FALSE),
|
||||
mBuf(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
nsXPIDLCString::~nsXPIDLCString()
|
||||
{
|
||||
if (mBufOwner && mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
}
|
||||
|
||||
|
||||
nsXPIDLCString::operator const char*()
|
||||
{
|
||||
return mBuf;
|
||||
}
|
||||
|
||||
|
||||
char*
|
||||
nsXPIDLCString::Copy(const char* aCString)
|
||||
{
|
||||
NS_ASSERTION(aCString, "null ptr");
|
||||
if (! aCString)
|
||||
return 0;
|
||||
|
||||
PRInt32 len = PL_strlen(aCString);
|
||||
char* result = XPIDL_CSTRING_ALLOC(len + 1);
|
||||
if (result)
|
||||
PL_strcpy(result, aCString);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
char**
|
||||
nsXPIDLCString::StartAssignmentByValue()
|
||||
{
|
||||
if (mBufOwner && mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
|
||||
mBufOwner = PR_TRUE;
|
||||
return &mBuf;
|
||||
}
|
||||
|
||||
|
||||
const char**
|
||||
nsXPIDLCString::StartAssignmentByReference()
|
||||
{
|
||||
if (mBufOwner && mBuf)
|
||||
XPIDL_FREE(mBuf);
|
||||
|
||||
mBufOwner = PR_FALSE;
|
||||
return (const char**) &mBuf;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,294 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
A set of string wrapper classes that ease transition to use of XPIDL
|
||||
interfaces. nsXPIDLString and nsXPIDLCString are to XPIDL `wstring'
|
||||
and `string' out params as nsCOMPtr is to generic XPCOM interface
|
||||
pointers. They help you deal with object ownership.
|
||||
|
||||
Consider the following interface:
|
||||
|
||||
interface nsIFoo {
|
||||
attribute string Bar;
|
||||
};
|
||||
|
||||
This will generated the following C++ header file:
|
||||
|
||||
class nsIFoo {
|
||||
NS_IMETHOD SetBar(const PRUnichar* aValue);
|
||||
NS_IMETHOD GetBar(PRUnichar* *aValue);
|
||||
};
|
||||
|
||||
The GetBar() method will allocate a copy of the nsIFoo object's
|
||||
"bar" attribute, and leave you to deal with freeing it:
|
||||
|
||||
nsIFoo* aFoo; // assume we get this somehow
|
||||
PRUnichar* bar;
|
||||
aFoo->GetFoo(&bar);
|
||||
// Use bar here...
|
||||
delete[] bar;
|
||||
|
||||
(Strictly speaking, The `delete[] bar' would use the proper XPCOM
|
||||
de-allocator, we'll ignore that for now.) This makes your life
|
||||
harder, because you need to convolute your code to ensure that you
|
||||
don't leak `bar'.
|
||||
|
||||
Enter nsXPIDLString, which manages the ownership of the allocated
|
||||
string, and automatically destroys it when the nsXPIDLString goes
|
||||
out of scope:
|
||||
|
||||
nsIFoo* aFoo;
|
||||
nsXPIDLString bar;
|
||||
aFoo->GetFoo( getter_Copies(bar) );
|
||||
// Use bar here...
|
||||
|
||||
Like nsCOMPtr, nsXPIDLString uses some syntactic sugar to make it
|
||||
painfully clear exactly what the code expects. You need to wrap an
|
||||
nsXPIDLString object with either `getter_Copies()' or
|
||||
`getter_Shares()': these tell the nsXPIDLString how ownership is
|
||||
being handled. In the case of `getter_Copies()', the callee is
|
||||
allocating a copy (which is usually the case). In the case of
|
||||
`getter_Shares()', the callee is returning a const reference to `the
|
||||
real deal' (this can be done using the [shared] attribute in XPIDL).
|
||||
|
||||
*/
|
||||
|
||||
#ifndef nsXPIDLString_h__
|
||||
#define nsXPIDLString_h__
|
||||
|
||||
#include "nsCom.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
#ifndef __PRUNICHAR__
|
||||
#define __PRUNICHAR__
|
||||
typedef PRUint16 PRUnichar;
|
||||
#endif /* __PRUNICHAR__ */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLString
|
||||
//
|
||||
// A wrapper for Unicode strings. With the |getter_Copies()| and
|
||||
// |getter_Shares()| helper functions, this can be used instead of
|
||||
// the "naked" |PRUnichar*| interface for |wstring| parameters in
|
||||
// XPIDL interfaces.
|
||||
//
|
||||
|
||||
class NS_COM nsXPIDLString {
|
||||
private:
|
||||
PRUnichar* mBuf;
|
||||
PRBool mBufOwner;
|
||||
|
||||
PRUnichar** StartAssignmentByValue();
|
||||
const PRUnichar** StartAssignmentByReference();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new, uninitialized wrapper for a Unicode string.
|
||||
*/
|
||||
nsXPIDLString();
|
||||
|
||||
virtual ~nsXPIDLString();
|
||||
|
||||
/**
|
||||
* Return an immutable reference to the Unicode string.
|
||||
*/
|
||||
operator const PRUnichar*();
|
||||
|
||||
/**
|
||||
* Make a copy of the Unicode string. Use this function in the
|
||||
* callee to ensure that the correct memory allocator is used.
|
||||
*/
|
||||
static PRUnichar* Copy(const PRUnichar* aString);
|
||||
|
||||
// A helper class for assignment-by-value. This class is an
|
||||
// implementation detail and should not be considered part of the
|
||||
// public interface.
|
||||
class NS_COM GetterCopies {
|
||||
private:
|
||||
nsXPIDLString& mXPIDLString;
|
||||
|
||||
public:
|
||||
GetterCopies(nsXPIDLString& aXPIDLString)
|
||||
: mXPIDLString(aXPIDLString) {}
|
||||
|
||||
operator PRUnichar**() {
|
||||
return mXPIDLString.StartAssignmentByValue();
|
||||
}
|
||||
|
||||
friend GetterCopies getter_Copies(nsXPIDLString& aXPIDLString);
|
||||
};
|
||||
|
||||
friend class GetterCopies;
|
||||
|
||||
// A helper class for assignment-by-reference. This class is an
|
||||
// implementation detail and should not be considered part of the
|
||||
// public interface.
|
||||
class NS_COM GetterShares {
|
||||
private:
|
||||
nsXPIDLString& mXPIDLString;
|
||||
|
||||
public:
|
||||
GetterShares(nsXPIDLString& aXPIDLString)
|
||||
: mXPIDLString(aXPIDLString) {}
|
||||
|
||||
operator const PRUnichar**() {
|
||||
return mXPIDLString.StartAssignmentByReference();
|
||||
}
|
||||
|
||||
friend GetterShares getter_Shares(nsXPIDLString& aXPIDLString);
|
||||
};
|
||||
|
||||
friend class GetterShares;
|
||||
|
||||
private:
|
||||
// not to be implemented
|
||||
nsXPIDLString(nsXPIDLString& aXPIDLString) {}
|
||||
nsXPIDLString& operator =(nsXPIDLString& aXPIDLString) { return *this; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Use this function to "wrap" the nsXPIDLString object that is to
|
||||
* receive an |out| value.
|
||||
*/
|
||||
inline nsXPIDLString::GetterCopies
|
||||
getter_Copies(nsXPIDLString& aXPIDLString)
|
||||
{
|
||||
return nsXPIDLString::GetterCopies(aXPIDLString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this function to "wrap" the nsXPIDLString object that is to
|
||||
* receive a |[shared] out| value.
|
||||
*/
|
||||
inline nsXPIDLString::GetterShares
|
||||
getter_Shares(nsXPIDLString& aXPIDLString)
|
||||
{
|
||||
return nsXPIDLString::GetterShares(aXPIDLString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// nsXPIDLCString
|
||||
//
|
||||
// A wrapper for Unicode strings. With the |getter_Copies()| and
|
||||
// |getter_Shares()| helper functions, this can be used instead of
|
||||
// the "naked" |char*| interface for |wstring| parameters in XPIDL
|
||||
// interfaces.
|
||||
//
|
||||
|
||||
class NS_COM nsXPIDLCString {
|
||||
private:
|
||||
char* mBuf;
|
||||
PRBool mBufOwner;
|
||||
|
||||
char** StartAssignmentByValue();
|
||||
const char** StartAssignmentByReference();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new, uninitialized wrapper for a single-byte string.
|
||||
*/
|
||||
nsXPIDLCString();
|
||||
|
||||
virtual ~nsXPIDLCString();
|
||||
|
||||
/**
|
||||
* Return an immutable reference to the single-byte string.
|
||||
*/
|
||||
operator const char*();
|
||||
|
||||
/**
|
||||
* Make a copy of the single-byte string. Use this function in the
|
||||
* callee to ensure that the correct memory allocator is used.
|
||||
*/
|
||||
static char* Copy(const char* aString);
|
||||
|
||||
// A helper class for assignment-by-value. This class is an
|
||||
// implementation detail and should not be considered part of the
|
||||
// public interface.
|
||||
class NS_COM GetterCopies {
|
||||
private:
|
||||
nsXPIDLCString& mXPIDLString;
|
||||
|
||||
public:
|
||||
GetterCopies(nsXPIDLCString& aXPIDLString)
|
||||
: mXPIDLString(aXPIDLString) {}
|
||||
|
||||
operator char**() {
|
||||
return mXPIDLString.StartAssignmentByValue();
|
||||
}
|
||||
|
||||
friend GetterCopies getter_Copies(nsXPIDLCString& aXPIDLString);
|
||||
};
|
||||
|
||||
friend class GetterCopies;
|
||||
|
||||
// A helper class for assignment-by-reference. This class is an
|
||||
// implementation detail and should not be considered part of the
|
||||
// public interface.
|
||||
class NS_COM GetterShares {
|
||||
private:
|
||||
nsXPIDLCString& mXPIDLString;
|
||||
|
||||
public:
|
||||
GetterShares(nsXPIDLCString& aXPIDLString)
|
||||
: mXPIDLString(aXPIDLString) {}
|
||||
|
||||
operator const char**() {
|
||||
return mXPIDLString.StartAssignmentByReference();
|
||||
}
|
||||
|
||||
friend GetterShares getter_Shares(nsXPIDLCString& aXPIDLString);
|
||||
};
|
||||
|
||||
friend class GetterShares;
|
||||
|
||||
private:
|
||||
// not to be implemented
|
||||
nsXPIDLCString(nsXPIDLCString& aXPIDLString) {}
|
||||
nsXPIDLCString& operator =(nsXPIDLCString& aXPIDLString) { return *this; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Use this function to "wrap" the nsXPIDLCString object that is to
|
||||
* receive an |out| value.
|
||||
*/
|
||||
inline nsXPIDLCString::GetterCopies
|
||||
getter_Copies(nsXPIDLCString& aXPIDLString)
|
||||
{
|
||||
return nsXPIDLCString::GetterCopies(aXPIDLString);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use this function to "wrap" the nsXPIDLCString object that is to
|
||||
* receive a |[shared] out| value.
|
||||
*/
|
||||
inline nsXPIDLCString::GetterShares
|
||||
getter_Shares(nsXPIDLCString& aXPIDLString)
|
||||
{
|
||||
return nsXPIDLCString::GetterShares(aXPIDLString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // nsXPIDLString_h__
|
||||
@@ -1,30 +0,0 @@
|
||||
#!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 idl libxpt
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
DIRS += tests
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,170 +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 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___ */
|
||||
@@ -1,129 +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.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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?
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1,92 +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.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of nsIAllocator using NSPR
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef nsAllocator_h__
|
||||
#define nsAllocator_h__
|
||||
|
||||
#include "nsIAllocator.h"
|
||||
#include "prmem.h"
|
||||
#include "nsAgg.h"
|
||||
#include "nsIFactory.h"
|
||||
|
||||
class nsAllocator : public nsIAllocator {
|
||||
public:
|
||||
static const nsCID& CID() { static nsCID cid = NS_ALLOCATOR_CID; return cid; }
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsAllocatorFactory : public 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__
|
||||
@@ -1,54 +0,0 @@
|
||||
/* -*- 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);
|
||||
}
|
||||
@@ -1,493 +0,0 @@
|
||||
/* -*- 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
|
||||
|
||||
/*
|
||||
Having problems?
|
||||
|
||||
See the User Manual at:
|
||||
<http://www.meer.net/ScottCollins/doc/nsCOMPtr.html>, or
|
||||
<http://www.mozilla.org/projects/xpcom/nsCOMPtr.html>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
TO DO...
|
||||
|
||||
+ make StartAssignment optionally inlined
|
||||
+ make constructor for |nsQueryInterface| explicit (suddenly construct/assign from raw pointer becomes illegal)
|
||||
+ Improve internal documentation
|
||||
+ mention *&
|
||||
+ alternatives for comparison
|
||||
+ do_QueryInterface
|
||||
*/
|
||||
|
||||
/*
|
||||
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. These are set up automatically
|
||||
by the autoconf system for all Unixes. (Temporarily, I hope) I have to define them
|
||||
myself for Mac and Windows.
|
||||
*/
|
||||
|
||||
// under Metrowerks (Mac), we don't have autoconf yet
|
||||
#ifdef __MWERKS__
|
||||
#define HAVE_CPP_USING
|
||||
#define HAVE_CPP_EXPLICIT
|
||||
#define HAVE_CPP_NEW_CASTS
|
||||
#endif
|
||||
|
||||
// under VC++ (Windows), we don't have autoconf yet
|
||||
#ifdef _MSC_VER
|
||||
#define HAVE_CPP_EXPLICIT
|
||||
#define HAVE_CPP_USING
|
||||
#define HAVE_CPP_NEW_CASTS
|
||||
|
||||
#if (_MSC_VER<1100)
|
||||
// before 5.0, VC++ couldn't handle explicit
|
||||
#undef HAVE_CPP_EXPLICIT
|
||||
#elif (_MSC_VER==1100)
|
||||
// VC++5.0 has an internal compiler error (sometimes) without this
|
||||
#undef HAVE_CPP_USING
|
||||
#endif
|
||||
|
||||
#define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
|
||||
// under VC++, we win by inlining StartAssignment
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
If the compiler doesn't support |explicit|, we'll just make it go away, trusting
|
||||
that the builds under compilers that do have it will keep us on the straight and narrow.
|
||||
*/
|
||||
#ifndef HAVE_CPP_EXPLICIT
|
||||
#define explicit
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CPP_NEW_CASTS
|
||||
#define NSCAP_REINTERPRET_CAST(T,x) reinterpret_cast<T>(x)
|
||||
#else
|
||||
#define NSCAP_REINTERPRET_CAST(T,x) ((T)(x))
|
||||
#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:
|
||||
#ifdef HAVE_CPP_USING
|
||||
using T::AddRef;
|
||||
using T::Release;
|
||||
#else
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void);
|
||||
NS_IMETHOD_(nsrefcnt) Release(void);
|
||||
#endif
|
||||
|
||||
void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED
|
||||
// declaring |operator delete| private makes calling delete on an interface pointer a compile error
|
||||
|
||||
nsDerivedSafe<T>& operator=( const nsDerivedSafe<T>& ); // NOT TO BE IMPLEMENTED
|
||||
// you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one
|
||||
};
|
||||
|
||||
#if !defined(HAVE_CPP_USING) && defined(NEED_CPP_UNUSED_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;
|
||||
};
|
||||
|
||||
// This call is now deprecated. Use |getter_AddRefs()| instead.
|
||||
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)|.
|
||||
*/
|
||||
{
|
||||
return nsDontAddRef<T>(aRawPtr);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline
|
||||
nsDontAddRef<T>
|
||||
getter_AddRefs( T* aRawPtr )
|
||||
{
|
||||
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::GetIID(), 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::GetIID(), 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<T>& 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()
|
||||
{
|
||||
#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
|
||||
return NSCAP_REINTERPRET_CAST(T**, begin_assignment());
|
||||
#else
|
||||
if ( mRawPtr )
|
||||
NSCAP_RELEASE(mRawPtr);
|
||||
mRawPtr = 0;
|
||||
return NSCAP_REINTERPRET_CAST(T**, &mRawPtr);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
{
|
||||
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___)
|
||||
@@ -1,227 +0,0 @@
|
||||
/* -*- 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
|
||||
|
||||
#define NS_CALLBACK_(_type, _name) _type (__stdcall * _name)
|
||||
#define NS_CALLBACK(_name) nsresult (__stdcall * _name)
|
||||
|
||||
#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
|
||||
|
||||
#define NS_CALLBACK_(_type, _name) _type (* _name)
|
||||
#define NS_CALLBACK(_name) nsresult (* _name)
|
||||
|
||||
#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
|
||||
|
||||
#define NS_CALLBACK_(_type, _name) _type (* _name)
|
||||
#define NS_CALLBACK(_name) nsresult (* _name)
|
||||
|
||||
#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
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/* -*- 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"
|
||||
#include "prinit.h"
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
/* for abort() */
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#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
|
||||
//------------------------
|
||||
#elif defined(XP_UNIX)
|
||||
#include<stdlib.h>
|
||||
#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)
|
||||
PR_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));
|
||||
PR_LogFlush();
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/* -*- 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___ */
|
||||
@@ -1,195 +0,0 @@
|
||||
/* -*- 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
|
||||
#define NS_ERROR_MODULE_EDITOR 17
|
||||
|
||||
/**
|
||||
* @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)
|
||||
|
||||
/*@}*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef XP_PC
|
||||
#pragma warning(disable: 4251) // 'nsCOMPtr<class nsIInputStream>' needs to have dll-interface to be used by clients of class 'nsInputStream'
|
||||
#pragma warning(disable: 4275) // non dll-interface class 'nsISupports' used as base for dll-interface class 'nsIRDFNode'
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,83 +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 nsIAllocator_h___
|
||||
#define nsIAllocator_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
|
||||
/**
|
||||
* Unlike IMalloc, this interface returns nsresults and doesn't
|
||||
* implement the problematic GetSize and DidAlloc routines.
|
||||
*/
|
||||
|
||||
#define NS_IALLOCATOR_IID \
|
||||
{ /* 56def700-b1b9-11d2-8177-006008119d7a */ \
|
||||
0x56def700, \
|
||||
0xb1b9, \
|
||||
0x11d2, \
|
||||
{0x81, 0x77, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
class nsIAllocator : public nsISupports {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IALLOCATOR_IID; return iid; }
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
};
|
||||
|
||||
// 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___ */
|
||||
@@ -1,73 +0,0 @@
|
||||
/* -*- 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;
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/* -*- 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
|
||||
|
||||
/*
|
||||
* Class IDs
|
||||
*/
|
||||
|
||||
typedef nsID nsCID;
|
||||
|
||||
// Define an CID
|
||||
#define NS_DEFINE_CID(_name, _cidspec) \
|
||||
const nsCID _name = _cidspec
|
||||
|
||||
#define REFNSCID const nsCID&
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/* -*- 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___
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/* -*- Mode: IDL; 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.
|
||||
*/
|
||||
|
||||
%{C++
|
||||
#include "nsDebug.h"
|
||||
#include "nsTraceRefcnt.h"
|
||||
#include "nsIID.h"
|
||||
%}
|
||||
#include "nsID.idl"
|
||||
%{C++
|
||||
#include "nsError.h"
|
||||
|
||||
#include "nsISupportsUtils.h"
|
||||
%}
|
||||
|
||||
native nsQIResult(void *);
|
||||
native voidStar(void*);
|
||||
native voidStarRef(void**);
|
||||
native nsIIDRef(REFNSIID);
|
||||
|
||||
typedef unsigned long nsrefcnt;
|
||||
|
||||
[
|
||||
object,
|
||||
uuid(00000000-0000-0000-c000-000000000046)
|
||||
]
|
||||
interface nsISupports {
|
||||
void QueryInterface(in nsIIDRef uuid, out nsQIResult result);
|
||||
[notxpcom] nsrefcnt AddRef();
|
||||
[notxpcom] nsrefcnt Release();
|
||||
};
|
||||
@@ -1,557 +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 __nsISupportsUtils_h
|
||||
#define __nsISupportsUtils_h
|
||||
|
||||
|
||||
/**
|
||||
* A macro to build the static const IID accessor method
|
||||
*/
|
||||
|
||||
#define NS_DEFINE_STATIC_IID_ACCESSOR(the_iid) \
|
||||
static const nsIID& GetIID() {static nsIID iid = the_iid; return iid;}
|
||||
|
||||
/**
|
||||
* A macro to build the static const CID accessor method
|
||||
*/
|
||||
|
||||
#define NS_DEFINE_STATIC_CID_ACCESSOR(the_cid) \
|
||||
static const nsID& GetCID() {static nsID cid = the_cid; return cid;}
|
||||
|
||||
/**
|
||||
* Some convenience macros for implementing AddRef and Release
|
||||
*/
|
||||
|
||||
/**
|
||||
* Declare the reference count variable and the implementations of the
|
||||
* AddRef and QueryInterface methods.
|
||||
*/
|
||||
|
||||
#define NS_DECL_ISUPPORTS \
|
||||
public: \
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, \
|
||||
void** aInstancePtr); \
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void); \
|
||||
NS_IMETHOD_(nsrefcnt) Release(void); \
|
||||
protected: \
|
||||
nsrefcnt mRefCnt; \
|
||||
public:
|
||||
|
||||
#define NS_DECL_ISUPPORTS_EXPORTED \
|
||||
public: \
|
||||
NS_EXPORT NS_IMETHOD QueryInterface(REFNSIID aIID, \
|
||||
void** aInstancePtr); \
|
||||
NS_EXPORT NS_IMETHOD_(nsrefcnt) AddRef(void); \
|
||||
NS_EXPORT NS_IMETHOD_(nsrefcnt) Release(void); \
|
||||
protected: \
|
||||
nsrefcnt mRefCnt; \
|
||||
public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Initialize the reference count variable. Add this to each and every
|
||||
* constructor you implement.
|
||||
*/
|
||||
#define NS_INIT_REFCNT() mRefCnt = 0
|
||||
#define NS_INIT_ISUPPORTS() NS_INIT_REFCNT() // what it should have been called in the first place
|
||||
|
||||
/**
|
||||
* Use this macro to implement the AddRef method for a given <i>_class</i>
|
||||
* @param _class The name of the class implementing the method
|
||||
*/
|
||||
#define NS_IMPL_ADDREF(_class) \
|
||||
NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \
|
||||
{ \
|
||||
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \
|
||||
return ++mRefCnt; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this macro to implement the Release method for a given <i>_class</i>
|
||||
* @param _class The name of the class implementing the method
|
||||
*/
|
||||
#define NS_IMPL_RELEASE(_class) \
|
||||
NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \
|
||||
{ \
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release"); \
|
||||
if (--mRefCnt == 0) { \
|
||||
NS_DELETEXPCOM(this); \
|
||||
return 0; \
|
||||
} \
|
||||
return mRefCnt; \
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Some convenience macros for implementing QueryInterface
|
||||
*/
|
||||
|
||||
/**
|
||||
* This implements query interface with two assumptions: First, the
|
||||
* class in question implements nsISupports and it's own interface and
|
||||
* nothing else. Second, the implementation of the class's primary
|
||||
* inheritance chain leads to it's own interface.
|
||||
*
|
||||
* @param _class The name of the class implementing the method
|
||||
* @param _classiiddef The name of the #define symbol that defines the IID
|
||||
* for the class (e.g. NS_ISUPPORTS_IID)
|
||||
*/
|
||||
|
||||
#define NS_IMPL_QUERY_INTERFACE(_class,_classiiddef) \
|
||||
NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
|
||||
{ \
|
||||
if (NULL == aInstancePtr) { \
|
||||
return NS_ERROR_NULL_POINTER; \
|
||||
} \
|
||||
\
|
||||
*aInstancePtr = NULL; \
|
||||
\
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); \
|
||||
static NS_DEFINE_IID(kClassIID, _classiiddef); \
|
||||
if (aIID.Equals(kClassIID)) { \
|
||||
*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; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience macro for implementing all nsISupports methods for
|
||||
* a simple class.
|
||||
* @param _class The name of the class implementing the method
|
||||
* @param _classiiddef The name of the #define symbol that defines the IID
|
||||
* for the class (e.g. NS_ISUPPORTS_IID)
|
||||
*/
|
||||
|
||||
#define NS_IMPL_ISUPPORTS(_class,_classiiddef) \
|
||||
NS_IMPL_ADDREF(_class) \
|
||||
NS_IMPL_RELEASE(_class) \
|
||||
NS_IMPL_QUERY_INTERFACE(_class,_classiiddef)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Declare that you're going to inherit from something that already
|
||||
* implements nsISupports, but also implements an additional interface, thus
|
||||
* causing an ambiguity. In this case you don't need another mRefCnt, you
|
||||
* just need to forward the definitions to the appropriate superclass. E.g.
|
||||
*
|
||||
* class Bar : public Foo, public nsIBar { // both provide nsISupports
|
||||
* public:
|
||||
* NS_DECL_ISUPPORTS_INHERITED
|
||||
* ...other nsIBar and Bar methods...
|
||||
* };
|
||||
*/
|
||||
#define NS_DECL_ISUPPORTS_INHERITED \
|
||||
public: \
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, \
|
||||
void** aInstancePtr); \
|
||||
NS_IMETHOD_(nsrefcnt) AddRef(void); \
|
||||
NS_IMETHOD_(nsrefcnt) Release(void); \
|
||||
|
||||
/**
|
||||
* These macros can be used in conjunction with NS_DECL_ISUPPORTS_INHERITED
|
||||
* to implement the nsISupports methods, forwarding the invocations to a
|
||||
* superclass that already implements nsISupports.
|
||||
*
|
||||
* Note that I didn't make these inlined because they're virtual methods.
|
||||
*/
|
||||
|
||||
#define NS_IMPL_ADDREF_INHERITED(Class, Super) \
|
||||
NS_IMETHODIMP_(nsrefcnt) Class::AddRef(void) \
|
||||
{ \
|
||||
return Super::AddRef(); \
|
||||
} \
|
||||
|
||||
#define NS_IMPL_RELEASE_INHERITED(Class, Super) \
|
||||
NS_IMETHODIMP_(nsrefcnt) Class::Release(void) \
|
||||
{ \
|
||||
return Super::Release(); \
|
||||
} \
|
||||
|
||||
#define NS_IMPL_QUERY_INTERFACE_INHERITED(Class, Super, AdditionalInterface) \
|
||||
NS_IMETHODIMP Class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
|
||||
{ \
|
||||
if (!aInstancePtr) return NS_ERROR_NULL_POINTER; \
|
||||
if (aIID.Equals(AdditionalInterface::GetIID())) { \
|
||||
*aInstancePtr = NS_STATIC_CAST(AdditionalInterface*, this); \
|
||||
NS_ADDREF_THIS(); \
|
||||
return NS_OK; \
|
||||
} \
|
||||
return Super::QueryInterface(aIID, aInstancePtr); \
|
||||
} \
|
||||
|
||||
#define NS_IMPL_ISUPPORTS_INHERITED(Class, Super, AdditionalInterface) \
|
||||
NS_IMPL_QUERY_INTERFACE_INHERITED(Class, Super, AdditionalInterface) \
|
||||
NS_IMPL_ADDREF_INHERITED(Class, Super) \
|
||||
NS_IMPL_RELEASE_INHERITED(Class, Super) \
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
*
|
||||
* Threadsafe implementations of the ISupports convenience macros
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* IID for the nsIsThreadsafe interface
|
||||
* {88210890-47a6-11d2-bec3-00805f8a66dc}
|
||||
*
|
||||
* This interface is *only* used for debugging purposes to determine if
|
||||
* a given component is threadsafe.
|
||||
*/
|
||||
#define NS_ISTHREADSAFE_IID \
|
||||
{ 0x88210890, 0x47a6, 0x11d2, \
|
||||
{0xbe, 0xc3, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0xdc} }
|
||||
|
||||
#if defined(NS_MT_SUPPORTED)
|
||||
|
||||
#define NS_LOCK_INSTANCE() \
|
||||
PR_CEnterMonitor((void*)this)
|
||||
|
||||
#define NS_UNLOCK_INSTANCE() \
|
||||
PR_CExitMonitor((void*)this)
|
||||
|
||||
/**
|
||||
* Use this macro to implement the AddRef method for a given <i>_class</i>
|
||||
* @param _class The name of the class implementing the method
|
||||
*/
|
||||
#if defined(XP_PC)
|
||||
#define NS_IMPL_THREADSAFE_ADDREF(_class) \
|
||||
NS_IMETHODIMP_(nsrefcnt) _class::AddRef(void) \
|
||||
{ \
|
||||
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \
|
||||
return InterlockedIncrement((LONG*)&mRefCnt); \
|
||||
}
|
||||
|
||||
#else /* ! XP_PC */
|
||||
#define NS_IMPL_THREADSAFE_ADDREF(_class) \
|
||||
nsrefcnt _class::AddRef(void) \
|
||||
{ \
|
||||
nsrefcnt count; \
|
||||
NS_LOCK_INSTANCE(); \
|
||||
NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); \
|
||||
count = ++mRefCnt; \
|
||||
NS_UNLOCK_INSTANCE(); \
|
||||
return count; \
|
||||
}
|
||||
#endif /* ! XP_PC */
|
||||
|
||||
/**
|
||||
* Use this macro to implement the Release method for a given <i>_class</i>
|
||||
* @param _class The name of the class implementing the method
|
||||
*/
|
||||
#if defined(XP_PC)
|
||||
#define NS_IMPL_THREADSAFE_RELEASE(_class) \
|
||||
NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \
|
||||
{ \
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release"); \
|
||||
if (0 == InterlockedDecrement((LONG*)&mRefCnt)) { \
|
||||
NS_DELETEXPCOM(this); \
|
||||
return 0; \
|
||||
} \
|
||||
return mRefCnt; /* Not threadsafe but who cares. */ \
|
||||
}
|
||||
|
||||
#else /* ! XP_PC */
|
||||
#define NS_IMPL_THREADSAFE_RELEASE(_class) \
|
||||
nsrefcnt _class::Release(void) \
|
||||
{ \
|
||||
nsrefcnt count; \
|
||||
NS_PRECONDITION(0 != mRefCnt, "dup release"); \
|
||||
NS_LOCK_INSTANCE(); \
|
||||
count = --mRefCnt; \
|
||||
NS_UNLOCK_INSTANCE(); \
|
||||
if (0 == count) { \
|
||||
NS_DELETEXPCOM(this); \
|
||||
return 0; \
|
||||
} \
|
||||
return count; \
|
||||
}
|
||||
#endif /* ! XP_PC */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* Some convenience macros for implementing QueryInterface
|
||||
*/
|
||||
|
||||
/**
|
||||
* This implements query interface with two assumptions: First, the
|
||||
* class in question implements nsISupports and it's own interface and
|
||||
* nothing else. Second, the implementation of the class's primary
|
||||
* inheritance chain leads to it's own interface.
|
||||
*
|
||||
* @param _class The name of the class implementing the method
|
||||
* @param _classiiddef The name of the #define symbol that defines the IID
|
||||
* for the class (e.g. NS_ISUPPORTS_IID)
|
||||
*/
|
||||
#if defined(NS_DEBUG)
|
||||
#define NS_VERIFY_THREADSAFE_INTERFACE(_iface) \
|
||||
if (NULL != (_iface)) { \
|
||||
nsISupports* tmp; \
|
||||
static NS_DEFINE_IID(kIsThreadsafeIID, NS_ISTHREADSAFE_IID); \
|
||||
NS_PRECONDITION((NS_OK == _iface->QueryInterface(kIsThreadsafeIID, \
|
||||
(void**)&tmp)), \
|
||||
"Interface is not threadsafe"); \
|
||||
}
|
||||
|
||||
#define NS_IMPL_THREADSAFE_QUERY_INTERFACE(_class,_classiiddef) \
|
||||
NS_IMETHODIMP _class::QueryInterface(REFNSIID aIID, void** aInstancePtr) \
|
||||
{ \
|
||||
if (NULL == aInstancePtr) { \
|
||||
return NS_ERROR_NULL_POINTER; \
|
||||
} \
|
||||
\
|
||||
*aInstancePtr = NULL; \
|
||||
\
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); \
|
||||
static NS_DEFINE_IID(kIsThreadsafeIID, NS_ISTHREADSAFE_IID); \
|
||||
static NS_DEFINE_IID(kClassIID, _classiiddef); \
|
||||
if (aIID.Equals(kClassIID)) { \
|
||||
*aInstancePtr = (void*) this; \
|
||||
NS_ADDREF_THIS(); \
|
||||
return NS_OK; \
|
||||
} \
|
||||
if (aIID.Equals(kISupportsIID)) { \
|
||||
*aInstancePtr = (void*) ((nsISupports*)this); \
|
||||
NS_ADDREF_THIS(); \
|
||||
return NS_OK; \
|
||||
} \
|
||||
if (aIID.Equals(kIsThreadsafeIID)) { \
|
||||
return NS_OK; \
|
||||
} \
|
||||
return NS_NOINTERFACE; \
|
||||
}
|
||||
|
||||
#else /* !NS_DEBUG */
|
||||
|
||||
#define NS_VERIFY_THREADSAFE_INTERFACE(_iface)
|
||||
#define NS_IMPL_THREADSAFE_QUERY_INTERFACE(_class,_classiiddef) \
|
||||
NS_IMPL_QUERY_INTERFACE(_class, _classiiddef)
|
||||
|
||||
#endif /* !NS_DEBUG */
|
||||
|
||||
/**
|
||||
* Convenience macro for implementing all nsISupports methods for
|
||||
* a simple class.
|
||||
* @param _class The name of the class implementing the method
|
||||
* @param _classiiddef The name of the #define symbol that defines the IID
|
||||
* for the class (e.g. NS_ISUPPORTS_IID)
|
||||
*/
|
||||
|
||||
#define NS_IMPL_THREADSAFE_ISUPPORTS(_class,_classiiddef) \
|
||||
NS_IMPL_THREADSAFE_ADDREF(_class) \
|
||||
NS_IMPL_THREADSAFE_RELEASE(_class) \
|
||||
NS_IMPL_THREADSAFE_QUERY_INTERFACE(_class,_classiiddef)
|
||||
|
||||
#else /* !NS_MT_SUPPORTED */
|
||||
|
||||
#define NS_LOCK_INSTANCE()
|
||||
|
||||
#define NS_UNLOCK_INSTANCE()
|
||||
|
||||
#define NS_IMPL_THREADSAFE_ADDREF(_class) NS_IMPL_ADDREF(_class)
|
||||
|
||||
#define NS_IMPL_THREADSAFE_RELEASE(_class) NS_IMPL_RELEASE(_class)
|
||||
|
||||
#define NS_VERIFY_THREADSAFE_INTERFACE(_iface)
|
||||
|
||||
#define NS_IMPL_THREADSAFE_QUERY_INTERFACE(_class,_classiiddef) \
|
||||
NS_IMPL_QUERY_INTERFACE(_class, _classiiddef)
|
||||
|
||||
#define NS_IMPL_THREADSAFE_ISUPPORTS(_class,_classiiddef) \
|
||||
NS_IMPL_ADDREF(_class) \
|
||||
NS_IMPL_RELEASE(_class) \
|
||||
NS_IMPL_QUERY_INTERFACE(_class,_classiiddef)
|
||||
|
||||
#endif /* !NS_MT_SUPPORTED */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Debugging Macros
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Macro for instantiating a new object that implements nsISupports.
|
||||
* Use this in your factory methods to allow for refcnt tracing.
|
||||
* Note that you can only use this if you adhere to the no arguments
|
||||
* constructor com policy (which you really should!).
|
||||
* @param _result Where the new instance pointer is stored
|
||||
* @param _type The type of object to call "new" with.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_NEWXPCOM(_result,_type) \
|
||||
PR_BEGIN_MACRO \
|
||||
_result = new _type(); \
|
||||
nsTraceRefcnt::Create(_result, #_type, __FILE__, __LINE__); \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
#define NS_NEWXPCOM(_result,_type) \
|
||||
_result = new _type()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for deleting an object that implements nsISupports.
|
||||
* Use this in your Release methods to allow for refcnt tracing.
|
||||
* @param _ptr The object to delete.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_DELETEXPCOM(_ptr) \
|
||||
PR_BEGIN_MACRO \
|
||||
nsTraceRefcnt::Destroy((_ptr), __FILE__, __LINE__); \
|
||||
delete (_ptr); \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
#define NS_DELETEXPCOM(_ptr) \
|
||||
delete (_ptr)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for adding a reference to an interface.
|
||||
* @param _ptr The interface pointer.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_ADDREF(_ptr) \
|
||||
((nsrefcnt) nsTraceRefcnt::AddRef((_ptr), (_ptr)->AddRef(), \
|
||||
__FILE__, __LINE__))
|
||||
#else
|
||||
#define NS_ADDREF(_ptr) \
|
||||
(_ptr)->AddRef()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for adding a reference to this. This macro should be used
|
||||
* because NS_ADDREF (when tracing) may require an ambiguous cast
|
||||
* from the pointers primary type to nsISupports. This macro sidesteps
|
||||
* that entire problem.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_ADDREF_THIS() \
|
||||
((nsrefcnt) nsTraceRefcnt::AddRef(this, AddRef(), __FILE__, __LINE__))
|
||||
#else
|
||||
#define NS_ADDREF_THIS() \
|
||||
AddRef()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for adding a reference to an interface that checks for NULL.
|
||||
* @param _ptr The interface pointer.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_IF_ADDREF(_ptr) \
|
||||
((0 != (_ptr)) \
|
||||
? ((nsrefcnt) nsTraceRefcnt::AddRef((_ptr), (_ptr)->AddRef(), __FILE__, \
|
||||
__LINE__)) \
|
||||
: 0)
|
||||
#else
|
||||
#define NS_IF_ADDREF(_ptr) \
|
||||
((0 != (_ptr)) ? (_ptr)->AddRef() : 0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for releasing a reference to an interface.
|
||||
*
|
||||
* Note that when MOZ_TRACE_XPCOM_REFCNT is defined that the release will
|
||||
* be done before the trace message is logged. If the reference count
|
||||
* goes to zero and implementation of Release logs a message, the two
|
||||
* messages will be logged out of order.
|
||||
*
|
||||
* @param _ptr The interface pointer.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_RELEASE(_ptr) \
|
||||
PR_BEGIN_MACRO \
|
||||
nsTraceRefcnt::Release((_ptr), (_ptr)->Release(), __FILE__, __LINE__); \
|
||||
(_ptr) = 0; \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
#define NS_RELEASE(_ptr) \
|
||||
PR_BEGIN_MACRO \
|
||||
(_ptr)->Release(); \
|
||||
(_ptr) = 0; \
|
||||
PR_END_MACRO
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for releasing a reference to an interface, except that this
|
||||
* macro preserves the return value from the underlying Release call.
|
||||
* The interface pointer argument will only be NULLed if the reference count
|
||||
* goes to zero.
|
||||
*
|
||||
* Note that when MOZ_TRACE_XPCOM_REFCNT is defined that the release will
|
||||
* be done before the trace message is logged. If the reference count
|
||||
* goes to zero and implementation of Release logs a message, the two
|
||||
* messages will be logged out of order.
|
||||
*
|
||||
* @param _ptr The interface pointer.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_RELEASE2(_ptr, _result) \
|
||||
PR_BEGIN_MACRO \
|
||||
_result = ((nsrefcnt) nsTraceRefcnt::Release((_ptr), (_ptr)->Release(), \
|
||||
__FILE__, __LINE__)); \
|
||||
if (0 == (_result)) (_ptr) = 0; \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
#define NS_RELEASE2(_ptr, _result) \
|
||||
PR_BEGIN_MACRO \
|
||||
_result = (_ptr)->Release(); \
|
||||
if (0 == (_result)) (_ptr) = 0; \
|
||||
PR_END_MACRO
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro for releasing a reference to an interface that checks for NULL;
|
||||
*
|
||||
* Note that when MOZ_TRACE_XPCOM_REFCNT is defined that the release will
|
||||
* be done before the trace message is logged. If the reference count
|
||||
* goes to zero and implementation of Release logs a message, the two
|
||||
* messages will be logged out of order.
|
||||
*
|
||||
* @param _ptr The interface pointer.
|
||||
*/
|
||||
#ifdef MOZ_TRACE_XPCOM_REFCNT
|
||||
#define NS_IF_RELEASE(_ptr) \
|
||||
PR_BEGIN_MACRO \
|
||||
((0 != (_ptr)) \
|
||||
? ((nsrefcnt) nsTraceRefcnt::Release((_ptr), (_ptr)->Release(), \
|
||||
__FILE__, __LINE__)) \
|
||||
: 0); \
|
||||
(_ptr) = 0; \
|
||||
PR_END_MACRO
|
||||
#else
|
||||
#define NS_IF_RELEASE(_ptr) \
|
||||
PR_BEGIN_MACRO \
|
||||
((0 != (_ptr)) ? (_ptr)->Release() : 0); \
|
||||
(_ptr) = 0; \
|
||||
PR_END_MACRO
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* __nsISupportsUtils_h */
|
||||
@@ -1,317 +0,0 @@
|
||||
/* -*- 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(MOZ_TRACE_XPCOM_REFCNT)
|
||||
#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;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#else /* MOZ_TRACE_XPCOM_REFCNT */
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
||||
{
|
||||
aBuffer[0] = '\0';
|
||||
}
|
||||
#endif /* MOZ_TRACE_XPCOM_REFCNT */
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/* -*- 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___ */
|
||||
@@ -1,317 +0,0 @@
|
||||
/* -*- 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(MOZ_TRACE_XPCOM_REFCNT)
|
||||
#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;
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#else /* MOZ_TRACE_XPCOM_REFCNT */
|
||||
void
|
||||
nsTraceRefcnt::WalkTheStack(char* aBuffer, int aBufLen)
|
||||
{
|
||||
aBuffer[0] = '\0';
|
||||
}
|
||||
#endif /* MOZ_TRACE_XPCOM_REFCNT */
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/* -*- 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___ */
|
||||
@@ -1,168 +0,0 @@
|
||||
/* -*- 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 "nsIComponentManager.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 nsComponentManager.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
|
||||
@@ -1,326 +0,0 @@
|
||||
/* -*- 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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,248 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; 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 nsComponentManager_h__
|
||||
#define nsComponentManager_h__
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIRegistry.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "prtime.h"
|
||||
#include "prmon.h"
|
||||
|
||||
class nsFactoryEntry;
|
||||
class nsDll;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
*** Quick Registration NOT FOR PUBLIC CONSUMPTION ***
|
||||
*
|
||||
* 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"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsComponentManagerImpl : public nsIComponentManager {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIComponentManager methods:
|
||||
NS_IMETHOD FindFactory(const nsCID &aClass,
|
||||
nsIFactory **aFactory);
|
||||
|
||||
// Finds a class ID for a specific Program ID
|
||||
NS_IMETHOD ProgIDToCLSID(const char *aProgID,
|
||||
nsCID *aClass);
|
||||
|
||||
// Finds a Program ID for a specific class ID
|
||||
// caller frees the result with delete[]
|
||||
NS_IMETHOD CLSIDToProgID(nsCID *aClass,
|
||||
char* *aClassName,
|
||||
char* *aProgID);
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
NS_IMETHOD CreateInstance(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult);
|
||||
|
||||
// Convenience routine, creates a class instance for a specific ProgID
|
||||
NS_IMETHOD CreateInstance(const char *aProgID,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult);
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
/*
|
||||
NS_IMETHOD CreateInstance2(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void *aSignature,
|
||||
void **aResult);
|
||||
*/
|
||||
|
||||
// Manually registry a factory for a class
|
||||
NS_IMETHOD RegisterFactory(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory *aFactory,
|
||||
PRBool aReplace);
|
||||
|
||||
// Manually register a dynamically loaded component.
|
||||
NS_IMETHOD RegisterComponent(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
const char *aLibrary,
|
||||
PRBool aReplace,
|
||||
PRBool aPersist);
|
||||
|
||||
// Manually unregister a factory for a class
|
||||
NS_IMETHOD UnregisterFactory(const nsCID &aClass,
|
||||
nsIFactory *aFactory);
|
||||
|
||||
// Manually unregister a dynamically loaded factory for a class
|
||||
NS_IMETHOD UnregisterFactory(const nsCID &aClass,
|
||||
const char *aLibrary);
|
||||
|
||||
// Manually unregister a dynamically loaded component
|
||||
NS_IMETHOD UnregisterComponent(const nsCID &aClass,
|
||||
const char *aLibrary);
|
||||
|
||||
// Unload dynamically loaded factories that are not in use
|
||||
NS_IMETHOD FreeLibraries(void);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// DLL registration support
|
||||
/* 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
|
||||
*/
|
||||
NS_IMETHOD AutoRegister(RegistrationTime when, const char* pathlist);
|
||||
// Pathlist is a semicolon separated list of pathnames
|
||||
NS_IMETHOD AddToDefaultPathList(const char *pathlist);
|
||||
NS_IMETHOD SyncComponentsInPathList(const char *pathlist);
|
||||
NS_IMETHOD SyncComponentsInDir(const char *path);
|
||||
NS_IMETHOD SyncComponentsInFile(const char *fullname);
|
||||
|
||||
// nsComponentManagerImpl methods:
|
||||
nsComponentManagerImpl();
|
||||
virtual ~nsComponentManagerImpl();
|
||||
|
||||
static nsComponentManagerImpl* gComponentManager;
|
||||
nsresult Init(void);
|
||||
|
||||
protected:
|
||||
nsresult LoadFactory(nsFactoryEntry *aEntry, nsIFactory **aFactory);
|
||||
nsresult SelfRegisterDll(nsDll *dll);
|
||||
nsresult SelfUnregisterDll(nsDll *dll);
|
||||
|
||||
nsresult PlatformVersionCheck();
|
||||
nsresult PlatformCreateDll(const char *fullname, nsDll* *result);
|
||||
nsresult PlatformMarkNoComponents(nsDll *dll);
|
||||
struct QuickRegisterData {
|
||||
const char *CIDString; // {98765-8776-8958758759-958785}
|
||||
const char *className; // "Layout Engine"
|
||||
const char *progID; // "Gecko.LayoutEngine.1"
|
||||
};
|
||||
nsresult PlatformRegister(QuickRegisterData* regd, nsDll *dll);
|
||||
nsresult PlatformUnregister(QuickRegisterData* regd, const char *aLibrary);
|
||||
nsresult PlatformFind(const nsCID &aCID, nsFactoryEntry* *result);
|
||||
nsresult PlatformProgIDToCLSID(const char *aProgID, nsCID *aClass);
|
||||
nsresult PlatformCLSIDToProgID(nsCID *aClass, char* *aClassName, char* *aProgID);
|
||||
void PlatformGetFileInfo(nsIRegistry::Key Key,PRTime *lastModifiedTime,PRUint32 *fileSize);
|
||||
|
||||
protected:
|
||||
nsHashtable* mFactories;
|
||||
nsHashtable* mProgIDs;
|
||||
PRMonitor* mMon;
|
||||
nsHashtable* mDllStore;
|
||||
nsIRegistry* mRegistry;
|
||||
};
|
||||
|
||||
#define NS_MAX_FILENAME_LEN 1024
|
||||
|
||||
#define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24)
|
||||
|
||||
#ifdef XP_UNIX
|
||||
/* The default registry on the unix system is $HOME/.mozilla/registry per
|
||||
* vr_findGlobalRegName(). vr_findRegFile() will create the registry file
|
||||
* if it doesn't exist. But it wont create directories.
|
||||
*
|
||||
* Hence we need to create the directory if it doesn't exist already.
|
||||
*
|
||||
* Why create it here as opposed to the app ?
|
||||
* ------------------------------------------
|
||||
* The app cannot create the directory in main() as most of the registry
|
||||
* and initialization happens due to use of static variables.
|
||||
* And we dont want to be dependent on the order in which
|
||||
* these static stuff happen.
|
||||
*
|
||||
* Permission for the $HOME/.mozilla will be Read,Write,Execute
|
||||
* for user only. Nothing to group and others.
|
||||
*/
|
||||
#define NS_MOZILLA_DIR_NAME ".mozilla"
|
||||
#define NS_MOZILLA_DIR_PERMISSION 00700
|
||||
#endif /* XP_UNIX */
|
||||
|
||||
/**
|
||||
* When using the registry we put a version number in it.
|
||||
* If the version number that is in the registry doesn't match
|
||||
* the following, we ignore the registry. This lets news versions
|
||||
* of the software deal with old formats of registry and not
|
||||
*
|
||||
* alpha0.20 : First time we did versioning
|
||||
* alpha0.30 : Changing autoreg to begin registration from ./components on unix
|
||||
* alpha0.40 : repository -> component manager
|
||||
* alpha0.50 : using nsIRegistry
|
||||
*/
|
||||
#define NS_XPCOM_COMPONENT_MANAGER_VERSION_STRING "alpha0.51"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Class: nsFactoryEntry()
|
||||
*
|
||||
* There are two types of FactoryEntries.
|
||||
*
|
||||
* 1. {CID, dll} mapping.
|
||||
* Factory is a consequence of the dll. These can be either session
|
||||
* specific or persistent based on whether we write this
|
||||
* to the registry or not.
|
||||
*
|
||||
* 2. {CID, factory} mapping
|
||||
* These are strictly session specific and in memory only.
|
||||
*/
|
||||
|
||||
class nsFactoryEntry {
|
||||
public:
|
||||
nsFactoryEntry();
|
||||
nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory);
|
||||
~nsFactoryEntry();
|
||||
|
||||
nsresult Init(nsHashtable* dllHashtable, const nsCID &aClass, const char *aLibrary,
|
||||
PRTime lastModTime, PRUint32 fileSize);
|
||||
|
||||
nsCID cid;
|
||||
nsIFactory *factory;
|
||||
|
||||
// DO NOT DELETE THIS. Many nsFactoryEntry(s) could be sharing the same Dll.
|
||||
// This gets deleted from the dllStore going away.
|
||||
nsDll *dll;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // nsComponentManager_h__
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
#include "nsGenericFactory.h"
|
||||
|
||||
nsGenericFactory::nsGenericFactory(ConstructorProcPtr constructor)
|
||||
: mConstructor(constructor), mDestructor(NULL)
|
||||
{
|
||||
NS_INIT_ISUPPORTS();
|
||||
}
|
||||
|
||||
nsGenericFactory::~nsGenericFactory()
|
||||
{
|
||||
if (mDestructor != NULL)
|
||||
(*mDestructor) ();
|
||||
}
|
||||
|
||||
NS_METHOD nsGenericFactory::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
if (aIID.Equals(nsIFactory::GetIID()) ||
|
||||
aIID.Equals(nsIGenericFactory::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = (void*) this;
|
||||
AddRef();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsGenericFactory)
|
||||
NS_IMPL_RELEASE(nsGenericFactory)
|
||||
|
||||
NS_IMETHODIMP nsGenericFactory::CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
return mConstructor(aOuter, aIID, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsGenericFactory::LockFactory(PRBool aLock)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsGenericFactory::SetConstructor(ConstructorProcPtr constructor)
|
||||
{
|
||||
mConstructor = constructor;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsGenericFactory::SetDestructor(DestructorProcPtr destructor)
|
||||
{
|
||||
mDestructor = destructor;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_METHOD nsGenericFactory::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
|
||||
{
|
||||
// sorry, aggregation not spoken here.
|
||||
nsresult res = NS_ERROR_NO_AGGREGATION;
|
||||
if (outer == NULL) {
|
||||
nsGenericFactory* factory = new nsGenericFactory;
|
||||
if (factory != NULL) {
|
||||
res = factory->QueryInterface(aIID, aInstancePtr);
|
||||
if (res != NS_OK)
|
||||
delete factory;
|
||||
} else {
|
||||
res = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1,60 +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 nsGenericFactory_h___
|
||||
#define nsGenericFactory_h___
|
||||
|
||||
#include "nsIGenericFactory.h"
|
||||
|
||||
/**
|
||||
* Most factories follow this simple pattern, so why not just use a function pointer
|
||||
* for most creation operations?
|
||||
*/
|
||||
class nsGenericFactory : public nsIGenericFactory {
|
||||
public:
|
||||
static const nsCID& CID() { static nsCID cid = NS_GENERICFACTORY_CID; return cid; }
|
||||
|
||||
nsGenericFactory(ConstructorProcPtr constructor = NULL);
|
||||
virtual ~nsGenericFactory();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD CreateInstance(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
NS_IMETHOD LockFactory(PRBool aLock);
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's constructor function, which will be called
|
||||
* by CreateInstance.
|
||||
*/
|
||||
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor);
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's destructor function, which will be called
|
||||
* whe the generic factory is deleted. This is used to notify the DLL that
|
||||
* an instance of one of its generic factories is going away.
|
||||
*/
|
||||
NS_IMETHOD SetDestructor(DestructorProcPtr destructor);
|
||||
|
||||
static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
|
||||
private:
|
||||
ConstructorProcPtr mConstructor;
|
||||
DestructorProcPtr mDestructor;
|
||||
};
|
||||
|
||||
#endif /* nsGenericFactory_h___ */
|
||||
@@ -1,258 +0,0 @@
|
||||
/* -*- 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 nsIComponentManager_h__
|
||||
#define nsIComponentManager_h__
|
||||
|
||||
#include "prtypes.h"
|
||||
#include "nsCom.h"
|
||||
#include "nsID.h"
|
||||
#include "nsError.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
|
||||
/*
|
||||
* Prototypes for dynamic library export functions. Your DLL/DSO needs to export
|
||||
* these methods to play in the component world.
|
||||
*/
|
||||
|
||||
extern "C" NS_EXPORT nsresult NSGetFactory(nsISupports* aServMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" NS_EXPORT PRBool NSCanUnload(nsISupports* aServMgr);
|
||||
extern "C" NS_EXPORT nsresult NSRegisterSelf(nsISupports* aServMgr, const char *fullpath);
|
||||
extern "C" NS_EXPORT nsresult NSUnregisterSelf(nsISupports* aServMgr, const char *fullpath);
|
||||
|
||||
typedef nsresult (*nsFactoryProc)(nsISupports* aServMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
typedef PRBool (*nsCanUnloadProc)(nsISupports* aServMgr);
|
||||
typedef nsresult (*nsRegisterProc)(nsISupports* aServMgr, const char *path);
|
||||
typedef nsresult (*nsUnregisterProc)(nsISupports* aServMgr, const char *path);
|
||||
|
||||
#define NS_ICOMPONENTMANAGER_IID \
|
||||
{ /* 8458a740-d5dc-11d2-92fb-00e09805570f */ \
|
||||
0x8458a740, \
|
||||
0xd5dc, \
|
||||
0x11d2, \
|
||||
{0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \
|
||||
}
|
||||
|
||||
#define NS_COMPONENTMANAGER_CID \
|
||||
{ /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \
|
||||
0x91775d60, \
|
||||
0xd5dc, \
|
||||
0x11d2, \
|
||||
{0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \
|
||||
}
|
||||
|
||||
/*
|
||||
* nsIComponentManager interface
|
||||
*/
|
||||
|
||||
class nsIComponentManager : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ICOMPONENTMANAGER_IID)
|
||||
|
||||
NS_IMETHOD FindFactory(const nsCID &aClass,
|
||||
nsIFactory **aFactory) = 0;
|
||||
|
||||
// Finds a class ID for a specific Program ID
|
||||
NS_IMETHOD ProgIDToCLSID(const char *aProgID,
|
||||
nsCID *aClass) = 0;
|
||||
|
||||
// Finds a Program ID for a specific class ID
|
||||
// caller frees the result with delete[]
|
||||
NS_IMETHOD CLSIDToProgID(nsCID *aClass,
|
||||
char* *aClassName,
|
||||
char* *aProgID) = 0;
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
NS_IMETHOD CreateInstance(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult) = 0;
|
||||
|
||||
// Convenience routine, creates a class instance for a specific ProgID
|
||||
NS_IMETHOD CreateInstance(const char *aProgID,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult) = 0;
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
/*
|
||||
NS_IMETHOD CreateInstance2(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void *aSignature,
|
||||
void **aResult) = 0;
|
||||
*/
|
||||
|
||||
// Manually registry a factory for a class
|
||||
NS_IMETHOD RegisterFactory(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory *aFactory,
|
||||
PRBool aReplace) = 0;
|
||||
|
||||
// Manually register a dynamically loaded component.
|
||||
NS_IMETHOD RegisterComponent(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
const char *aLibrary,
|
||||
PRBool aReplace,
|
||||
PRBool aPersist) = 0;
|
||||
|
||||
// Manually unregister a factory for a class
|
||||
NS_IMETHOD UnregisterFactory(const nsCID &aClass,
|
||||
nsIFactory *aFactory) = 0;
|
||||
|
||||
// Manually unregister a dynamically loaded factory for a class
|
||||
NS_IMETHOD UnregisterFactory(const nsCID &aClass,
|
||||
const char *aLibrary) = 0;
|
||||
|
||||
// Manually unregister a dynamically loaded component
|
||||
NS_IMETHOD UnregisterComponent(const nsCID &aClass,
|
||||
const char *aLibrary) = 0;
|
||||
|
||||
// Unload dynamically loaded factories that are not in use
|
||||
NS_IMETHOD FreeLibraries(void) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// DLL registration support
|
||||
/* 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
|
||||
*/
|
||||
enum RegistrationTime {
|
||||
NS_Startup = 0,
|
||||
NS_Script = 1,
|
||||
NS_Timer = 2
|
||||
};
|
||||
|
||||
NS_IMETHOD AutoRegister(RegistrationTime when, const char* pathlist) = 0;
|
||||
// Pathlist is a semicolon separated list of pathnames
|
||||
NS_IMETHOD AddToDefaultPathList(const char *pathlist) = 0;
|
||||
NS_IMETHOD SyncComponentsInPathList(const char *pathlist) = 0;
|
||||
NS_IMETHOD SyncComponentsInDir(const char *path) = 0;
|
||||
NS_IMETHOD SyncComponentsInFile(const char *fullname) = 0;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_GetGlobalComponentManager(nsIComponentManager* *result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global Static Component Manager Methods
|
||||
// (for when you need to link with xpcom)
|
||||
|
||||
class NS_COM nsComponentManager {
|
||||
public:
|
||||
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);
|
||||
|
||||
// Finds a Program ID for a specific class ID
|
||||
// caller frees the result with delete[]
|
||||
static nsresult CLSIDToProgID(nsCID *aClass,
|
||||
char* *aClassName,
|
||||
char* *aProgID);
|
||||
|
||||
// Creates a class instance for a specific class ID
|
||||
static nsresult CreateInstance(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult);
|
||||
|
||||
// Convenience routine, creates a class instance for a specific ProgID
|
||||
static nsresult CreateInstance(const char *aProgID,
|
||||
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,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory *aFactory,
|
||||
PRBool aReplace);
|
||||
|
||||
// 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(nsIComponentManager::RegistrationTime 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
|
||||
@@ -1,68 +0,0 @@
|
||||
/* -*- 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"
|
||||
|
||||
/*
|
||||
* 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& GetIID() { 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& GetIID() { static nsIID iid = NS_IFACTORY2_IID; return iid; }
|
||||
|
||||
NS_IMETHOD CreateInstance2(nsISupports *aOuter,
|
||||
REFNSIID aIID,
|
||||
void *aSignature,
|
||||
void **aResult) = 0;
|
||||
};
|
||||
#endif /* 0 */
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/* -*- Mode: IDL; 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 "nsISupports.idl"
|
||||
%{ C++
|
||||
#include "nsCID.h"
|
||||
%}
|
||||
|
||||
[object, uuid(19997C41-A343-11d1-B665-00805F8A2676)]
|
||||
interface nsIFactory : nsISupports {
|
||||
|
||||
voidStar CreateInstance(in nsISupports aOuter,
|
||||
in nsIID iid);
|
||||
|
||||
void LockFactory(in boolean lock);
|
||||
|
||||
};
|
||||
|
||||
@@ -1,57 +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 nsIGenericFactory_h___
|
||||
#define nsIGenericFactory_h___
|
||||
|
||||
#include "nsIFactory.h"
|
||||
|
||||
// {3bc97f01-ccdf-11d2-bab8-b548654461fc}
|
||||
#define NS_GENERICFACTORY_CID \
|
||||
{ 0x3bc97f01, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
|
||||
|
||||
// {3bc97f00-ccdf-11d2-bab8-b548654461fc}
|
||||
#define NS_IGENERICFACTORY_IID \
|
||||
{ 0x3bc97f00, 0xccdf, 0x11d2, { 0xba, 0xb8, 0xb5, 0x48, 0x65, 0x44, 0x61, 0xfc } }
|
||||
|
||||
/**
|
||||
* Provides a Generic nsIFactory implementation that can be used by
|
||||
* DLLs with very simple factory needs.
|
||||
*/
|
||||
class nsIGenericFactory : public nsIFactory {
|
||||
public:
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IGENERICFACTORY_IID; return iid; }
|
||||
|
||||
typedef NS_CALLBACK(ConstructorProcPtr) (nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
typedef NS_CALLBACK(DestructorProcPtr) (void);
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's constructor function, which will be called
|
||||
* by CreateInstance.
|
||||
*/
|
||||
NS_IMETHOD SetConstructor(ConstructorProcPtr constructor) = 0;
|
||||
|
||||
/**
|
||||
* Establishes the generic factory's destructor function, which will be called
|
||||
* whe the generic factory is deleted. This is used to notify the DLL that
|
||||
* an instance of one of its generic factories is going away.
|
||||
*/
|
||||
NS_IMETHOD SetDestructor(DestructorProcPtr destructor) = 0;
|
||||
};
|
||||
|
||||
#endif /* nsIGenericFactory_h___ */
|
||||
@@ -1,350 +0,0 @@
|
||||
/* -*- 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"
|
||||
|
||||
// {5D41A440-8E37-11d2-8059-00600811A9C3}
|
||||
#define NS_IREGISTRY_IID { 0x5d41a440, 0x8e37, 0x11d2, { 0x80, 0x59, 0x0, 0x60, 0x8, 0x11, 0xa9, 0xc3 } }
|
||||
#define NS_REGISTRY_PROGID "component://netscape/registry"
|
||||
#define NS_REGISTRY_CLASSNAME "Mozilla Registry"
|
||||
|
||||
// {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 } }
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
static const nsIID& GetIID() { static nsIID iid = NS_IREGISTRY_IID; return iid; }
|
||||
|
||||
/*--------------------------- 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). |
|
||||
| AddSubtreeRaw - 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). |
|
||||
| Does not interpret special chars in key names. |
|
||||
| |
|
||||
| RemoveSubtree - Removes the specified registry subtree or |
|
||||
| value at the specified location. |
|
||||
| RemoveSubtreeRaw - Removes the specified registry subtree or |
|
||||
| value at the specified location. |
|
||||
| Does not interpret special chars in key names. |
|
||||
| |
|
||||
| GetSubtree - Returns a nsIRegistry::Key that can be used |
|
||||
| to refer to the specified registry location. |
|
||||
| GetSubtreeRaw - Returns a nsIRegistry::Key that can be used |
|
||||
| to refer to the specified registry location. |
|
||||
| Does not interpret special chars in key names. |
|
||||
| |
|
||||
| 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 AddSubtreeRaw( Key baseKey, const char *keyname, Key *result ) = 0;
|
||||
NS_IMETHOD RemoveSubtreeRaw( Key baseKey, const char *keyname ) = 0;
|
||||
NS_IMETHOD GetSubtreeRaw( Key baseKey, const char *keyname, 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 )
|
||||
|
||||
#endif
|
||||
@@ -1,361 +0,0 @@
|
||||
/* -*- 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 nsIServiceManager_h___
|
||||
#define nsIServiceManager_h___
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsID.h"
|
||||
|
||||
class nsIShutdownListener;
|
||||
|
||||
#define NS_ISERVICEMANAGER_IID \
|
||||
{ /* cf0df3b0-3401-11d2-8163-006008119d7a */ \
|
||||
0xcf0df3b0, \
|
||||
0x3401, \
|
||||
0x11d2, \
|
||||
{0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_DEFINE_STATIC_IID_ACCESSOR(NS_ISERVICEMANAGER_IID);
|
||||
|
||||
/**
|
||||
* RegisterService may be called explicitly to register a service
|
||||
* with the service manager. If a service is not registered explicitly,
|
||||
* the component manager will be used to create an instance according
|
||||
* to the class ID specified.
|
||||
*/
|
||||
NS_IMETHOD
|
||||
RegisterService(const nsCID& aClass, nsISupports* aService) = 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
|
||||
UnregisterService(const nsCID& aClass) = 0;
|
||||
|
||||
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;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// let's do it again, this time with ProgIDs...
|
||||
|
||||
NS_IMETHOD
|
||||
RegisterService(const char* aProgID, nsISupports* aService) = 0;
|
||||
|
||||
NS_IMETHOD
|
||||
UnregisterService(const char* aProgID) = 0;
|
||||
|
||||
NS_IMETHOD
|
||||
GetService(const char* aProgID, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener = NULL) = 0;
|
||||
|
||||
NS_IMETHOD
|
||||
ReleaseService(const char* aProgID, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener = NULL) = 0;
|
||||
|
||||
};
|
||||
|
||||
#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)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NS_ISHUTDOWNLISTENER_IID \
|
||||
{ /* 56decae0-3406-11d2-8163-006008119d7a */ \
|
||||
0x56decae0, \
|
||||
0x3406, \
|
||||
0x11d2, \
|
||||
{0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \
|
||||
}
|
||||
|
||||
class nsIShutdownListener : public nsISupports {
|
||||
public:
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISHUTDOWNLISTENER_IID);
|
||||
|
||||
NS_IMETHOD
|
||||
OnShutdown(const nsCID& aClass, nsISupports* service) = 0;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface to Global Services
|
||||
|
||||
class NS_COM nsServiceManager {
|
||||
public:
|
||||
|
||||
static nsresult RegisterService(const nsCID& aClass, nsISupports* aService);
|
||||
|
||||
static nsresult UnregisterService(const nsCID& aClass);
|
||||
|
||||
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);
|
||||
|
||||
// Since the global Service Manager is truly global, there's no need to
|
||||
// release it.
|
||||
static nsresult GetGlobalServiceManager(nsIServiceManager* *result);
|
||||
|
||||
// This method can be called when shutting down the application. It
|
||||
// releases all the global services, and deletes the global service manager.
|
||||
static nsresult ShutdownGlobalServiceManager(nsIServiceManager* *result);
|
||||
|
||||
static nsIServiceManager* mGlobalServiceManager;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsService: Template to make using services easier. Now you can replace this:
|
||||
//
|
||||
// nsIMyService* service;
|
||||
// rv = nsServiceManager::GetService(cid, iid, &service);
|
||||
// if (NS_SUCCEEDED(rv)) {
|
||||
// service->Doit(...); // use my service
|
||||
// rv = nsServiceManager::ReleaseService(cid, service);
|
||||
// }
|
||||
//
|
||||
// with this:
|
||||
//
|
||||
// nsService<nsIMyService> service(cid, &rv);
|
||||
// if (NS_SUCCEEDED(rv)) {
|
||||
// service->Doit(...); // use my service
|
||||
// }
|
||||
//
|
||||
// and the automatic destructor will take care of releasing the service.
|
||||
|
||||
#if 0 // sorry the T::GetIID() construct doesn't work with egcs
|
||||
|
||||
template<class T> class nsService {
|
||||
protected:
|
||||
nsCID mCID;
|
||||
T* mService;
|
||||
|
||||
public:
|
||||
nsService(nsISupports* aServMgr, const nsCID& aClass, nsresult *rv)
|
||||
: mCID(aClass), mService(0)
|
||||
{
|
||||
nsIServiceManager* servMgr;
|
||||
*rv = aServMgr->QueryInterface(nsIServiceManager::GetIID(), (void**)&servMgr);
|
||||
if (NS_SUCCEEDED(*rv)) {
|
||||
*rv = servMgr->GetService(mCID, T::GetIID(), (nsISupports**)&mService);
|
||||
NS_RELEASE(servMgr);
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get service.");
|
||||
}
|
||||
|
||||
nsService(nsISupports* aServMgr, const char* aProgID, nsresult *rv)
|
||||
: mService(0)
|
||||
{
|
||||
*rv = nsComponentManager::ProgIDToCLSID(aProgID, &mCID);
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get CLSID.");
|
||||
if (NS_FAILED(*rv)) return;
|
||||
|
||||
nsIServiceManager* servMgr;
|
||||
*rv = aServMgr->QueryInterface(nsIServiceManager::GetIID(), (void**)&servMgr);
|
||||
if (NS_SUCCEEDED(*rv)) {
|
||||
*rv = servMgr->GetService(mCID, T::GetIID(), (nsISupports**)&mService);
|
||||
NS_RELEASE(servMgr);
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get service.");
|
||||
}
|
||||
|
||||
nsService(const nsCID& aClass, nsresult *rv)
|
||||
: mCID(aClass), mService(0) {
|
||||
*rv = nsServiceManager::GetService(aClass, T::GetIID(),
|
||||
(nsISupports**)&mService);
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get service.");
|
||||
}
|
||||
|
||||
~nsService() {
|
||||
if (mService) { // mService could be null if the constructor fails
|
||||
nsresult rv = nsServiceManager::ReleaseService(mCID, mService);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't release service.");
|
||||
}
|
||||
}
|
||||
|
||||
T* operator->() const {
|
||||
NS_PRECONDITION(mService != 0, "Your code should test the error result from the constructor.");
|
||||
return mService;
|
||||
}
|
||||
|
||||
PRBool operator==(const T* other) {
|
||||
return mService == other;
|
||||
}
|
||||
|
||||
operator T*() const {
|
||||
return mService;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class nsService {
|
||||
protected:
|
||||
nsCID mCID;
|
||||
nsISupports* mService;
|
||||
|
||||
public:
|
||||
nsService(nsISupports* aServMgr, const nsCID& aClass, const nsIID& aIID, nsresult *rv)
|
||||
: mCID(aClass), mService(0)
|
||||
{
|
||||
nsIServiceManager* servMgr;
|
||||
*rv = aServMgr->QueryInterface(nsIServiceManager::GetIID(), (void**)&servMgr);
|
||||
if (NS_SUCCEEDED(*rv)) {
|
||||
*rv = servMgr->GetService(mCID, aIID, &mService);
|
||||
NS_RELEASE(servMgr);
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get service.");
|
||||
}
|
||||
|
||||
nsService(nsISupports* aServMgr, const char* aProgID, const nsIID& aIID, nsresult *rv)
|
||||
: mService(0)
|
||||
{
|
||||
*rv = nsComponentManager::ProgIDToCLSID(aProgID, &mCID);
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get CLSID.");
|
||||
if (NS_FAILED(*rv)) return;
|
||||
|
||||
nsIServiceManager* servMgr;
|
||||
*rv = aServMgr->QueryInterface(nsIServiceManager::GetIID(), (void**)&servMgr);
|
||||
if (NS_SUCCEEDED(*rv)) {
|
||||
*rv = servMgr->GetService(mCID, aIID, &mService);
|
||||
NS_RELEASE(servMgr);
|
||||
}
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get service.");
|
||||
}
|
||||
|
||||
nsService(const nsCID& aClass, const nsIID& aIID, nsresult *rv)
|
||||
: mCID(aClass), mService(0) {
|
||||
*rv = nsServiceManager::GetService(aClass, aIID,
|
||||
(nsISupports**)&mService);
|
||||
NS_ASSERTION(NS_SUCCEEDED(*rv), "Couldn't get service.");
|
||||
}
|
||||
|
||||
~nsService() {
|
||||
if (mService) { // mService could be null if the constructor fails
|
||||
nsresult rv = NS_OK;
|
||||
rv = nsServiceManager::ReleaseService(mCID, mService);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Couldn't release service.");
|
||||
}
|
||||
}
|
||||
|
||||
nsISupports* operator->() const {
|
||||
NS_PRECONDITION(mService != 0, "Your code should test the error result from the constructor.");
|
||||
return mService;
|
||||
}
|
||||
|
||||
PRBool operator==(const nsISupports* other) {
|
||||
return mService == other;
|
||||
}
|
||||
|
||||
operator nsISupports*() const {
|
||||
return mService;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define NS_WITH_SERVICE(T, var, cid, rvAddr) \
|
||||
nsService _serv##var(cid, T::GetIID(), rvAddr); \
|
||||
T* var = (T*)(nsISupports*)_serv##var;
|
||||
|
||||
#define NS_WITH_SERVICE1(T, var, isupports, cid, rvAddr) \
|
||||
nsService _serv##var(isupports, cid, T::GetIID(), rvAddr); \
|
||||
T* var = (T*)(nsISupports*)_serv##var;
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NS_NewServiceManager: For when you want to create a service manager
|
||||
// in a given context.
|
||||
|
||||
extern NS_COM nsresult
|
||||
NS_NewServiceManager(nsIServiceManager* *result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization of XPCOM. Creates the global ComponentManager, ServiceManager
|
||||
// and registers xpcom components with the ComponentManager. Should be called
|
||||
// before any call can be made to XPCOM. Currently we are coping with this
|
||||
// not being called and internally initializing XPCOM if not already.
|
||||
extern NS_COM nsresult
|
||||
NS_InitXPCOM(nsIServiceManager* *result);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* nsIServiceManager_h___ */
|
||||
@@ -1,164 +0,0 @@
|
||||
/* -*- 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(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_GFXWIN_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_VIEW_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_WEB_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
#if 0
|
||||
extern "C" nsresult NSGetFactory_PLUGIN_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
#endif
|
||||
extern "C" nsresult NSGetFactory_PREF_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_PARSER_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_DOM_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_LAYOUT_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_NETLIB_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
extern "C" nsresult NSGetFactory_EDITOR_DLL(nsISupports* serviceMgr,
|
||||
const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory **aFactory);
|
||||
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,194 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; 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 "nsIComponentManager.h"
|
||||
|
||||
nsresult
|
||||
nsComponentManager::Initialize(void)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::FindFactory(const nsCID &aClass,
|
||||
nsIFactory **aFactory)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->FindFactory(aClass, aFactory);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::ProgIDToCLSID(const char *aProgID,
|
||||
nsCID *aClass)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->ProgIDToCLSID(aProgID, aClass);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::CLSIDToProgID(nsCID *aClass,
|
||||
char* *aClassName,
|
||||
char* *aProgID)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->CLSIDToProgID(aClass, aClassName, aProgID);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::CreateInstance(const nsCID &aClass,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->CreateInstance(aClass, aDelegate, aIID, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::CreateInstance(const char *aProgID,
|
||||
nsISupports *aDelegate,
|
||||
const nsIID &aIID,
|
||||
void **aResult)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->CreateInstance(aProgID, aDelegate, aIID, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::RegisterFactory(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
nsIFactory *aFactory,
|
||||
PRBool aReplace)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->RegisterFactory(aClass, aClassName, aProgID,
|
||||
aFactory, aReplace);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::RegisterComponent(const nsCID &aClass,
|
||||
const char *aClassName,
|
||||
const char *aProgID,
|
||||
const char *aLibrary,
|
||||
PRBool aReplace,
|
||||
PRBool aPersist)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->RegisterComponent(aClass, aClassName, aProgID,
|
||||
aLibrary, aReplace, aPersist);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::UnregisterFactory(const nsCID &aClass,
|
||||
nsIFactory *aFactory)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->UnregisterFactory(aClass, aFactory);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::UnregisterFactory(const nsCID &aClass,
|
||||
const char *aLibrary)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->UnregisterFactory(aClass, aLibrary);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::UnregisterComponent(const nsCID &aClass,
|
||||
const char *aLibrary)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->UnregisterComponent(aClass, aLibrary);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::FreeLibraries(void)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->FreeLibraries();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::AutoRegister(nsIComponentManager::RegistrationTime when,
|
||||
const char* pathlist)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->AutoRegister(when, pathlist);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::AddToDefaultPathList(const char *pathlist)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->AddToDefaultPathList(pathlist);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::SyncComponentsInPathList(const char *pathlist)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->SyncComponentsInPathList(pathlist);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::SyncComponentsInDir(const char *path)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->SyncComponentsInDir(path);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsComponentManager::SyncComponentsInFile(const char *fullname)
|
||||
{
|
||||
nsIComponentManager* cm;
|
||||
nsresult rv = NS_GetGlobalComponentManager(&cm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return cm->SyncComponentsInFile(fullname);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* -*- 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 "nsIComponentManager.h"
|
||||
|
||||
// XXX nsRepository is obsolete! Use nsComponentManager now!
|
||||
|
||||
#define nsRepository nsComponentManager
|
||||
|
||||
#endif
|
||||
@@ -1,560 +0,0 @@
|
||||
/* -*- 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 "nsHashtable.h"
|
||||
#include "prcmon.h"
|
||||
#include "prthread.h" /* XXX: only used for the NSPR initialization hack (rick) */
|
||||
|
||||
static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
|
||||
|
||||
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];
|
||||
NS_RELEASE(listener);
|
||||
}
|
||||
#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 rv = mListeners->Add(listener);
|
||||
NS_ADDREF(listener);
|
||||
return rv == -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);
|
||||
NS_RELEASE(listener);
|
||||
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 rv = listener->OnShutdown(mClassID, mService);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_RELEASE(listener);
|
||||
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
|
||||
RegisterService(const nsCID& aClass, nsISupports* aService);
|
||||
|
||||
NS_IMETHOD
|
||||
UnregisterService(const nsCID& aClass);
|
||||
|
||||
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
|
||||
RegisterService(const char* aProgID, nsISupports* aService);
|
||||
|
||||
NS_IMETHOD
|
||||
UnregisterService(const char* aProgID);
|
||||
|
||||
NS_IMETHOD
|
||||
GetService(const char* aProgID, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener = NULL);
|
||||
|
||||
NS_IMETHOD
|
||||
ReleaseService(const char* aProgID, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener = NULL);
|
||||
|
||||
nsServiceManagerImpl(void);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~nsServiceManagerImpl(void);
|
||||
|
||||
nsHashtable/*<nsServiceEntry>*/* mServices;
|
||||
};
|
||||
|
||||
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;
|
||||
NS_RELEASE(entry->mService);
|
||||
delete entry;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsServiceManagerImpl::~nsServiceManagerImpl(void)
|
||||
{
|
||||
if (mServices) {
|
||||
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);
|
||||
|
||||
NS_IMETHODIMP
|
||||
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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsresult rv = 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;
|
||||
rv = entry->mService->QueryInterface(aIID, (void**)&service);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = entry->AddListener(shutdownListener);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*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;
|
||||
NS_ADDREF(service); // Released in UnregisterService
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
nsISupports* service;
|
||||
rv = nsComponentManager::CreateInstance(aClass, NULL, aIID, (void**)&service);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
entry = new nsServiceEntry(aClass, service);
|
||||
if (entry == NULL) {
|
||||
NS_RELEASE(service);
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
rv = entry->AddListener(shutdownListener);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mServices->Put(&key, entry);
|
||||
*result = service;
|
||||
NS_ADDREF(service); // Released in UnregisterService
|
||||
}
|
||||
else {
|
||||
NS_RELEASE(service);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsresult rv = 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) {
|
||||
rv = entry->RemoveListener(shutdownListener);
|
||||
nsrefcnt cnt;
|
||||
NS_RELEASE2(service, cnt);
|
||||
if (NS_SUCCEEDED(rv) && cnt == 0) {
|
||||
mServices->Remove(&key);
|
||||
delete entry;
|
||||
rv = nsComponentManager::FreeLibraries();
|
||||
}
|
||||
}
|
||||
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
PR_CEnterMonitor(this);
|
||||
|
||||
nsIDKey key(aClass);
|
||||
nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key);
|
||||
if (entry) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
else {
|
||||
nsServiceEntry* entry = new nsServiceEntry(aClass, aService);
|
||||
if (entry == NULL)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else {
|
||||
mServices->Put(&key, entry);
|
||||
NS_ADDREF(aService); // Released in UnregisterService
|
||||
}
|
||||
}
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::UnregisterService(const nsCID& aClass)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
PR_CEnterMonitor(this);
|
||||
|
||||
nsIDKey key(aClass);
|
||||
nsServiceEntry* entry = (nsServiceEntry*)mServices->Get(&key);
|
||||
|
||||
if (entry == NULL) {
|
||||
rv = NS_ERROR_SERVICE_NOT_FOUND;
|
||||
}
|
||||
else {
|
||||
rv = entry->NotifyListeners(); // break the cycles
|
||||
entry->mShuttingDown = PR_TRUE;
|
||||
nsrefcnt cnt;
|
||||
NS_RELEASE2(entry->mService, cnt); // AddRef in GetService
|
||||
if (NS_SUCCEEDED(rv) && cnt == 0) {
|
||||
mServices->Remove(&key);
|
||||
delete entry;
|
||||
rv = nsComponentManager::FreeLibraries();
|
||||
}
|
||||
else
|
||||
rv = NS_ERROR_SERVICE_IN_USE;
|
||||
}
|
||||
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// let's do it again, this time with ProgIDs...
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::RegisterService(const char* aProgID, nsISupports* aService)
|
||||
{
|
||||
nsCID aClass;
|
||||
nsresult rv;
|
||||
rv = nsComponentManager::ProgIDToCLSID(aProgID, &aClass);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return RegisterService(aClass, aService);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::UnregisterService(const char* aProgID)
|
||||
{
|
||||
nsCID aClass;
|
||||
nsresult rv;
|
||||
rv = nsComponentManager::ProgIDToCLSID(aProgID, &aClass);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return UnregisterService(aClass);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::GetService(const char* aProgID, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsCID aClass;
|
||||
nsresult rv;
|
||||
rv = nsComponentManager::ProgIDToCLSID(aProgID, &aClass);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return GetService(aClass, aIID, result, shutdownListener);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsServiceManagerImpl::ReleaseService(const char* aProgID, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsCID aClass;
|
||||
nsresult rv;
|
||||
rv = nsComponentManager::ProgIDToCLSID(aProgID, &aClass);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return ReleaseService(aClass, service, shutdownListener);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsresult
|
||||
NS_NewServiceManager(nsIServiceManager* *result)
|
||||
{
|
||||
nsServiceManagerImpl* servMgr = new nsServiceManagerImpl();
|
||||
if (servMgr == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(servMgr);
|
||||
*result = servMgr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global service manager interface (see nsIServiceManager.h)
|
||||
|
||||
nsresult
|
||||
nsServiceManager::GetGlobalServiceManager(nsIServiceManager* *result)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (mGlobalServiceManager == NULL) {
|
||||
// XPCOM not initialized yet. Let us do initialization of our module.
|
||||
rv = NS_InitXPCOM(NULL);
|
||||
}
|
||||
// No ADDREF as we are advicing no release of this.
|
||||
if (NS_SUCCEEDED(rv)) *result = mGlobalServiceManager;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::ShutdownGlobalServiceManager(nsIServiceManager* *result)
|
||||
{
|
||||
if (mGlobalServiceManager != NULL) {
|
||||
NS_RELEASE(mGlobalServiceManager);
|
||||
mGlobalServiceManager = NULL;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::GetService(const nsCID& aClass, const nsIID& aIID,
|
||||
nsISupports* *result,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rv = GetGlobalServiceManager(&mgr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mgr->GetService(aClass, aIID, result, shutdownListener);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::ReleaseService(const nsCID& aClass, nsISupports* service,
|
||||
nsIShutdownListener* shutdownListener)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rv = GetGlobalServiceManager(&mgr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mgr->ReleaseService(aClass, service, shutdownListener);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::RegisterService(const nsCID& aClass, nsISupports* aService)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rv = GetGlobalServiceManager(&mgr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mgr->RegisterService(aClass, aService);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsServiceManager::UnregisterService(const nsCID& aClass)
|
||||
{
|
||||
nsIServiceManager* mgr;
|
||||
nsresult rv = GetGlobalServiceManager(&mgr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return mgr->UnregisterService(aClass);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// XPCOM initialization
|
||||
//
|
||||
// To Control the order of initialization of these key components I am putting
|
||||
// this function.
|
||||
//
|
||||
// - nsServiceManager
|
||||
// - nsComponentManager
|
||||
// - nsRegistry
|
||||
//
|
||||
// Here are key points to remember:
|
||||
// - A global of all these need to exist. nsServiceManager is an independent object.
|
||||
// nsComponentManager uses both the globalServiceManager and its own registry.
|
||||
//
|
||||
// - A static object of both the nsComponentManager and nsServiceManager
|
||||
// are in use. Hence InitXPCOM() gets triggered from both
|
||||
// NS_GetGlobale{Service/Component}Manager() calls.
|
||||
//
|
||||
// - There exists no global Registry. Registry can be created from the component manager.
|
||||
//
|
||||
#include "nsComponentManager.h"
|
||||
#include "nsIRegistry.h"
|
||||
#include "nsXPComCIID.h"
|
||||
extern "C" NS_EXPORT nsresult
|
||||
NS_RegistryGetFactory(nsISupports* servMgr, nsIFactory** aFactory);
|
||||
|
||||
nsIServiceManager* nsServiceManager::mGlobalServiceManager = NULL;
|
||||
nsComponentManagerImpl* nsComponentManagerImpl::gComponentManager = NULL;
|
||||
|
||||
nsresult NS_InitXPCOM(nsIServiceManager* *result)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// 1. Create the Global Service Manager
|
||||
nsIServiceManager* servMgr = NULL;
|
||||
if (nsServiceManager::mGlobalServiceManager == NULL)
|
||||
{
|
||||
rv = NS_NewServiceManager(&servMgr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsServiceManager::mGlobalServiceManager = servMgr;
|
||||
NS_ADDREF(servMgr);
|
||||
if (result && *result) *result = servMgr;
|
||||
}
|
||||
|
||||
// 2. Create the Component Manager and register with global service manager
|
||||
// It is understood that the component manager can use the global service manager.
|
||||
nsComponentManagerImpl *compMgr = NULL;
|
||||
if (nsComponentManagerImpl::gComponentManager == NULL)
|
||||
{
|
||||
compMgr = new nsComponentManagerImpl();
|
||||
if (compMgr == NULL)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(compMgr);
|
||||
nsresult rv = compMgr->Init();
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
NS_RELEASE(compMgr);
|
||||
return rv;
|
||||
}
|
||||
nsComponentManagerImpl::gComponentManager = compMgr;
|
||||
}
|
||||
|
||||
rv = servMgr->RegisterService(kComponentManagerCID, compMgr);
|
||||
if (NS_FAILED(rv))
|
||||
{
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// 3. Register the RegistryFactory with the component manager so that
|
||||
// clients can create new registry objects.
|
||||
nsIFactory *registryFactory = NULL;
|
||||
rv = NS_RegistryGetFactory(servMgr, ®istryFactory);
|
||||
if (NS_FAILED(rv)) return (rv);
|
||||
|
||||
NS_DEFINE_CID(kRegistryCID, NS_REGISTRY_CID);
|
||||
|
||||
rv = compMgr->RegisterFactory(kRegistryCID, NS_REGISTRY_CLASSNAME,
|
||||
NS_REGISTRY_PROGID, registryFactory,
|
||||
PR_TRUE);
|
||||
NS_RELEASE(registryFactory);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/* -*- 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 macro for the implementation of a simple XPCOM factory.
|
||||
*
|
||||
* To implement a factory for a given component, you need to declare the
|
||||
* factory class using the NS_DEF_FACTORY() macro.
|
||||
*
|
||||
* The first macro argument is the name for the factory.
|
||||
*
|
||||
* The second macro argument is a function (provided by you) which
|
||||
* can be called by your DLL's NSGetFactory(...) entry point.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* NS_DEF_FACTORY(SomeComponent,SomeComponentImpl)
|
||||
*
|
||||
* Declares:
|
||||
*
|
||||
* class nsSomeComponentFactory : public nsIFactory {};
|
||||
*
|
||||
* NOTE that the NS_DEF_FACTORY takes care of enforcing the "ns" prefix
|
||||
* and appending the "Factory" suffix to the given name.
|
||||
*
|
||||
* To use the new factory:
|
||||
*
|
||||
* nsresult NS_New_SomeComponent_Factory(nsIFactory** aResult)
|
||||
* {
|
||||
* nsresult rv = NS_OK;
|
||||
* nsIFactory* inst = new nsSomeComponentFactory;
|
||||
* if (NULL == inst) {
|
||||
* rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
* } else {
|
||||
* NS_ADDREF(inst);
|
||||
* }
|
||||
* *aResult = inst;
|
||||
* return rv;
|
||||
* }
|
||||
*
|
||||
* NOTE:
|
||||
* ----
|
||||
* The factories created by this macro are not thread-safe and do not
|
||||
* support aggregation.
|
||||
*
|
||||
*/
|
||||
#define NS_DEF_FACTORY(_name,_type) \
|
||||
class ns##_name##Factory : public nsIFactory \
|
||||
{ \
|
||||
public: \
|
||||
ns##_name##Factory() { NS_INIT_REFCNT(); } \
|
||||
\
|
||||
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; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHOD CreateInstance(nsISupports *aOuter, \
|
||||
const nsIID &aIID, \
|
||||
void **aResult) \
|
||||
{ \
|
||||
nsresult rv; \
|
||||
\
|
||||
_type * inst; \
|
||||
\
|
||||
if (NULL == aResult) { \
|
||||
rv = NS_ERROR_NULL_POINTER; \
|
||||
goto done; \
|
||||
} \
|
||||
*aResult = NULL; \
|
||||
if (NULL != aOuter) { \
|
||||
rv = NS_ERROR_NO_AGGREGATION; \
|
||||
goto done; \
|
||||
} \
|
||||
\
|
||||
NS_NEWXPCOM(inst, _type); \
|
||||
if (NULL == inst) { \
|
||||
rv = NS_ERROR_OUT_OF_MEMORY; \
|
||||
goto done; \
|
||||
} \
|
||||
NS_ADDREF(inst); \
|
||||
rv = inst->QueryInterface(aIID, aResult); \
|
||||
NS_RELEASE(inst); \
|
||||
\
|
||||
done: \
|
||||
return rv; \
|
||||
} \
|
||||
\
|
||||
NS_IMETHOD LockFactory(PRBool aLock) \
|
||||
{ \
|
||||
return NS_OK; \
|
||||
} \
|
||||
\
|
||||
\
|
||||
protected: \
|
||||
virtual ~ns##_name##Factory() \
|
||||
{ \
|
||||
NS_ASSERTION(mRefCnt == 0, "non-zero refcnt at destruction"); \
|
||||
} \
|
||||
\
|
||||
nsrefcnt mRefCnt; \
|
||||
};
|
||||
|
||||
#endif /* nsXPComFactory_h__ */
|
||||
@@ -1,171 +0,0 @@
|
||||
/* -*- 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)
|
||||
{
|
||||
#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
|
||||
// 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));
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/* -*- 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); }
|
||||
};
|
||||
@@ -1,88 +0,0 @@
|
||||
/* -*- 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 IS OBSOLETE */
|
||||
|
||||
/* 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,49 +0,0 @@
|
||||
/* -*- 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 "plhash.h"
|
||||
#include "xcDll.h"
|
||||
|
||||
class nsDllStore
|
||||
{
|
||||
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);
|
||||
};
|
||||
@@ -1,117 +0,0 @@
|
||||
<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>
|
||||
@@ -1,169 +0,0 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.51 [en] (X11; U; Linux 2.0.36 i686) [Netscape]">
|
||||
<meta name="Author" content="Suresh Duddi">
|
||||
<title>TODO List for XPCOM</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<h1>
|
||||
TODO List for XPCOM</h1></center>
|
||||
|
||||
<center>Last updated: 25 March 1999
|
||||
<br><a href="mailto:dp@netscape.com">Suresh Duddi</a></center>
|
||||
|
||||
<table BORDER WIDTH="100%" NOSAVE >
|
||||
<tr NOSAVE>
|
||||
<th NOSAVE>Task</th>
|
||||
|
||||
<th NOSAVE><a href="http://bugzilla.mozilla.org/bug_status.html#priority">Priority</a></th>
|
||||
|
||||
<th NOSAVE>Owner</th>
|
||||
|
||||
<th NOSAVE>MileStone complete/Status</th>
|
||||
</tr>
|
||||
|
||||
<tr NOSAVE>
|
||||
<td NOSAVE>Move xpcom from using NR_*() functions (modules/libreg) to nsIRegistry
|
||||
(xpcom/src/nsRegistry.cpp)
|
||||
<ul>
|
||||
<li>
|
||||
Mainly you want to change all the Platform*() functions in nsComponentManager.cpp</li>
|
||||
|
||||
<li>
|
||||
Now we open/close the registry all the time. I want to keep the registry
|
||||
open all the time. That would get performance up.</li>
|
||||
|
||||
<li>
|
||||
Platform*() functions use the NR_*Raw() functions in some places. I wonder
|
||||
if the nsRegistry has a equivalent. If not we need to create them.</li>
|
||||
</ul>
|
||||
Mostly, there is equivalence between NR_*() calls and nsRegistry calls. </td>
|
||||
|
||||
<td>P2</td>
|
||||
|
||||
<td>Nick Ambrose <<a href="mailto:nicka87@hotmail.com">nicka87@hotmail.com</a>></td>
|
||||
|
||||
<td>3/22/1999 started
|
||||
<br>3/27/1999 Patch submitted
|
||||
<br>4/1/1999 Espected date of landing</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Startup components: Some components need to be created at startup.
|
||||
Have a framework for them.</td>
|
||||
|
||||
<td>P1</td>
|
||||
|
||||
<td></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>nsIRegistry access via Javascript.</td>
|
||||
|
||||
<td>P1</td>
|
||||
|
||||
<td></td>
|
||||
|
||||
<td>IDL of nsIRegistry will fix this says <a href="mailto:jband@netscape.com">John
|
||||
Bandhauer</a></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>API changes: Remove all pathlist. XPCOM should support only paths.</td>
|
||||
|
||||
<td>P1</td>
|
||||
|
||||
<td></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Fix xpcom from being initialized before main from static variables.</td>
|
||||
|
||||
<td>P1</td>
|
||||
|
||||
<td><a href="mailto:dp@netscape.com">Suresh Duddi</a></td>
|
||||
|
||||
<td>3/22/1999 Started.
|
||||
<br>- checked in a fixed xpcom initialization sequence.
|
||||
<br>- Now got to fix all code statically calling it. I know Netlib does.</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Path handling: Use nsFileSpec instead of file path names. Char * pathnames
|
||||
are not intl, and cannot be stored in the registry. Plus that wont support
|
||||
mac aliases.
|
||||
<ul>
|
||||
<li>
|
||||
Possibly move autoreg out of xpcom</li>
|
||||
</ul>
|
||||
</td>
|
||||
|
||||
<td>P1</td>
|
||||
|
||||
<td><a href="mailto:dp@netscape.com">Suresh Duddi</a>
|
||||
<br><a href="mailto:rjc@netscape.com">Robert Churchill</a></td>
|
||||
|
||||
<td>3/24/1999 started</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Registry dump utility (regExport exists on windows) and about:registry
|
||||
(or) better yet an rdf data source for the registry.</td>
|
||||
|
||||
<td>P3</td>
|
||||
|
||||
<td></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Replace use of nsVector (PL_Vector) with nsISupportsArray</td>
|
||||
|
||||
<td>P3</td>
|
||||
|
||||
<td><a href="mailto:warren"></a></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>PATH argument to NSRegisterSelf() and NSUnregisterSelf() to be
|
||||
a nsISupports</td>
|
||||
|
||||
<td>P1</td>
|
||||
|
||||
<td></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>
|
||||
Documentation on XPCOM</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="TODO.html">TODO List</a> <<i>this page></i></li>
|
||||
|
||||
<li>
|
||||
XPCOM main page : <a href="http://www.mozilla.org/projects/xpcom">http://www.mozilla.org/projects/xpcom</a></li>
|
||||
|
||||
<li>
|
||||
<a href="xpcom-code-faq.html">Code FAQ</a></li>
|
||||
|
||||
<li>
|
||||
<a href="xpcom-component-registration.html">Component Registration</a></li>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,93 +0,0 @@
|
||||
<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>
|
||||
@@ -1,214 +0,0 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.51 [en] (WinNT; U) [Netscape]">
|
||||
<meta name="Author" content="Suresh Duddi">
|
||||
<title>XPCOM Code FAQ</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>
|
||||
XPCOM Code FAQ</h2>
|
||||
Suresh Duddi <<a href="mailto:dp@netscape.com">dp@netscape.com</a>>
|
||||
<br>Last Modified: March 22 1999
|
||||
<br>
|
||||
<hr WIDTH="100%">
|
||||
<br>I am documenting things randomly as I am replying to people's questions.
|
||||
So this might look more like an FAQ.
|
||||
<h4>
|
||||
What are the Global Objects that XPCOM maintains</h4>
|
||||
|
||||
<ul>mGlobalServiceManager
|
||||
<br>mGlobalComponentManager</ul>
|
||||
|
||||
<h4>
|
||||
What are the static classes that XPCOM maintains</h4>
|
||||
|
||||
<blockquote>nsComponentManager
|
||||
<br>nsServiceManager</blockquote>
|
||||
|
||||
<h4>
|
||||
Is there any restriction on which static class I should call first</h4>
|
||||
|
||||
<blockquote>No restrictions. You can call any function from the static
|
||||
classes nsComponentManager and nsServiceManager. XPCOM will do the right
|
||||
thing to initialize itself at both places.
|
||||
<p>Autoregistration() can happen only after Init_XPCOM() is called since
|
||||
the registy might be required by SelfRegister() functions of the dlls and
|
||||
it is only in Init_XPCOM() do we create register the RegistryFactory()
|
||||
with the ComponentManager.</blockquote>
|
||||
|
||||
<h4>
|
||||
What is the order of creation of the ServiceManager, ComponentManager and
|
||||
Registry</h4>
|
||||
|
||||
<blockquote>Init_XPCOM()
|
||||
<blockquote>
|
||||
<li>
|
||||
create the global component manager</li>
|
||||
|
||||
<li>
|
||||
create the global component manager and register as service with the global
|
||||
service manager</li>
|
||||
|
||||
<li>
|
||||
RegisterFactory(...RegistryFactory...) Register the RegistryFactory()
|
||||
with the component manager so that new registry objects can be created.</li>
|
||||
</blockquote>
|
||||
Now the hard problem is when to trigger Init_XPCOM() There are two static
|
||||
objects nsComponentManager and nsServiceManager. Any function in either
|
||||
of them can be called first. Today nsServiceManager::GetService() is the
|
||||
first one that gets called. All the members of the static nsServiceManager
|
||||
use the nsGetGlobalServiceManager() to get to the global service manager.
|
||||
All members of the static nsComponentManager use the nsGetGlobalComponentManager()
|
||||
to get to the global component manager. Hence if we trigger Init_XPCOM()
|
||||
from both NS_GetGlobalComponentManager() and NS_GetGlobalServiceManager()
|
||||
we will be safe.</blockquote>
|
||||
|
||||
<h4>
|
||||
Is there a global Registry being maintained</h4>
|
||||
|
||||
<blockquote>No. The nsIRegistry is designed to be lightweight access to
|
||||
the registry. Consumers who need to access the registry should use the
|
||||
component manager to create the their own registry access object. This
|
||||
is required because the open() call is supported by the nsIRegistry() and
|
||||
if we maintain a global registry arbitrating which registry file is opened
|
||||
is going to be a major headach.
|
||||
<p>The ProgID for the registry will be <font color="#990000">component://netscape/registry</font>
|
||||
<br> </blockquote>
|
||||
|
||||
<h4>
|
||||
<font color="#000000">ComponentManager Vs ServiceManager</font></h4>
|
||||
|
||||
<blockquote><font color="#000000">ComponentManager is the only way for
|
||||
component creation. ComponentManager always uses the component's factory
|
||||
to create the component instance. Clients (code that calls CreateInstance()
|
||||
to create and use a component) call the ComponentManager to create instances.
|
||||
Components (the code that implemented NSRegisterSelf()) calls the ComponentManager
|
||||
to register itself and gets called when a Client wants to instantiate a
|
||||
component.</font>
|
||||
<p><font color="#000000">ServiceManager is a convinience for getting singleton
|
||||
components, components for which only one instance stays alive for the
|
||||
entire application e.g Netlib. It enforces only one of a kind of a component
|
||||
to exist. Hence the notion of getting a service not creating one. (as opposed
|
||||
to the notion of Creating instances with the componentManager). ServiceManager
|
||||
is a convenience because components can technically force singletonism
|
||||
by making their factory return the same instance if one was created already.
|
||||
The other big use of ServiceManager is the (still unimplemented) notion
|
||||
of Shutting down a service.</font>
|
||||
<p><b><i><font color="#000000">Client</font></i></b>
|
||||
<ul>
|
||||
<li>
|
||||
<i><font color="#000000">When does a client use the service manager vs
|
||||
component manager</font></i></li>
|
||||
|
||||
<p><br><font color="#000000">When a client knows that the component that
|
||||
they are trying to instantiate is a singleton, they need to call service
|
||||
manager instead of component manager. Clients dont have to worry about
|
||||
calling the ComponentManager at all in this case. The ServiceManager will
|
||||
take care of creating the instance if the first one doesn't exist already.</font>
|
||||
<br><font color="#000000">-</font>
|
||||
<li>
|
||||
<i><font color="#000000">When does a client use the Component Manager as
|
||||
opposed to Service Manager</font></i></li>
|
||||
|
||||
<p><br><font color="#000000">When a client wants a private instance of
|
||||
a component, they call the Component Manager. From the Clients point of
|
||||
view, a new xpcom object creation happens everytime they call CreateInstance()
|
||||
Anything else is an implementation detail that the Client need not worry
|
||||
about.</font>
|
||||
<br><font color="#000000">-</font>
|
||||
<li>
|
||||
<i><font color="#000000">How does a Client know that they have to instantiate
|
||||
a singleton</font></i></li>
|
||||
|
||||
<p><br><font color="#000000">For now, the Client just has to know. There
|
||||
is no way of telling which component is a Service and which isn't. In fact,
|
||||
in todays xpcom (Mar 1999) any component can be accessed as a Service.
|
||||
Use your judgement until there is a proper method or service manager is
|
||||
eliminated. There is nothing even in the code that detects Services from
|
||||
Instances.</font>
|
||||
<p><b><font color="#CC0000">Need a solution for this. Email suggestion
|
||||
to <a href="mailto:warren@netscape.com,dp@netscape.com">warren@netscape.com,
|
||||
dp@netscape.com</a></font></b>
|
||||
<br><font color="#000000">-</font></ul>
|
||||
<b><i><font color="#000000">Component</font></i></b>
|
||||
<ul>
|
||||
<li>
|
||||
<i><font color="#000000">Can a component enforce use only as a Service</font></i></li>
|
||||
|
||||
<p><br><font color="#000000">No. The notion of the ServiceManager is available
|
||||
only to Clients.</font>
|
||||
<p><font color="#000000">Note that at some points when a component wants
|
||||
another component, it actually behaves as a client and hence follows the
|
||||
rules of the Client above to either CreateInstance() or GetService() the
|
||||
needed component.</font>
|
||||
<p><b><tt><font color="#990000">Workaround:</font></tt></b><font color="#000000">
|
||||
If however a component wants only one of its instances to exist and cannot
|
||||
ensure that Clients understand well enough only to use the Service Manager
|
||||
to get it, it can implement singletonism in its factory. Basically the
|
||||
factory on first instance creation should hang on to the instance. On subsequence
|
||||
instance creations, addref the instance it is holding to and return that
|
||||
instead creating a new one.</font>
|
||||
<ul>
|
||||
<br><font color="#000000">E.g preferences does this.</font> Code sample
|
||||
at
|
||||
<a href="http://lxr.mozilla.org/seamonkey/source/modules/libpref/src/nsPref.cpp#621">nsPref.cpp
|
||||
nsPrefFactory::CreateInstance()</a> and <a href="http://lxr.mozilla.org/seamonkey/source/modules/libpref/src/nsPref.cpp#227">nsPref.cpp
|
||||
nsPref::GetInstance()</a> With this implementation, whether Clients get
|
||||
to it by calling nsIServiceManager::GetService() or nsIComponentManager::CreateInstance(),
|
||||
the same object will be returned hence guaranteeing singletonism.</ul>
|
||||
<font color="#000000">-</font>
|
||||
<li>
|
||||
<i><font color="#000000">Should a component do anything at creation to
|
||||
become a Service</font></i></li>
|
||||
|
||||
<p><br><font color="#000000">No. Again, the notion of a ServiceManager
|
||||
is available only to Clients.</font>
|
||||
<br><font color="#000000">-</font>
|
||||
<li>
|
||||
<i><font color="#000000">Can a component advertise that it is a service
|
||||
so clients can use it as one</font></i></li>
|
||||
|
||||
<p><br>No. There isn't a way other than a comment in the interface of the
|
||||
header file.</ul>
|
||||
</blockquote>
|
||||
|
||||
<h4>
|
||||
ProgID Vs CLSID</h4>
|
||||
|
||||
<blockquote>ClassID or CLSID is the unique indentification of a component.
|
||||
It is a structure of huge numbers generated by using uuidgen on a windows
|
||||
box. It is represented as a string in documentation as {108d75a0-bab5-11d2-96c4-0060b0fb9956}
|
||||
<p>ProgID is the string identification of an implementation of a component
|
||||
the client is looking for. The representation takes a URI syntax. Eg. component://netscape/network/protocol&name=http
|
||||
Some simplify this to, ProgID is a more readable string form of a CLSID.
|
||||
That is acceptable on the periphery. The ProgID is a Client thing. Components
|
||||
register with component manager to claim that they are the implementation
|
||||
for a ProgID. A component can register to be the implementation for multiple
|
||||
ProgIDs (not implemented yet).
|
||||
<p><b><i>Client</i></b>
|
||||
<ul>
|
||||
<li>
|
||||
<i>Should CreateInstance() calls use ProgID or CLSID<br>
|
||||
<br>
|
||||
</i>ProgID is what Clients should use to CreateInstances. Clients should
|
||||
not even know about the CLSID unless they are hell bent on creating a particular
|
||||
implementation of a component.<br>
|
||||
-</li>
|
||||
</ul>
|
||||
<b><i>Component</i></b>
|
||||
<ul>
|
||||
<li>
|
||||
<i>Should Components register with both a CID and ProgID<br>
|
||||
<br>
|
||||
</i>Absolutely.</li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
<br> </blockquote>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,354 +0,0 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="Author" content="Suresh Duddi">
|
||||
<meta name="GENERATOR" content="Mozilla/4.51 [en] (X11; U; Linux 2.0.36 i686) [Netscape]">
|
||||
<title>XPCOM Dynamic Component Registration</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<h2>
|
||||
XPCOM Dynamic Component Registration</h2></center>
|
||||
|
||||
<center>Suresh Duddi <<a href="mailto:dp@netscape.com">dp@netscape.com</a>>
|
||||
<hr WIDTH="100%"></center>
|
||||
|
||||
<p>Dynamic object registration in XPCOM is achieved by interaction of the
|
||||
following components:
|
||||
<ul>
|
||||
<li>
|
||||
The Registry</li>
|
||||
|
||||
<li>
|
||||
The Repository</li>
|
||||
|
||||
<li>
|
||||
The Service Manager</li>
|
||||
|
||||
<li>
|
||||
Component dll implementing <tt>NSRegisterSelf()</tt></li>
|
||||
</ul>
|
||||
The registration mechanism for XPCOM components is similar in many ways
|
||||
to that of COM. The XPCOM component dlls will have the opportunity to register
|
||||
themselves with the registry. The exact time of installation would be either
|
||||
at install time or as a result of <b>autodetection</b> by the Repository
|
||||
Manager at runtime.
|
||||
<br>
|
||||
<h3>
|
||||
<a NAME="The Registry: XPCOM Hierarchy"></a>The Registry: XPCOM Hierarchy</h3>
|
||||
XPCOM uses the nsRegistry to store mappings between CLSIDs and their implementations.
|
||||
The Registry provides persistent storage of hierarchical keys and name-value
|
||||
pairs associated with each key. Each key also keeps a default value.
|
||||
<p>XPCOM will use the following registry hierarchy:
|
||||
<blockquote><tt>ROOTKEY_COMMON</tt>
|
||||
<br><tt> Common - Classes - CLSID</tt>
|
||||
<br><tt> <b><font color="#CC0000">{108d75a0-bab5-11d2-96c4-0060b0fb9956}</font></b></tt>
|
||||
<br><tt>
|
||||
InprocServer (S) = <font color="#CC0000">libnfs-protocol.so</font></tt>
|
||||
<br><tt>
|
||||
ProgID (S) = <b><font color="#CC0000">component://netscape/network-protocol&type=nfs</font></b></tt>
|
||||
<br><tt>
|
||||
ClassName (S) = <b><font color="#CC0000">NFS Protocol
|
||||
Handler</font></b></tt>
|
||||
<p><tt> <font color="#CC0000">component://netscape/network-protocol&type=nfs</font></tt>
|
||||
<br><tt>
|
||||
CLSID (S) = <font color="#CC0000">{108d75a0-bab5-11d2-96c4-0060b0fb9956}</font></tt>
|
||||
<p><tt><i> </i>Software - Netscape - XPCOM</tt>
|
||||
<br><tt> VersionString
|
||||
(S) = <font color="#CC0000">alpha0.20</font></tt>
|
||||
<p><tt> <font color="#CC0000">libnfs-protocol.so</font></tt>
|
||||
<br><tt>
|
||||
ComponentsCount (S) = <font color="#CC0000">1</font></tt>
|
||||
<br><tt>
|
||||
FileSize (S)
|
||||
= <font color="#CC0000">78965</font></tt>
|
||||
<br><tt>
|
||||
LastModTimeStamp (S) = <font color="#CC0000">Wed Feb
|
||||
24 11:24:06 PST 1999</font></tt></blockquote>
|
||||
|
||||
<h3>
|
||||
<a NAME="The Repository: Object instance creation"></a>The Repository:
|
||||
Object instance creation</h3>
|
||||
All object creation happens via The Repository. <tt>nsIRepository::CreateInstance()</tt>
|
||||
will be the primary way of creation of object instances. The steps in instantiation
|
||||
of an object that implements the IID interface and of class CLSID is as
|
||||
follows:
|
||||
<ol>
|
||||
<li>
|
||||
The CLSID of the component that would need to create the object instance
|
||||
is identified.</li>
|
||||
|
||||
<ol>Callers use <tt>nsIRepository::ProgIDToCLSID()</tt> to convert the
|
||||
ProgID string to the CLSID.</ol>
|
||||
|
||||
<li>
|
||||
Load the dll associated with the CLSID after consulting the Registry</li>
|
||||
|
||||
<li>
|
||||
Instantiate the class factory by calling a globally exported dll function
|
||||
<tt>NSGetFactory()</tt>.
|
||||
This returns an instance of the class factory that implements the <tt>nsIFactory</tt>
|
||||
interface.</li>
|
||||
|
||||
<li>
|
||||
The actual object creation is delegated to this <tt>nsIFactory</tt> instance
|
||||
with a call to <tt>nsIFactory::CreateInstance()</tt>.</li>
|
||||
</ol>
|
||||
|
||||
<h3>
|
||||
<a NAME="The Service Manager"></a>The Service Manager</h3>
|
||||
All globally created system services are available via the <tt>nsIServiceManager</tt>,
|
||||
including the <tt>nsIRepository</tt> and <tt>nsIRegistry</tt>. Although
|
||||
the <tt>nsIServiceManager</tt> uses the Registry and Repository in the
|
||||
creation and maintenance of other services, the circular dependency is
|
||||
broken by not letting the <tt>nsIServiceManager</tt> create the <tt>nsIRepository</tt>
|
||||
and <tt>nsIRegistry</tt> instance and registering them specially with the
|
||||
<tt>nsIServiceManager</tt>.
|
||||
The nsIServiceManager is passed into NSGetFactory() for assisting the DLL
|
||||
in the Factory creation process.
|
||||
<h3>
|
||||
<a NAME="Component Registration"></a>Component Registration</h3>
|
||||
Either at installation time of the Component or at times when the XPCOM
|
||||
library autodetect new/changed dlls, component registration is activated.
|
||||
The autodetection happens at startup time of the navigator or via a javascript
|
||||
trigger <tt>navigator.repository.autodetect()</tt>. The steps in component
|
||||
registration would be:
|
||||
<ol>
|
||||
<li>
|
||||
The dll is loaded</li>
|
||||
|
||||
<li>
|
||||
The component is allowed to self register by a call to a globally exported
|
||||
dll function <tt>NSRegisterSelf()</tt>. The <tt>nsIServiceManager</tt>
|
||||
and the fullpath of the dll are passed in to assist in the registration
|
||||
process. The dll is expected to create/modify its entries in the Registry
|
||||
according to the guidelines of the <a href="#The Registry: XPCOM Hierarchy">XPCOM
|
||||
hierarchy</a> in the registry. <tt>nsIRepository</tt>, which can be queried
|
||||
from the <tt>nsIServiceManager</tt>, has useful registration functions
|
||||
that would easen the process.</li>
|
||||
|
||||
<li>
|
||||
The dll is unloaded</li>
|
||||
</ol>
|
||||
|
||||
<h3>
|
||||
<a NAME="Autodetection of Components"></a>Autodetection of Components</h3>
|
||||
Autodetection of changed dlls happened by storing the dll's last modified
|
||||
time and its size in the Registry automatically. If either the last modified
|
||||
time stamp or the filesize differs from that stored in the Registry for
|
||||
the dll, re-registration takes place. Before re-registration, the existing
|
||||
instances of the objects created by the classes in the dll are not freed
|
||||
because the <tt>nsIRepository</tt> has no list of them. The <tt>NSCanUnload()</tt>
|
||||
will be called with input parameter <i>force</i> set to <tt>true</tt>.
|
||||
The dll has to prepare for getting unloaded. After this call returns, the
|
||||
dll <b>will</b> be unloaded if the return value is <tt>true</tt>. If the
|
||||
dll detects that it cannot properly prepare for unloading, then it can
|
||||
return <tt>false</tt>. XPCOM will not let the re-registration of the modified
|
||||
dll proceed in this case. There is nothing much that XPCOM library can
|
||||
do to salvage this situation other than warning the user of possible instability
|
||||
and advice a restart upon which the re-registration will happen.
|
||||
<h3>
|
||||
<a NAME="ProgID Spec"></a>ProgID Spec</h3>
|
||||
Let us consider some more examples:
|
||||
<ol>
|
||||
<li>
|
||||
A pluggable protocol that implementes the nfs protocol</li>
|
||||
|
||||
<li>
|
||||
A converter that can handle application/x-zip</li>
|
||||
|
||||
<li>
|
||||
A plugin that can handle image/gif</li>
|
||||
|
||||
<li>
|
||||
A widget that can do a toolbar</li>
|
||||
|
||||
<li>
|
||||
A datasource that can handle mail</li>
|
||||
|
||||
<li>
|
||||
A helperapp that deals with application/postscript</li>
|
||||
</ol>
|
||||
All the above have what type they are and one or more arguments on what
|
||||
they particularly do.
|
||||
<p>The ProgID for these would look like
|
||||
<ol>
|
||||
<li>
|
||||
<tt>component://netscape/network-protocol&type=nfs</tt></li>
|
||||
|
||||
<li>
|
||||
<tt>component://netscape/data-converter&type=application/x-zip</tt></li>
|
||||
|
||||
<li>
|
||||
<tt>component://netscape/plugin&type=image/gif&name=ImageMedia's
|
||||
Gif Image Plugin&Description=Reders GIF Images....</tt></li>
|
||||
|
||||
<li>
|
||||
<tt>component://netscape/widget&type=toolbar</tt></li>
|
||||
|
||||
<li>
|
||||
<tt>component://netscape/rdf/datsource&type=mail</tt></li>
|
||||
|
||||
<li>
|
||||
<tt>component://netscape/helperapp&type=application/postscript</tt></li>
|
||||
</ol>
|
||||
{Assume proper escaping of all above URI}
|
||||
<p>The above semantics would let ProgID be an extensible mechanism that
|
||||
could be searched on multiple ways. And
|
||||
<br>query on a progid should match only whatever was passed in. So a query
|
||||
for
|
||||
<br>component://netscape/plugin&type=image/gif should pass for the
|
||||
progid specified above. We could extend this
|
||||
<br>mechanism with wildcards, but I dont want to go there yet... :-)
|
||||
<br>
|
||||
<h3>
|
||||
<a NAME="How will all this help me"></a>How will all this help me</h3>
|
||||
For Component Developers:
|
||||
<ul>
|
||||
<li>
|
||||
Component dlls developed could be dropped into a directory, a JS function
|
||||
called after which your component is in business without even a restart
|
||||
of the browser. Of course, there needs to be someone accessing it.</li>
|
||||
|
||||
<li>
|
||||
No need to export you CLSID or run around finding where to advertise your
|
||||
CLSID</li>
|
||||
</ul>
|
||||
For Component Users:
|
||||
<blockquote>
|
||||
<li>
|
||||
No more hacking in calls to <tt>nsIRepository::RegisterFactory()</tt></li>
|
||||
|
||||
<li>
|
||||
No need to know the CLSID of components that you want to instantiate. Component
|
||||
creation can happen like this</li>
|
||||
|
||||
<br><tt>nsIRepository::CreateInstance(<b>"<font color="#CC0000">component://netscape/network-protocol&type=nfs</font>"</b>,
|
||||
NULL, kProtocolIID, &result);</tt>
|
||||
<br>instead of
|
||||
<br><strike>nsIRepository::CreateInstance(NFS_PROTOCOL_CID, NULL, domIID,
|
||||
&result);</strike></blockquote>
|
||||
|
||||
<h3>
|
||||
<a NAME="What has happened so far"></a>What has happened so far</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Autoregistration implemented to grovel for components from the current
|
||||
directory</li>
|
||||
|
||||
<li>
|
||||
nsRepository is a global object. Not nsIRepository exists.</li>
|
||||
|
||||
<li>
|
||||
nsRepository::ProgIDToCLSID() implemented</li>
|
||||
</ul>
|
||||
|
||||
<h3>
|
||||
<a NAME="Changes to XPCOM happening"></a>Changes to XPCOM happening</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
API changes to get ProgID in entire registration process for factories
|
||||
and components</li>
|
||||
|
||||
<li>
|
||||
ProgID cache to improve performance of ProgID queries</li>
|
||||
|
||||
<li>
|
||||
Notion of Component dlls living in a <b>Components directory </b>and autoregistration
|
||||
will load/manage only these components. Other components that are linked
|
||||
in to the app need to call <tt>nsRepository::RegisterFactory()</tt> from
|
||||
the app. <b>To make this happen we need a list of these.</b></li>
|
||||
|
||||
<li>
|
||||
<b>nsRegistry:</b> Enabling the new nsRegistry developed by Bill Law <law@netscape.com></li>
|
||||
|
||||
<li>
|
||||
Service Manager and Repository: Merge them</li>
|
||||
|
||||
<li>
|
||||
Convenience function to createIntance(progid)</li>
|
||||
|
||||
<li>
|
||||
Base ProgID in the interface ID header file</li>
|
||||
</ul>
|
||||
|
||||
<h3>
|
||||
<a NAME="What should I do"></a>What should I do</h3>
|
||||
|
||||
<ul><b><font color="#CC0000">Component Developers</font></b>
|
||||
<ul>
|
||||
<li>
|
||||
<font color="#000000">Implement <tt>NSRegisterSelf()</tt> for your component
|
||||
dlls. Sample implementation that perf</font> <a href="http://cvs-mirror.mozilla.org/webtools/lxr/source/modules/libpref/src/nsPref.cpp#608">http://cvs-mirror.mozilla.org/webtools/lxr/source/modules/libpref/src/nsPref.cpp#608</a></li>
|
||||
|
||||
<li>
|
||||
Use <tt>nsRepository::RegisterComponent()</tt> instead of <tt>nsRepository::RegisterFactory()</tt>
|
||||
if your component lives in a DLL</li>
|
||||
|
||||
<li>
|
||||
<b>Dont use static constructors in loadable components</b></li>
|
||||
</ul>
|
||||
|
||||
<p><br><b><font color="#CC0000">Component Users</font></b>
|
||||
<ul>
|
||||
<li>
|
||||
Create all your components using ProgID rather than CID</li>
|
||||
|
||||
<li>
|
||||
If you were thinking of managing creation of components yourself, think
|
||||
again. The repository may be already doing that.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<h3>
|
||||
<a NAME="Issues"></a>Issues</h3>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Need support for questions like:</li>
|
||||
|
||||
<ol>
|
||||
<li>
|
||||
Enumerate all CLSIDs that implement a particular interface.</li>
|
||||
|
||||
<li>
|
||||
Let a particular CLSID be the preferable implementation for an interface.</li>
|
||||
|
||||
<br>I dont know how this a XPCOM component user could use it unless there
|
||||
could be a call like:
|
||||
<br><tt>nsIRepository::CreateInstance(<b>NULL</b>, NULL, nsWidgetIID, &result);</tt>
|
||||
<li>
|
||||
Enumerate all interfaces supported by a CLSID</li>
|
||||
</ol>
|
||||
|
||||
<li>
|
||||
Resolving naming conflicts between ProgID</li>
|
||||
|
||||
<li>
|
||||
Store component specific name-values under <tt>ROOTKEY_COMMON\\<i>component.class.version\\</i></tt></li>
|
||||
|
||||
<li>
|
||||
Add a registry entry under <tt>ROOTKEY_COMMON\\<i>component.class.version\\</i></tt>to
|
||||
indicate the willingness for a CLSID to behave as a Service.</li>
|
||||
|
||||
<li>
|
||||
Add quick registration support functions in <tt>nsIRepository</tt> for
|
||||
components to use.</li>
|
||||
|
||||
<li>
|
||||
Is the hierarchy <tt>ROOTKEY_COMMON\\<b>Classes</b>\\CLSID </tt>acceptable.</li>
|
||||
|
||||
<li>
|
||||
Should we have a nsIRepository. JS needs it so that they can reflect it
|
||||
in javascript. Remove &'s in the API.</li>
|
||||
</ul>
|
||||
|
||||
<hr WIDTH="100%">
|
||||
<br><i><font size=-1>Last Modified: 28 Jan 1998</font></i>
|
||||
<br><font size=-1><i>Feedback to: </i><a href="news:netscape.public.mozilla.xpcom">netscape.public.mozilla.xpcom</a></font>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,161 +0,0 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="Author" content="pnunn">
|
||||
<meta name="GENERATOR" content="Mozilla/4.5 [en]C-NSCP (WinNT; U) [Netscape]">
|
||||
<title>xpCom FAQ</title>
|
||||
</head>
|
||||
<body>
|
||||
<b><font size=+3>XPCOM FAQ</font></b>
|
||||
<p>Get out your decoder rings kids!
|
||||
<p>Having a basic understanding of COM is only the first
|
||||
<br>step. To get CMonkey code to build and run,
|
||||
<br>you need to translate your COM ideas into Netscape
|
||||
<br>speak.
|
||||
<p>Feel free to add to this document or change incorrect info.
|
||||
<br>Hopefully more info and more examples will help new
|
||||
<br>people reach XPCOM nirvana more quickly.
|
||||
<p><b>To mentally translate XPCOM to COM.</b>
|
||||
<br>
|
||||
<table BORDER COLS=2 WIDTH="100%" >
|
||||
<tr>
|
||||
<td BGCOLOR="#CCCCCC"><b>vanilla COM</b></td>
|
||||
|
||||
<td BGCOLOR="#FFCCCC"><b>XPCOM</b></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#CCCCCC"> IUnknown</td>
|
||||
|
||||
<td BGCOLOR="#FFCCCC">nsISupports</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#CCCCCC">IClassFactory</td>
|
||||
|
||||
<td BGCOLOR="#FFCCCC">nsIFactory</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#CCCCCC">virtual void _stdcall</td>
|
||||
|
||||
<td BGCOLOR="#FFCCCC">NS_IMETHOD</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#CCCCCC">interface ID = IID</td>
|
||||
|
||||
<td BGCOLOR="#FFCCCC">nsID = nsIID = IID</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#CCCCCC">class ID = CLSID </td>
|
||||
|
||||
<td BGCOLOR="#FFCCCC">nsCID = CID</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>Not too difficult.
|
||||
<br>But wait. There's more.
|
||||
<br><b>-------------------------------------------</b>
|
||||
<p><b><font size=+1>Why don't those classes have AddRef?</font></b>
|
||||
<p>Actually, those classes do have AddRef. It is hidden
|
||||
<br>in a macro. There are alot of macros that are alot of help
|
||||
<br>once you know :
|
||||
<br> 1) They exist.
|
||||
<p> 2) Where they are defined. (They aren't always mnemonic
|
||||
or onomatipeic.
|
||||
<br>
|
||||
You might want to print them out.)
|
||||
<p> mozilla/xpcom/public/nsCom.h
|
||||
<br>
|
||||
mozilla/xpcom/public/nsISupports.h
|
||||
<p> 3)What they are
|
||||
<br>
|
||||
Here's a short list to give you an idea of what you've been missing.
|
||||
<br>
|
||||
The include files listed above are the real reference.
|
||||
<p> 4) A quick way to expand pesky macros:
|
||||
<br>
|
||||
For macros in foo.cpp, 'make foo.i'
|
||||
<p> This
|
||||
will pump the foo.cpp file through C preprocessing
|
||||
<br>
|
||||
and expand all the macros for you. The output can be
|
||||
<br>
|
||||
hard to read, but if you search for unique strings
|
||||
<br>
|
||||
in the area you aredebugging, you can navigate
|
||||
<br>
|
||||
the file pretty easily.
|
||||
<br>
|
||||
(thanks to hshaw@netscape.com)
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<table BORDER COLS=2 WIDTH="100%" BGCOLOR="#CCCCCC" >
|
||||
<tr>
|
||||
<td BGCOLOR="#FFCCCC"><b><font size=+1>Netscape MACRO</font></b></td>
|
||||
|
||||
<td><b><font size=+1>Expansion of macro</font></b></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#FFCCCC">NSADDREF(factoryinstname)</td>
|
||||
|
||||
<td>Factory->AddRef();</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#FFCCCC">NS_IMETHOD</td>
|
||||
|
||||
<td>virtual nsresult __stdcall</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#FFCCCC">NS_INIT_REFCNT()</td>
|
||||
|
||||
<td>mRefCnt = 0</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#FFCCCC">NS_INIT_ISUPPORTS()</td>
|
||||
|
||||
<td>NS_INIT_REFCNT()</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td BGCOLOR="#FFCCCC">NS_DECL_ISUPPORTS</td>
|
||||
|
||||
<td>public:
|
||||
<br> NS_IMETHOD QueryInterface(REFNSIID
|
||||
aIID,
|
||||
<br>
|
||||
void** aInstancePtr);
|
||||
<br> NS_IMETHOD_(nsrefcnt)
|
||||
AddRef(void);
|
||||
<br> NS_IMETHOD_(nsrefcnt)
|
||||
Release(void);
|
||||
<br> protected:
|
||||
<br> nsrefcnt mRefCnt;</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p> <font size=+1>Useful Links to COM Documents:</font>
|
||||
<p><a href="http://www.mozilla.org/projects/xpcom/">XPCOM Page</a>
|
||||
<br><a href="http://www.mozilla.org/projects/xpcom/nsCOMPtr.html">nsCOMPtr</a>
|
||||
<br><a href="http://warp.netscape.com/client/raptor/codingconventions.html">Coding
|
||||
Conventions</a>
|
||||
<br><a href="http://warp/client/bam/eng/howto.html">Getting BAMmed</a>
|
||||
<br><a href="http://warp/client/bam/eng/comdoc.html">How to COM</a>
|
||||
<br><a href="http://www.mozilla.org/docs/tplist/catFlow/modunote.htm">Modularization
|
||||
Techniques</a>
|
||||
<br><a href="http://www.mozilla.org/docs/tplist/catBuild/portable-cpp.html">C++
|
||||
Portability Guide</a>
|
||||
<br><a href="http://www.mozilla.org/newlayout/">NGLayout</a>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,392 +0,0 @@
|
||||
/* -*- 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 "nsIEnumerator.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Intersection Enumerators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsConjoiningEnumerator : public nsIBidirectionalEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIEnumerator methods:
|
||||
NS_IMETHOD First(void);
|
||||
NS_IMETHOD Next(void);
|
||||
NS_IMETHOD CurrentItem(nsISupports **aItem);
|
||||
NS_IMETHOD IsDone(void);
|
||||
|
||||
// nsIBidirectionalEnumerator methods:
|
||||
NS_IMETHOD Last(void);
|
||||
NS_IMETHOD Prev(void);
|
||||
|
||||
// nsConjoiningEnumerator methods:
|
||||
nsConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second);
|
||||
virtual ~nsConjoiningEnumerator(void);
|
||||
|
||||
protected:
|
||||
nsIEnumerator* mFirst;
|
||||
nsIEnumerator* mSecond;
|
||||
nsIEnumerator* mCurrent;
|
||||
};
|
||||
|
||||
nsConjoiningEnumerator::nsConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second)
|
||||
: mFirst(first), mSecond(second), mCurrent(first)
|
||||
{
|
||||
NS_ADDREF(mFirst);
|
||||
NS_ADDREF(mSecond);
|
||||
}
|
||||
|
||||
nsConjoiningEnumerator::~nsConjoiningEnumerator(void)
|
||||
{
|
||||
NS_RELEASE(mFirst);
|
||||
NS_RELEASE(mSecond);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsConjoiningEnumerator);
|
||||
NS_IMPL_RELEASE(nsConjoiningEnumerator);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aIID.Equals(nsIBidirectionalEnumerator::GetIID()) ||
|
||||
aIID.Equals(nsIEnumerator::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = (void*) this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::First(void)
|
||||
{
|
||||
mCurrent = mFirst;
|
||||
return mCurrent->First();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::Next(void)
|
||||
{
|
||||
nsresult rv = mCurrent->Next();
|
||||
if (NS_FAILED(rv) && mCurrent == mFirst) {
|
||||
mCurrent = mSecond;
|
||||
rv = mCurrent->First();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::CurrentItem(nsISupports **aItem)
|
||||
{
|
||||
return mCurrent->CurrentItem(aItem);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::IsDone(void)
|
||||
{
|
||||
return (mCurrent == mFirst && mCurrent->IsDone() == NS_OK)
|
||||
|| (mCurrent == mSecond && mCurrent->IsDone() == NS_OK)
|
||||
? NS_OK : NS_COMFALSE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::Last(void)
|
||||
{
|
||||
nsresult rv;
|
||||
nsIBidirectionalEnumerator* be;
|
||||
rv = mSecond->QueryInterface(nsIBidirectionalEnumerator::GetIID(), (void**)&be);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mCurrent = mSecond;
|
||||
rv = be->Last();
|
||||
NS_RELEASE(be);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsConjoiningEnumerator::Prev(void)
|
||||
{
|
||||
nsresult rv;
|
||||
nsIBidirectionalEnumerator* be;
|
||||
rv = mCurrent->QueryInterface(nsIBidirectionalEnumerator::GetIID(), (void**)&be);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = be->Prev();
|
||||
NS_RELEASE(be);
|
||||
if (NS_FAILED(rv) && mCurrent == mSecond) {
|
||||
rv = mFirst->QueryInterface(nsIBidirectionalEnumerator::GetIID(), (void**)&be);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mCurrent = mFirst;
|
||||
rv = be->Last();
|
||||
NS_RELEASE(be);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second,
|
||||
nsIBidirectionalEnumerator* *aInstancePtrResult)
|
||||
{
|
||||
if (aInstancePtrResult == 0)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsConjoiningEnumerator* e = new nsConjoiningEnumerator(first, second);
|
||||
if (e == 0)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(e);
|
||||
*aInstancePtrResult = e;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static nsresult
|
||||
nsEnumeratorContains(nsIEnumerator* e, nsISupports* item)
|
||||
{
|
||||
nsresult rv;
|
||||
for (e->First(); e->IsDone() != NS_OK; e->Next()) {
|
||||
nsISupports* other;
|
||||
rv = e->CurrentItem(&other);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (item == other) {
|
||||
NS_RELEASE(other);
|
||||
return NS_OK; // true -- exists in enumerator
|
||||
}
|
||||
NS_RELEASE(other);
|
||||
}
|
||||
return NS_COMFALSE; // false -- doesn't exist
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Intersection Enumerators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsIntersectionEnumerator : public nsIEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIEnumerator methods:
|
||||
NS_IMETHOD First(void);
|
||||
NS_IMETHOD Next(void);
|
||||
NS_IMETHOD CurrentItem(nsISupports **aItem);
|
||||
NS_IMETHOD IsDone(void);
|
||||
|
||||
// nsIntersectionEnumerator methods:
|
||||
nsIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second);
|
||||
virtual ~nsIntersectionEnumerator(void);
|
||||
|
||||
protected:
|
||||
nsIEnumerator* mFirst;
|
||||
nsIEnumerator* mSecond;
|
||||
};
|
||||
|
||||
nsIntersectionEnumerator::nsIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second)
|
||||
: mFirst(first), mSecond(second)
|
||||
{
|
||||
NS_ADDREF(mFirst);
|
||||
NS_ADDREF(mSecond);
|
||||
}
|
||||
|
||||
nsIntersectionEnumerator::~nsIntersectionEnumerator(void)
|
||||
{
|
||||
NS_RELEASE(mFirst);
|
||||
NS_RELEASE(mSecond);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsIntersectionEnumerator, nsIEnumerator::GetIID());
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIntersectionEnumerator::First(void)
|
||||
{
|
||||
nsresult rv = mFirst->First();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return Next();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIntersectionEnumerator::Next(void)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// find the first item that exists in both
|
||||
for (; mFirst->IsDone() != NS_OK; mFirst->Next()) {
|
||||
nsISupports* item;
|
||||
rv = mFirst->CurrentItem(&item);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// see if it also exists in mSecond
|
||||
rv = nsEnumeratorContains(mSecond, item);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_RELEASE(item);
|
||||
if (rv == NS_OK) {
|
||||
// found in both, so return leaving it as the current item of mFirst
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIntersectionEnumerator::CurrentItem(nsISupports **aItem)
|
||||
{
|
||||
return mFirst->CurrentItem(aItem);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIntersectionEnumerator::IsDone(void)
|
||||
{
|
||||
return mFirst->IsDone();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
|
||||
nsIEnumerator* *aInstancePtrResult)
|
||||
{
|
||||
if (aInstancePtrResult == 0)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsIntersectionEnumerator* e = new nsIntersectionEnumerator(first, second);
|
||||
if (e == 0)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(e);
|
||||
*aInstancePtrResult = e;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Union Enumerators
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsUnionEnumerator : public nsIEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIEnumerator methods:
|
||||
NS_IMETHOD First(void);
|
||||
NS_IMETHOD Next(void);
|
||||
NS_IMETHOD CurrentItem(nsISupports **aItem);
|
||||
NS_IMETHOD IsDone(void);
|
||||
|
||||
// nsUnionEnumerator methods:
|
||||
nsUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second);
|
||||
virtual ~nsUnionEnumerator(void);
|
||||
|
||||
protected:
|
||||
nsIEnumerator* mFirst;
|
||||
nsIEnumerator* mSecond;
|
||||
};
|
||||
|
||||
nsUnionEnumerator::nsUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second)
|
||||
: mFirst(first), mSecond(second)
|
||||
{
|
||||
NS_ADDREF(mFirst);
|
||||
NS_ADDREF(mSecond);
|
||||
}
|
||||
|
||||
nsUnionEnumerator::~nsUnionEnumerator(void)
|
||||
{
|
||||
NS_RELEASE(mFirst);
|
||||
NS_RELEASE(mSecond);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsUnionEnumerator, nsIEnumerator::GetIID());
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUnionEnumerator::First(void)
|
||||
{
|
||||
nsresult rv = mFirst->First();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return Next();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUnionEnumerator::Next(void)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// find the first item that exists in both
|
||||
for (; mFirst->IsDone() != NS_OK; mFirst->Next()) {
|
||||
nsISupports* item;
|
||||
rv = mFirst->CurrentItem(&item);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// see if it also exists in mSecond
|
||||
rv = nsEnumeratorContains(mSecond, item);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_RELEASE(item);
|
||||
if (rv != NS_OK) {
|
||||
// if it didn't exist in mSecond, return, making it the current item
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// each time around, make sure that mSecond gets reset to the beginning
|
||||
// so that when mFirst is done, we'll be ready to enumerate mSecond
|
||||
rv = mSecond->First();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return mSecond->Next();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUnionEnumerator::CurrentItem(nsISupports **aItem)
|
||||
{
|
||||
if (mFirst->IsDone() != NS_OK)
|
||||
return mFirst->CurrentItem(aItem);
|
||||
else
|
||||
return mSecond->CurrentItem(aItem);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUnionEnumerator::IsDone(void)
|
||||
{
|
||||
return (mFirst->IsDone() == NS_OK && mSecond->IsDone() == NS_OK)
|
||||
? NS_OK : NS_COMFALSE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
|
||||
nsIEnumerator* *aInstancePtrResult)
|
||||
{
|
||||
if (aInstancePtrResult == 0)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsUnionEnumerator* e = new nsUnionEnumerator(first, second);
|
||||
if (e == 0)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(e);
|
||||
*aInstancePtrResult = e;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1,259 +0,0 @@
|
||||
/* -*- 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 "prlog.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, PRBool threadSafe)
|
||||
: mLock(NULL)
|
||||
{
|
||||
hashtable = PL_NewHashTable(aInitSize,
|
||||
_hashValue,
|
||||
_hashKeyCompare,
|
||||
_hashValueCompare,
|
||||
&_hashAllocOps,
|
||||
NULL);
|
||||
if (threadSafe == PR_TRUE)
|
||||
{
|
||||
mLock = PR_NewLock();
|
||||
if (mLock == NULL)
|
||||
{
|
||||
// Cannot create a lock. If running on a multiprocessing system
|
||||
// we are sure to die.
|
||||
PR_ASSERT(mLock != NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsHashtable::~nsHashtable() {
|
||||
PL_HashTableDestroy(hashtable);
|
||||
if (mLock) PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
PRBool nsHashtable::Exists(nsHashKey *aKey)
|
||||
{
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return *hep != NULL;
|
||||
}
|
||||
|
||||
void *nsHashtable::Put(nsHashKey *aKey, void *aData) {
|
||||
void *res = NULL;
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void *nsHashtable::Get(nsHashKey *aKey) {
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
void *ret = PL_HashTableLookup(hashtable, (void *) aKey);
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *nsHashtable::Remove(nsHashKey *aKey) {
|
||||
PLHashNumber hash = aKey->HashValue();
|
||||
PLHashEntry *he;
|
||||
|
||||
if (mLock) PR_Lock(mLock);
|
||||
|
||||
PLHashEntry **hep = PL_HashTableRawLookup(hashtable, hash, (void *) aKey);
|
||||
void *res = NULL;
|
||||
|
||||
if ((he = *hep) != NULL) {
|
||||
res = he->value;
|
||||
PL_HashTableRawRemove(hashtable, hep, he);
|
||||
}
|
||||
|
||||
if (mLock) PR_Unlock(mLock);
|
||||
|
||||
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() {
|
||||
PRBool threadSafe = PR_FALSE;
|
||||
if (mLock)
|
||||
threadSafe = PR_TRUE;
|
||||
nsHashtable *newHashTable = new nsHashtable(hashtable->nentries, threadSafe);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
nsCStringKey::nsCStringKey(const char* str)
|
||||
: mStr(mBuf)
|
||||
{
|
||||
PRUint32 len = PL_strlen(str);
|
||||
if (len >= sizeof(mBuf)) {
|
||||
mStr = PL_strdup(str);
|
||||
NS_ASSERTION(mStr, "out of memory");
|
||||
}
|
||||
else {
|
||||
PL_strcpy(mStr, str);
|
||||
}
|
||||
}
|
||||
|
||||
nsCStringKey::~nsCStringKey(void)
|
||||
{
|
||||
if (mStr != mBuf)
|
||||
PL_strfree(mStr);
|
||||
}
|
||||
|
||||
PRUint32 nsCStringKey::HashValue(void) const
|
||||
{
|
||||
return (PRUint32) PL_HashString((const void*) mStr);
|
||||
}
|
||||
|
||||
PRBool nsCStringKey::Equals(const nsHashKey* aKey) const
|
||||
{
|
||||
return PL_strcmp( ((nsCStringKey*)aKey)->mStr, mStr ) == 0;
|
||||
}
|
||||
|
||||
nsHashKey* nsCStringKey::Clone() const
|
||||
{
|
||||
return new nsCStringKey(mStr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1,168 +0,0 @@
|
||||
/* -*- 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 "prlock.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;
|
||||
PRLock *mLock;
|
||||
|
||||
public:
|
||||
nsHashtable(PRUint32 aSize = 256, PRBool threadSafe = PR_FALSE);
|
||||
~nsHashtable();
|
||||
|
||||
PRInt32 Count(void) { return hashtable->nentries; }
|
||||
PRBool Exists(nsHashKey *aKey);
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsCStringKey: Where keys are char*'s
|
||||
// Some uses: hashing ProgIDs, filenames, URIs
|
||||
|
||||
#include "plstr.h"
|
||||
|
||||
class NS_COM nsCStringKey : public nsHashKey {
|
||||
private:
|
||||
char mBuf[64];
|
||||
char* mStr;
|
||||
|
||||
public:
|
||||
nsCStringKey(const char* str);
|
||||
|
||||
~nsCStringKey(void);
|
||||
|
||||
PRUint32 HashValue(void) const;
|
||||
|
||||
PRBool Equals(const nsHashKey* aKey) const;
|
||||
|
||||
nsHashKey* Clone() const;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
/* -*- 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"
|
||||
|
||||
class nsIEnumerator;
|
||||
|
||||
// IID for the nsICollection interface
|
||||
#define NS_ICOLLECTION_IID \
|
||||
{ /* 83b6019c-cbc4-11d2-8cca-0060b0fc14a3 */ \
|
||||
0x83b6019c, \
|
||||
0xcbc4, \
|
||||
0x11d2, \
|
||||
{0x8c, 0xca, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
|
||||
}
|
||||
|
||||
// IID for the nsICollection Factory 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& GetIID(void) { static nsIID iid = NS_ICOLLECTION_IID; return iid; }
|
||||
|
||||
/** Return the count of elements in the collection.
|
||||
*/
|
||||
NS_IMETHOD_(PRUint32) Count(void) const = 0;
|
||||
|
||||
/** AddItem will take an ISupports and keep track of it
|
||||
* @param aItem is the Item to be added WILL BE ADDREFFED
|
||||
*/
|
||||
NS_IMETHOD AppendElement(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
|
||||
*/
|
||||
NS_IMETHOD RemoveElement(nsISupports *aItem) = 0;
|
||||
|
||||
/** Return an enumeration for the collection.
|
||||
*/
|
||||
NS_IMETHOD Enumerate(nsIEnumerator* *result) = 0;
|
||||
|
||||
/** Clear will clear all items from list
|
||||
*/
|
||||
NS_IMETHOD Clear(void) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* nsICollection_h___ */
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/* -*- 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 "nsISupports.idl"
|
||||
#include "nsIEnumerator.idl"
|
||||
|
||||
[uuid(83b6019c-cbc4-11d2-8cca-0060b0fc14a3)]
|
||||
interface nsICollection : nsISupports {
|
||||
|
||||
readonly attribute unsigned long count; // XXX wrong
|
||||
|
||||
void AppendElement(in nsISupports element);
|
||||
void RemoveElement(in nsISupports element);
|
||||
nsIEnumerator Enumerate();
|
||||
void Clear();
|
||||
};
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
/* -*- 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"
|
||||
|
||||
#if defined(XPIDL_JS_STUBS)
|
||||
struct JSObject;
|
||||
struct JSContext;
|
||||
#endif
|
||||
|
||||
#define NS_IENUMERATOR_IID \
|
||||
{ /* ad385286-cbc4-11d2-8cca-0060b0fc14a3 */ \
|
||||
0xad385286, \
|
||||
0xcbc4, \
|
||||
0x11d2, \
|
||||
{0x8c, 0xca, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
|
||||
}
|
||||
|
||||
class nsIEnumerator : public nsISupports {
|
||||
public:
|
||||
|
||||
static const nsIID& GetIID(void) { static nsIID iid = NS_IENUMERATOR_IID; return iid; }
|
||||
|
||||
/** First will reset the list. will return NS_FAILED if no items
|
||||
*/
|
||||
NS_IMETHOD First(void) = 0;
|
||||
|
||||
/** Next will advance the list. will return failed if already at end
|
||||
*/
|
||||
NS_IMETHOD Next(void) = 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(void) = 0;
|
||||
|
||||
#if defined(XPIDL_JS_STUBS)
|
||||
// XXX Scriptability hack...
|
||||
static NS_EXPORT_(JSObject*) InitJSClass(JSContext* cx) {
|
||||
NS_NOTYETIMPLEMENTED("nsIEnumerator isn't XPIDL scriptable yet");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NS_EXPORT_(JSObject*) GetJSObject(JSContext* cx, nsIEnumerator* priv) {
|
||||
NS_NOTYETIMPLEMENTED("nsIEnumerator isn't XPIDL scriptable yet");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#define NS_IBIDIRECTIONALENUMERATOR_IID \
|
||||
{ /* 75f158a0-cadd-11d2-8cca-0060b0fc14a3 */ \
|
||||
0x75f158a0, \
|
||||
0xcadd, \
|
||||
0x11d2, \
|
||||
{0x8c, 0xca, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
|
||||
}
|
||||
|
||||
class nsIBidirectionalEnumerator : public nsIEnumerator {
|
||||
public:
|
||||
|
||||
static const nsIID& GetIID(void) { static nsIID iid = NS_IBIDIRECTIONALENUMERATOR_IID; return iid; }
|
||||
|
||||
/** Last will reset the list to the end. will return NS_FAILED if no items
|
||||
*/
|
||||
NS_IMETHOD Last(void) = 0;
|
||||
|
||||
/** Prev will decrement the list. will return failed if already at beginning
|
||||
*/
|
||||
NS_IMETHOD Prev(void) = 0;
|
||||
|
||||
};
|
||||
|
||||
// Construct and return an implementation of a "conjoining enumerator." This
|
||||
// enumerator lets you string together two other enumerators into one sequence.
|
||||
// The result is an nsIBidirectionalEnumerator, but if either input is not
|
||||
// also bidirectional, the Last and Prev operations will fail.
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewConjoiningEnumerator(nsIEnumerator* first, nsIEnumerator* second,
|
||||
nsIBidirectionalEnumerator* *aInstancePtrResult);
|
||||
|
||||
// Construct and return an implementation of a "union enumerator." This
|
||||
// enumerator will only return elements that are found in both constituent
|
||||
// enumerators.
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewUnionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
|
||||
nsIEnumerator* *aInstancePtrResult);
|
||||
|
||||
// Construct and return an implementation of an "intersection enumerator." This
|
||||
// enumerator will return elements that are found in either constituent
|
||||
// enumerators, eliminating duplicates.
|
||||
extern "C" NS_COM nsresult
|
||||
NS_NewIntersectionEnumerator(nsIEnumerator* first, nsIEnumerator* second,
|
||||
nsIEnumerator* *aInstancePtrResult);
|
||||
|
||||
#endif // __nsIEnumerator_h
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/* -*- 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 "nsISupports.idl"
|
||||
|
||||
[uuid(ad385286-cbc4-11d2-8cca-0060b0fc14a3)]
|
||||
interface nsIEnumerator : nsISupports {
|
||||
void First();
|
||||
void Next();
|
||||
nsISupports CurrentItem();
|
||||
boolean IsDone();
|
||||
};
|
||||
|
||||
[uuid(75f158a0-cadd-11d2-8cca-0060b0fc14a3)]
|
||||
interface nsIBidirectionalEnumerator : nsIEnumerator {
|
||||
void Last();
|
||||
void Prev();
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
/* -*- 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 "nsICollection.h"
|
||||
|
||||
class nsIBidirectionalEnumerator;
|
||||
|
||||
// {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 nsICollection {
|
||||
public:
|
||||
static const nsIID& GetIID() { 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_(nsISupports*) ElementAt(PRUint32 aIndex) const = 0;
|
||||
NS_IMETHOD_(nsISupports*) operator[](PRUint32 aIndex) const = 0;
|
||||
|
||||
NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement, PRUint32 aStartIndex = 0) const = 0;
|
||||
NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement) const = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRUint32 aIndex) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex) = 0;
|
||||
NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement) = 0;
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements) = 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 whether this has to be here nsISupportsArray(const nsISupportsArray& other);
|
||||
};
|
||||
|
||||
// Construct and return a default implementation of nsISupportsArray:
|
||||
extern NS_COM nsresult
|
||||
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult);
|
||||
|
||||
// Construct and return a default implementation of an enumerator for nsISupportsArrays:
|
||||
extern NS_COM nsresult
|
||||
NS_NewISupportsArrayEnumerator(nsISupportsArray* array,
|
||||
nsIBidirectionalEnumerator* *aInstancePtrResult);
|
||||
|
||||
#endif // nsISupportsArray_h___
|
||||
@@ -1,359 +0,0 @@
|
||||
/* -*- 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 "nsSupportsArray.h"
|
||||
#include "nsSupportsArrayEnumerator.h"
|
||||
|
||||
static const PRUint32 kGrowArrayBy = 8;
|
||||
|
||||
nsSupportsArray::nsSupportsArray()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
mArray = &(mAutoArray[0]);
|
||||
mArraySize = kAutoArraySize;
|
||||
mCount = 0;
|
||||
}
|
||||
|
||||
nsSupportsArray::~nsSupportsArray()
|
||||
{
|
||||
DeleteArray();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSupportsArray, nsISupportsArray::GetIID());
|
||||
|
||||
void nsSupportsArray::DeleteArray(void)
|
||||
{
|
||||
Clear();
|
||||
if (mArray != &(mAutoArray[0])) {
|
||||
delete[] mArray;
|
||||
mArray = &(mAutoArray[0]);
|
||||
mArraySize = kAutoArraySize;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsISupportsArray&)
|
||||
nsISupportsArray::operator=(const nsISupportsArray& other)
|
||||
{
|
||||
NS_ASSERTION(0, "should be an abstract method");
|
||||
return *this; // bogus
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsISupportsArray&)
|
||||
nsSupportsArray::operator=(const nsISupportsArray& aOther)
|
||||
{
|
||||
PRUint32 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::Equals(const nsISupportsArray* aOther) const
|
||||
{
|
||||
if (0 != aOther) {
|
||||
const nsSupportsArray* other = (const nsSupportsArray*)aOther;
|
||||
if (mCount == other->mCount) {
|
||||
PRUint32 index = mCount;
|
||||
while (0 < index--) {
|
||||
if (mArray[index] != other->mArray[index]) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsISupports*)
|
||||
nsSupportsArray::ElementAt(PRUint32 aIndex) const
|
||||
{
|
||||
if ((0 <= aIndex) && (aIndex < mCount)) {
|
||||
nsISupports* element = mArray[aIndex];
|
||||
NS_ADDREF(element);
|
||||
return element;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsSupportsArray::IndexOf(const nsISupports* aPossibleElement, PRUint32 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRInt32)
|
||||
nsSupportsArray::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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::InsertElementAt(nsISupports* aElement, PRUint32 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*));
|
||||
}
|
||||
PRUint32 slide = (mCount - aIndex);
|
||||
if (0 < slide) {
|
||||
::memcpy(mArray + aIndex + 1, oldArray + aIndex, slide * sizeof(nsISupports*));
|
||||
}
|
||||
if (oldArray != &(mAutoArray[0])) {
|
||||
delete[] oldArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PRUint32 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::ReplaceElementAt(nsISupports* aElement, PRUint32 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::RemoveElementAt(PRUint32 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;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex)
|
||||
{
|
||||
if ((0 <= aStartIndex) && (aStartIndex < mCount)) {
|
||||
nsISupports** ep = mArray;
|
||||
nsISupports** end = ep + mCount;
|
||||
while (ep < end) {
|
||||
if (*ep == aElement) {
|
||||
return RemoveElementAt(PRUint32(ep - mArray));
|
||||
}
|
||||
ep++;
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::RemoveLastElement(const nsISupports* aElement)
|
||||
{
|
||||
if (0 < mCount) {
|
||||
nsISupports** ep = (mArray + mCount);
|
||||
while (mArray <= --ep) {
|
||||
if (*ep == aElement) {
|
||||
return RemoveElementAt(PRUint32(ep - mArray));
|
||||
}
|
||||
}
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::AppendElements(nsISupportsArray* aElements)
|
||||
{
|
||||
nsSupportsArray* elements = (nsSupportsArray*)aElements;
|
||||
|
||||
if (elements && (0 < elements->mCount)) {
|
||||
if (mArraySize < (mCount + elements->mCount)) { // need to grow the array
|
||||
PRUint32 count = mCount + elements->mCount;
|
||||
PRUint32 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRUint32 index = 0;
|
||||
while (index < elements->mCount) {
|
||||
NS_ADDREF(elements->mArray[index]);
|
||||
mArray[mCount++] = elements->mArray[index++];
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Clear(void)
|
||||
{
|
||||
if (0 < mCount) {
|
||||
do {
|
||||
--mCount;
|
||||
NS_RELEASE(mArray[mCount]);
|
||||
} while (0 != mCount);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsSupportsArray::Compact(void)
|
||||
{
|
||||
if ((mArraySize != mCount) && (kAutoArraySize < mArraySize)) {
|
||||
nsISupports** oldArray = mArray;
|
||||
PRUint32 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;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::EnumerateForwards(nsISupportsArrayEnumFunc aFunc, void* aData) const
|
||||
{
|
||||
PRInt32 index = -1;
|
||||
PRBool running = PR_TRUE;
|
||||
|
||||
while (running && (++index < (PRInt32)mCount)) {
|
||||
running = (*aFunc)(mArray[index], aData);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(PRBool)
|
||||
nsSupportsArray::EnumerateBackwards(nsISupportsArrayEnumFunc aFunc, void* aData) const
|
||||
{
|
||||
PRUint32 index = mCount;
|
||||
PRBool running = PR_TRUE;
|
||||
|
||||
while (running && (0 < index--)) {
|
||||
running = (*aFunc)(mArray[index], aData);
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArray::Enumerate(nsIEnumerator* *result)
|
||||
{
|
||||
nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(this);
|
||||
if (!e)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
*result = e;
|
||||
NS_ADDREF(e);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewISupportsArray(nsISupportsArray** aInstancePtrResult)
|
||||
{
|
||||
if (aInstancePtrResult == 0)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsSupportsArray *it = new nsSupportsArray();
|
||||
if (0 == it)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(it);
|
||||
*aInstancePtrResult = it;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/* -*- 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 nsSupportsArray_h__
|
||||
#define nsSupportsArray_h__
|
||||
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
static const PRUint32 kAutoArraySize = 4;
|
||||
|
||||
class nsSupportsArray : public nsISupportsArray {
|
||||
public:
|
||||
nsSupportsArray(void);
|
||||
virtual ~nsSupportsArray(void);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsICollection methods:
|
||||
NS_IMETHOD_(PRUint32) Count(void) const { return mCount; }
|
||||
NS_IMETHOD AppendElement(nsISupports *aElement) {
|
||||
return InsertElementAt(aElement, mCount);
|
||||
}
|
||||
NS_IMETHOD RemoveElement(nsISupports *aElement) {
|
||||
return RemoveElement(aElement, 0);
|
||||
}
|
||||
NS_IMETHOD Enumerate(nsIEnumerator* *result);
|
||||
NS_IMETHOD Clear(void);
|
||||
|
||||
// nsISupportsArray methods:
|
||||
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_(nsISupports*) ElementAt(PRUint32 aIndex) const;
|
||||
NS_IMETHOD_(nsISupports*) operator[](PRUint32 aIndex) const { return ElementAt(aIndex); }
|
||||
|
||||
NS_IMETHOD_(PRInt32) IndexOf(const nsISupports* aPossibleElement, PRUint32 aStartIndex = 0) const;
|
||||
NS_IMETHOD_(PRInt32) LastIndexOf(const nsISupports* aPossibleElement) const;
|
||||
|
||||
NS_IMETHOD_(PRBool) InsertElementAt(nsISupports* aElement, PRUint32 aIndex);
|
||||
|
||||
NS_IMETHOD_(PRBool) ReplaceElementAt(nsISupports* aElement, PRUint32 aIndex);
|
||||
|
||||
NS_IMETHOD_(PRBool) RemoveElementAt(PRUint32 aIndex);
|
||||
NS_IMETHOD_(PRBool) RemoveElement(const nsISupports* aElement, PRUint32 aStartIndex = 0);
|
||||
NS_IMETHOD_(PRBool) RemoveLastElement(const nsISupports* aElement);
|
||||
|
||||
NS_IMETHOD_(PRBool) AppendElements(nsISupportsArray* aElements);
|
||||
|
||||
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;
|
||||
PRUint32 mArraySize;
|
||||
PRUint32 mCount;
|
||||
nsISupports* mAutoArray[kAutoArraySize];
|
||||
|
||||
private:
|
||||
// Copy constructors are not allowed
|
||||
nsSupportsArray(const nsISupportsArray& other);
|
||||
};
|
||||
|
||||
#endif // nsSupportsArray_h__
|
||||
@@ -1,133 +0,0 @@
|
||||
/* -*- 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 "nsSupportsArrayEnumerator.h"
|
||||
#include "nsISupportsArray.h"
|
||||
|
||||
nsSupportsArrayEnumerator::nsSupportsArrayEnumerator(nsISupportsArray* array)
|
||||
: mArray(array), mCursor(0)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_ASSERTION(array, "null array");
|
||||
NS_ADDREF(mArray);
|
||||
}
|
||||
|
||||
nsSupportsArrayEnumerator::~nsSupportsArrayEnumerator()
|
||||
{
|
||||
NS_RELEASE(mArray);
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(nsSupportsArrayEnumerator);
|
||||
NS_IMPL_RELEASE(nsSupportsArrayEnumerator);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if (NULL == aInstancePtr)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if (aIID.Equals(nsIBidirectionalEnumerator::GetIID()) ||
|
||||
aIID.Equals(nsIEnumerator::GetIID()) ||
|
||||
aIID.Equals(nsISupports::GetIID())) {
|
||||
*aInstancePtr = (void*) this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::First()
|
||||
{
|
||||
mCursor = 0;
|
||||
PRInt32 end = (PRInt32)mArray->Count();
|
||||
if (mCursor < end)
|
||||
return NS_OK;
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::Next()
|
||||
{
|
||||
PRInt32 end = (PRInt32)mArray->Count();
|
||||
if (mCursor < end) // don't count upward forever
|
||||
mCursor++;
|
||||
if (mCursor < end)
|
||||
return NS_OK;
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::CurrentItem(nsISupports **aItem)
|
||||
{
|
||||
NS_ASSERTION(aItem, "null out parameter");
|
||||
if (mCursor >= 0 && mCursor < (PRInt32)mArray->Count()) {
|
||||
*aItem = (*mArray)[mCursor];
|
||||
NS_IF_ADDREF(*aItem);
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::IsDone()
|
||||
{
|
||||
return (mCursor >= 0 && mCursor < (PRInt32)mArray->Count())
|
||||
? NS_COMFALSE : NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::Last()
|
||||
{
|
||||
mCursor = mArray->Count() - 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSupportsArrayEnumerator::Prev()
|
||||
{
|
||||
if (mCursor >= 0)
|
||||
--mCursor;
|
||||
if (mCursor >= 0)
|
||||
return NS_OK;
|
||||
else
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewISupportsArrayEnumerator(nsISupportsArray* array,
|
||||
nsIBidirectionalEnumerator* *aInstancePtrResult)
|
||||
{
|
||||
if (aInstancePtrResult == 0)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsSupportsArrayEnumerator* e = new nsSupportsArrayEnumerator(array);
|
||||
if (e == 0)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(e);
|
||||
*aInstancePtrResult = e;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user