Compare commits
2 Commits
Flash9_Dot
...
regalloc_c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c43d4984f | ||
|
|
cfe021ff88 |
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal file
134
mozilla/ef/Compiler/RegisterAllocator/BitSet.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "BitSet.h"
|
||||
|
||||
// Return the next bit after index set to true or -1 if none.
|
||||
//
|
||||
Int32 BitSet::nextOne(Int32 pos) const
|
||||
{
|
||||
++pos;
|
||||
|
||||
if (pos < 0 || Uint32(pos) >= universeSize)
|
||||
return -1;
|
||||
|
||||
Uint32 offset = getWordOffset(pos);
|
||||
Uint8 index = getBitOffset(pos);
|
||||
Word* ptr = &word[offset];
|
||||
Word currentWord = *ptr++ >> index;
|
||||
|
||||
if (currentWord != Word(0)) {
|
||||
while ((currentWord & Word(1)) == 0) {
|
||||
++index;
|
||||
currentWord >>= 1;
|
||||
}
|
||||
return (offset << nBitsInWordLog2) + index;
|
||||
}
|
||||
|
||||
Word* limit = &word[getSizeInWords(universeSize)];
|
||||
while (ptr < limit) {
|
||||
++offset;
|
||||
currentWord = *ptr++;
|
||||
if (currentWord != Word(0)) {
|
||||
index = 0;
|
||||
while ((currentWord & Word(1)) == 0) {
|
||||
++index;
|
||||
currentWord >>= 1;
|
||||
}
|
||||
return (offset << nBitsInWordLog2) + index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return the next bit after index set to false or -1 if none.
|
||||
//
|
||||
Int32 BitSet::nextZero(Int32 pos) const
|
||||
{
|
||||
++pos;
|
||||
|
||||
if (pos < 0 || Uint32(pos) >= universeSize)
|
||||
return -1;
|
||||
|
||||
Uint32 offset = getWordOffset(pos);
|
||||
Uint8 index = getBitOffset(pos);
|
||||
Word* ptr = &word[offset];
|
||||
Word currentWord = *ptr++ >> index;
|
||||
|
||||
if (currentWord != Word(~0)) {
|
||||
for (; index < nBitsInWord; ++index) {
|
||||
if ((currentWord & Word(1)) == 0) {
|
||||
Int32 ret = (offset << nBitsInWordLog2) + index;
|
||||
return (Uint32(ret) < universeSize) ? ret : -1;
|
||||
}
|
||||
currentWord >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Word* limit = &word[getSizeInWords(universeSize)];
|
||||
while (ptr < limit) {
|
||||
++offset;
|
||||
currentWord = *ptr++;
|
||||
if (currentWord != Word(~0)) {
|
||||
for (index = 0; index < nBitsInWord; ++index) {
|
||||
if ((currentWord & Word(1)) == 0) {
|
||||
Int32 ret = (offset << nBitsInWordLog2) + index;
|
||||
return (Uint32(ret) < universeSize) ? ret : -1;
|
||||
}
|
||||
currentWord >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
|
||||
// Print the set.
|
||||
//
|
||||
void BitSet::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("[ "));
|
||||
|
||||
for (Int32 i = firstOne(); i != -1; i = nextOne(i)) {
|
||||
Int32 currentBit = i;
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", currentBit));
|
||||
|
||||
Int32 nextBit = nextOne(currentBit);
|
||||
if (nextBit != currentBit + 1) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" "));
|
||||
continue;
|
||||
}
|
||||
|
||||
while ((nextBit != -1) && (nextBit == (currentBit + 1))) {
|
||||
currentBit = nextBit;
|
||||
nextBit = nextOne(nextBit);
|
||||
}
|
||||
|
||||
if (currentBit > (i+1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("-%d ", currentBit));
|
||||
else
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" %d ", currentBit));
|
||||
|
||||
i = currentBit;
|
||||
}
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("]\n"));
|
||||
}
|
||||
|
||||
#endif // DEBUG_LOG
|
||||
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal file
195
mozilla/ef/Compiler/RegisterAllocator/BitSet.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BITSET_H_
|
||||
#define _BITSET_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "LogModule.h"
|
||||
#include "Pool.h"
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// BitSet -
|
||||
|
||||
class BitSet
|
||||
{
|
||||
private:
|
||||
|
||||
#if (PR_BITS_PER_WORD == 64)
|
||||
typedef Uint64 Word;
|
||||
#elif (PR_BITS_PER_WORD == 32)
|
||||
typedef Uint32 Word;
|
||||
#endif
|
||||
|
||||
static const nBitsInWord = PR_BITS_PER_WORD;
|
||||
static const nBytesInWord = PR_BYTES_PER_WORD;
|
||||
static const nBitsInWordLog2 = PR_BITS_PER_WORD_LOG2;
|
||||
static const nBytesInWordLog2 = PR_BYTES_PER_WORD_LOG2;
|
||||
|
||||
// Return the number of Word need to store the universe.
|
||||
static Uint32 getSizeInWords(Uint32 sizeOfUniverse) {return (sizeOfUniverse + (nBitsInWord - 1)) >> nBitsInWordLog2;}
|
||||
// Return the given element offset in its containing Word.
|
||||
static Uint32 getBitOffset(Uint32 element) {return element & (nBitsInWord - 1);}
|
||||
// Return the Word offset for the given element int the universe.
|
||||
static Uint32 getWordOffset(Uint32 element) {return element >> nBitsInWordLog2;}
|
||||
// Return the mask for the given bit index.
|
||||
static Word getMask(Uint8 index) {return Word(1) << index;}
|
||||
|
||||
private:
|
||||
|
||||
Uint32 universeSize; // Size of the universe
|
||||
Word* word; // universe memory.
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
BitSet(const BitSet&);
|
||||
|
||||
// Check if the given set's universe is of the same size than this universe.
|
||||
void checkUniverseCompatibility(const BitSet& set) const {assert(set.universeSize == universeSize);}
|
||||
// Check if pos is valid for this set's universe.
|
||||
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
|
||||
|
||||
public:
|
||||
|
||||
// Create a bitset of universeSize bits.
|
||||
BitSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {word = new(pool) Word[getSizeInWords(universeSize)]; clear();}
|
||||
|
||||
// Return the size of this bitset.
|
||||
Uint32 getSize() const {return universeSize;}
|
||||
|
||||
// Clear the bitset.
|
||||
void clear() {memset(word, 0x00, getSizeInWords(universeSize) << nBytesInWordLog2);}
|
||||
// Clear the bit at index.
|
||||
void clear(Uint32 index) {checkMember(index); word[getWordOffset(index)] &= ~getMask(index);}
|
||||
// Set the bitset.
|
||||
void set() {memset(word, 0xFF, getSizeInWords(universeSize) << nBytesInWordLog2);}
|
||||
// Set the bit at index.
|
||||
void set(Uint32 index) {checkMember(index); word[getWordOffset(index)] |= getMask(index);}
|
||||
// Return true if the bit at index is set.
|
||||
bool test(Uint32 index) const {checkMember(index); return (word[getWordOffset(index)] & getMask(index)) != 0;}
|
||||
// Union with the given bitset.
|
||||
inline void or(const BitSet& set);
|
||||
// Intersection with the given bitset.
|
||||
inline void and(const BitSet& set);
|
||||
// Difference with the given bitset.
|
||||
inline void difference(const BitSet& set);
|
||||
// Copy set.
|
||||
inline BitSet& operator = (const BitSet& set);
|
||||
// Return true if the bitset are identical.
|
||||
friend bool operator == (const BitSet& set1, const BitSet& set2);
|
||||
// Return true if the bitset are different.
|
||||
friend bool operator != (const BitSet& set1, const BitSet& set2);
|
||||
|
||||
// Logical operators.
|
||||
BitSet& operator |= (const BitSet& set) {or(set); return *this;}
|
||||
BitSet& operator &= (const BitSet& set) {and(set); return *this;}
|
||||
BitSet& operator -= (const BitSet& set) {difference(set); return *this;}
|
||||
|
||||
// Return the first bit at set to true or -1 if none.
|
||||
Int32 firstOne() const {return nextOne(-1);}
|
||||
// Return the next bit after index set to true or -1 if none.
|
||||
Int32 nextOne(Int32 pos) const;
|
||||
// Return the first bit at set to false or -1 if none.
|
||||
Int32 firstZero() const {return nextZero(-1);}
|
||||
// Return the next bit after index set to false or -1 if none.
|
||||
Int32 nextZero(Int32 pos) const;
|
||||
|
||||
// Iterator to conform with the set API.
|
||||
typedef Int32 iterator;
|
||||
// Return true if the walk is ordered.
|
||||
static bool isOrdered() {return true;}
|
||||
// Return the iterator for the first element of this set.
|
||||
iterator begin() const {return firstOne();}
|
||||
// Return the next iterator.
|
||||
iterator advance(iterator pos) const {return nextOne(pos);}
|
||||
// Return true if the iterator is at the end of the set.
|
||||
bool done(iterator pos) const {return pos == -1;}
|
||||
// Return the element corresponding to the given iterator.
|
||||
Uint32 get(iterator pos) const {return pos;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the set.
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// Union with the given bitset.
|
||||
//
|
||||
inline void BitSet::or(const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Word* src = set.word;
|
||||
Word* dst = word;
|
||||
Word* limit = &src[getSizeInWords(universeSize)];
|
||||
|
||||
while (src < limit)
|
||||
*dst++ |= *src++;
|
||||
}
|
||||
|
||||
// Intersection with the given bitset.
|
||||
//
|
||||
inline void BitSet::and(const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Word* src = set.word;
|
||||
Word* dst = word;
|
||||
Word* limit = &src[getSizeInWords(universeSize)];
|
||||
|
||||
while (src < limit)
|
||||
*dst++ &= *src++;
|
||||
}
|
||||
|
||||
// Difference with the given bitset.
|
||||
//
|
||||
inline void BitSet::difference(const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Word* src = set.word;
|
||||
Word* dst = word;
|
||||
Word* limit = &src[getSizeInWords(universeSize)];
|
||||
|
||||
while (src < limit)
|
||||
*dst++ &= ~*src++;
|
||||
}
|
||||
|
||||
// Copy the given set into this set.
|
||||
//
|
||||
inline BitSet& BitSet::operator = (const BitSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
if (this != &set)
|
||||
memcpy(word, set.word, getSizeInWords(universeSize) << nBytesInWordLog2);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Return true if the given set is identical to this set.
|
||||
inline bool operator == (const BitSet& set1, const BitSet& set2)
|
||||
{
|
||||
set1.checkUniverseCompatibility(set2);
|
||||
|
||||
if (&set1 == &set2)
|
||||
return true;
|
||||
|
||||
return memcmp(set1.word, set2.word, BitSet::getSizeInWords(set1.universeSize) << BitSet::nBytesInWordLog2) == 0;
|
||||
}
|
||||
|
||||
inline bool operator != (const BitSet& set1, const BitSet& set2) {return !(set1 == set2);}
|
||||
|
||||
#endif // _BITSET_H
|
||||
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal file
159
mozilla/ef/Compiler/RegisterAllocator/Coalescing.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _COALESCING_H_
|
||||
#define _COALESCING_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "InterferenceGraph.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "SparseSet.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
|
||||
#if 1
|
||||
// Performing an ultra conservative coalescing meens that when we look at
|
||||
// candidates (source,destination) for coalescing we need to make sure
|
||||
// that the combined interference of the source and destination register
|
||||
// will not exceed the total number of register available for the register
|
||||
// class.
|
||||
#define ULTRA_CONSERVATIVE_COALESCING
|
||||
#else
|
||||
// If we are not doing an ultra conservative coalescing we have to make sure
|
||||
// that the total number of neighbor whose degree is greater than the total
|
||||
// number of register is not greater than the total number of register.
|
||||
#undef ULTRA_CONSERVATIVE_COALESCING
|
||||
#endif
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct Coalescing
|
||||
{
|
||||
static bool coalesce(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Coalescing<RegisterPressure>::coalesce(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
|
||||
// Initialize the lookup table
|
||||
//
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* newRange = new RegisterName[2 * rangeCount];
|
||||
RegisterName* coalescedRange = &newRange[rangeCount];
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
init(coalescedRange, rangeCount);
|
||||
|
||||
SparseSet interferences(pool, rangeCount);
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
bool removedInstructions = false;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.lndList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
|
||||
// Walk the nodes in the loop nesting depth list.
|
||||
for (Int32 n = nNodes - 1; n >= 0; n--) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
|
||||
InstructionList::iterator it = instructions.begin();
|
||||
while (!instructions.done(it)) {
|
||||
Instruction& instruction = instructions.get(it);
|
||||
it = instructions.advance(it);
|
||||
|
||||
if ((instruction.getFlags() & ifCopy) != 0) {
|
||||
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
|
||||
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
|
||||
|
||||
RegisterName source = findRoot(name2range[instruction.getInstructionUseBegin()[0].getRegisterName()], coalescedRange);
|
||||
RegisterName destination = findRoot(name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()], coalescedRange);
|
||||
|
||||
if (source == destination) {
|
||||
instruction.remove();
|
||||
} else if (!iGraph.interfere(source, destination)) {
|
||||
InterferenceVector* sourceVector = iGraph.getInterferenceVector(source);
|
||||
InterferenceVector* destinationVector = iGraph.getInterferenceVector(destination);
|
||||
|
||||
#ifdef ULTRA_CONSERVATIVE_COALESCING
|
||||
interferences.clear();
|
||||
|
||||
InterferenceVector* vector;
|
||||
for (vector = sourceVector; vector != NULL; vector = vector->next) {
|
||||
RegisterName* neighbors = vector->neighbors;
|
||||
for (Uint32 i = 0; i < vector->count; i++)
|
||||
interferences.set(findRoot(neighbors[i], coalescedRange));
|
||||
}
|
||||
for (vector = destinationVector; vector != NULL; vector = vector->next) {
|
||||
RegisterName* neighbors = vector->neighbors;
|
||||
for (Uint32 i = 0; i < vector->count; i++)
|
||||
interferences.set(findRoot(neighbors[i], coalescedRange));
|
||||
}
|
||||
|
||||
Uint32 count = interferences.getSize();
|
||||
#else // ULTRA_CONSERVATIVE_COALESCING
|
||||
trespass("not implemented");
|
||||
Uint32 count = 0;
|
||||
#endif // ULTRA_CONSERVATIVE_COALESCING
|
||||
|
||||
if (count < 6 /* FIX: should get the number from the class */) {
|
||||
// Update the interferences vector.
|
||||
if (sourceVector == NULL) {
|
||||
iGraph.setInterferenceVector(source, destinationVector);
|
||||
sourceVector = destinationVector;
|
||||
} else if (destinationVector == NULL)
|
||||
iGraph.setInterferenceVector(destination, sourceVector);
|
||||
else {
|
||||
InterferenceVector* last = NULL;
|
||||
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next)
|
||||
last = v;
|
||||
assert(last);
|
||||
last->next = destinationVector;
|
||||
iGraph.setInterferenceVector(destination, sourceVector);
|
||||
}
|
||||
// Update the interference matrix.
|
||||
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next) {
|
||||
RegisterName* neighbors = v->neighbors;
|
||||
for (Uint32 i = 0; i < v->count; i++) {
|
||||
RegisterName neighbor = findRoot(neighbors[i], coalescedRange);
|
||||
iGraph.setInterference(neighbor, source);
|
||||
iGraph.setInterference(neighbor, destination);
|
||||
}
|
||||
}
|
||||
|
||||
instruction.remove();
|
||||
coalescedRange[source] = destination;
|
||||
removedInstructions = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAllocator.rangeCount = compress(registerAllocator.name2range, coalescedRange, registerAllocator.nameCount, rangeCount);
|
||||
delete newRange;
|
||||
|
||||
return removedInstructions;
|
||||
}
|
||||
|
||||
#endif // _COALESCING_H_
|
||||
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal file
283
mozilla/ef/Compiler/RegisterAllocator/Coloring.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef NEW_LAURENTM_CODE
|
||||
|
||||
#include "Coloring.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "FastBitSet.h"
|
||||
#include "FastBitMatrix.h"
|
||||
#include "CpuInfo.h"
|
||||
|
||||
bool Coloring::
|
||||
assignRegisters(FastBitMatrix& interferenceMatrix)
|
||||
{
|
||||
PRUint32 *stackPtr = new(pool) PRUint32[vRegManager.count()];
|
||||
|
||||
return select(interferenceMatrix, stackPtr, simplify(interferenceMatrix, stackPtr));
|
||||
}
|
||||
|
||||
PRInt32 Coloring::
|
||||
getLowestSpillCostRegister(FastBitSet& bitset)
|
||||
{
|
||||
PRInt32 lowest = bitset.firstOne();
|
||||
if (lowest != -1)
|
||||
{
|
||||
Flt32 cost = vRegManager.getVirtualRegister(lowest).spillInfo.spillCost;
|
||||
for (PRInt32 r = bitset.nextOne(lowest); r != -1; r = bitset.nextOne(r))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
|
||||
if (!vReg.spillInfo.infiniteSpillCost && (vReg.spillInfo.spillCost < cost))
|
||||
{
|
||||
cost = vReg.spillInfo.spillCost;
|
||||
lowest = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lowest;
|
||||
}
|
||||
|
||||
PRUint32* Coloring::
|
||||
simplify(FastBitMatrix interferenceMatrix, PRUint32* stackPtr)
|
||||
{
|
||||
// first we construct the sets low and high. low contains all nodes of degree
|
||||
// inferior to the number of register available on the processor. All the
|
||||
// nodes with an high degree and a finite spill cost are placed in high.
|
||||
// Nodes of high degree and infinite spill cost are not included in either sets.
|
||||
|
||||
PRUint32 nRegisters = vRegManager.count();
|
||||
FastBitSet low(pool, nRegisters);
|
||||
FastBitSet high(pool, nRegisters);
|
||||
FastBitSet stack(pool, nRegisters);
|
||||
|
||||
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
|
||||
|
||||
if (vReg.getClass() == vrcStackSlot)
|
||||
{
|
||||
stack.set(i);
|
||||
vReg.colorRegister(nRegisters);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vReg.colorInfo.interferenceDegree < NUMBER_OF_REGISTERS)
|
||||
low.set(i);
|
||||
else // if (!vReg.spillInfo.infiniteSpillCost)
|
||||
high.set(i);
|
||||
|
||||
// Set coloring info.
|
||||
vReg.spillInfo.willSpill = false;
|
||||
|
||||
switch(vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
vReg.colorRegister(LAST_GREGISTER + 1);
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
vReg.colorRegister(LAST_FPREGISTER + 1);
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(false); // Cannot happen.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// push the stack registers
|
||||
PRInt32 j;
|
||||
for (j = stack.firstOne(); j != -1; j = stack.nextOne(j))
|
||||
*stackPtr++ = j;
|
||||
|
||||
// simplify
|
||||
while (true)
|
||||
{
|
||||
PRInt32 r;
|
||||
while ((r = getLowestSpillCostRegister(low)) != -1)
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
|
||||
|
||||
/* update low and high */
|
||||
FastBitSet inter(interferenceMatrix.getRow(r), nRegisters);
|
||||
for (j = inter.firstOne(); j != -1; j = inter.nextOne(j))
|
||||
{
|
||||
VirtualRegister& neighbor = vRegManager.getVirtualRegister(j);
|
||||
// if the new interference degree of one of his neighbor becomes
|
||||
// NUMBER_OF_REGISTERS - 1 then it is added to the set 'low'.
|
||||
|
||||
PRUint32 maxInterference = 0;
|
||||
switch (neighbor.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
maxInterference = NUMBER_OF_GREGISTERS;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
maxInterference = NUMBER_OF_FPREGISTERS;
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(false);
|
||||
}
|
||||
if ((vRegManager.getVirtualRegister(j).colorInfo.interferenceDegree-- == maxInterference))
|
||||
{
|
||||
high.clear(j);
|
||||
low.set(j);
|
||||
}
|
||||
vReg.colorInfo.interferenceDegree--;
|
||||
interferenceMatrix.clear(r, j);
|
||||
interferenceMatrix.clear(j, r);
|
||||
}
|
||||
low.clear(r);
|
||||
|
||||
// Push this register.
|
||||
*stackPtr++ = r;
|
||||
}
|
||||
if ((r = getLowestSpillCostRegister(high)) != -1)
|
||||
{
|
||||
high.clear(r);
|
||||
low.set(r);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return stackPtr;
|
||||
}
|
||||
|
||||
bool Coloring::
|
||||
select(FastBitMatrix& interferenceMatrix, PRUint32* stackBase, PRUint32* stackPtr)
|
||||
{
|
||||
PRUint32 nRegisters = vRegManager.count();
|
||||
FastBitSet usedRegisters(NUMBER_OF_REGISTERS + 1); // usedRegisters if used for both GR & FPR.
|
||||
FastBitSet preColoredRegisters(NUMBER_OF_REGISTERS + 1);
|
||||
FastBitSet usedStack(nRegisters + 1);
|
||||
bool success = true;
|
||||
Int32 lastUsedSSR = -1;
|
||||
|
||||
// select
|
||||
while (stackPtr != stackBase)
|
||||
{
|
||||
// Pop one register.
|
||||
PRUint32 r = *--stackPtr;
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
|
||||
|
||||
FastBitSet neighbors(interferenceMatrix.getRow(r), nRegisters);
|
||||
|
||||
if (vReg.getClass() == vrcStackSlot)
|
||||
// Stack slots coloring.
|
||||
{
|
||||
usedStack.clear();
|
||||
|
||||
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
|
||||
usedStack.set(vRegManager.getVirtualRegister(i).getColor());
|
||||
|
||||
Int32 color = usedStack.firstZero();
|
||||
vReg.colorRegister(color);
|
||||
if (color > lastUsedSSR)
|
||||
lastUsedSSR = color;
|
||||
}
|
||||
else
|
||||
// Integer & Floating point register coloring.
|
||||
{
|
||||
usedRegisters.clear();
|
||||
preColoredRegisters.clear();
|
||||
|
||||
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
|
||||
{
|
||||
VirtualRegister& nvReg = vRegManager.getVirtualRegister(i);
|
||||
usedRegisters.set(nvReg.getColor());
|
||||
if (nvReg.isPreColored())
|
||||
preColoredRegisters.set(nvReg.getPreColor());
|
||||
}
|
||||
if (vReg.hasSpecialInterference)
|
||||
usedRegisters |= vReg.specialInterference;
|
||||
|
||||
PRInt8 c = -1;
|
||||
PRInt8 maxColor = 0;
|
||||
PRInt8 firstColor = 0;
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
firstColor = FIRST_GREGISTER;
|
||||
maxColor = LAST_GREGISTER;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
firstColor = FIRST_FPREGISTER;
|
||||
maxColor = LAST_FPREGISTER;
|
||||
break;
|
||||
default:
|
||||
PR_ASSERT(false);
|
||||
}
|
||||
|
||||
if (vReg.isPreColored())
|
||||
{
|
||||
c = vReg.getPreColor();
|
||||
if (usedRegisters.test(c))
|
||||
c = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (c = usedRegisters.nextZero(firstColor - 1); (c >= 0) && (c <= maxColor) && (preColoredRegisters.test(c));
|
||||
c = usedRegisters.nextZero(c)) {}
|
||||
}
|
||||
|
||||
if ((c >= 0) && (c <= maxColor))
|
||||
{
|
||||
vReg.colorRegister(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
VirtualRegister& stackRegister = vRegManager.newVirtualRegister(vrcStackSlot);
|
||||
vReg.equivalentRegister[vrcStackSlot] = &stackRegister;
|
||||
vReg.spillInfo.willSpill = true;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (success)
|
||||
{
|
||||
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
if (vReg.getColor() > LAST_GREGISTER)
|
||||
PR_ASSERT(false);
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
#if NUMBER_OF_FPREGISTERS != 0
|
||||
if (vReg.getColor() > LAST_FPREGISTER)
|
||||
PR_ASSERT(false);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vRegManager.nUsedStackSlots = lastUsedSSR + 1;
|
||||
return success;
|
||||
}
|
||||
#endif // NEW_LAURENTM_CODE
|
||||
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal file
284
mozilla/ef/Compiler/RegisterAllocator/Coloring.h
Normal file
@@ -0,0 +1,284 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "InterferenceGraph.h"
|
||||
#include "SparseSet.h"
|
||||
#include "Spilling.h"
|
||||
#include "Splits.h"
|
||||
|
||||
UT_EXTERN_LOG_MODULE(RegAlloc);
|
||||
|
||||
template <class RegisterPressure>
|
||||
class Coloring
|
||||
{
|
||||
private:
|
||||
static RegisterName* simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack);
|
||||
static bool select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr);
|
||||
|
||||
public:
|
||||
static bool color(RegisterAllocator& registerAllocator);
|
||||
static void finalColoring(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Coloring<RegisterPressure>::finalColoring(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
RegisterName* color = registerAllocator.color;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
usePtr->setRegisterName(color[name2range[usePtr->getRegisterName()]]);
|
||||
#ifdef DEBUG
|
||||
RegisterID rid = usePtr->getRegisterID();
|
||||
setColoredRegister(rid);
|
||||
usePtr->setRegisterID(rid);
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
definePtr->setRegisterName(color[name2range[definePtr->getRegisterName()]]);
|
||||
#ifdef DEBUG
|
||||
RegisterID rid = definePtr->getRegisterID();
|
||||
setColoredRegister(rid);
|
||||
definePtr->setRegisterID(rid);
|
||||
#endif // DEBUG
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Coloring<RegisterPressure>::select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr)
|
||||
{
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* color = new RegisterName[rangeCount];
|
||||
registerAllocator.color = color;
|
||||
|
||||
for (Uint32 r = 1; r < rangeCount; r++)
|
||||
color[r] = RegisterName(6); // FIX;
|
||||
|
||||
// Color the preColored registers.
|
||||
//
|
||||
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
|
||||
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
|
||||
if (machinePtr->id != invalidID) {
|
||||
color[name2range[getName(machinePtr->id)]] = machinePtr->color;
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill preColor range %d as %d\n", name2range[getName(machinePtr->id)], machinePtr->color));
|
||||
}
|
||||
|
||||
SpillCost* cost = registerAllocator.spillCost;
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet& spill = *new(pool) SparseSet(pool, rangeCount);
|
||||
registerAllocator.willSpill = &spill;
|
||||
SparseSet neighborColors(pool, 6); // FIX
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
|
||||
bool coloringFailed = false;
|
||||
while (coloringStackPtr > coloringStack) {
|
||||
RegisterName range = *--coloringStackPtr;
|
||||
|
||||
if (!cost[range].infinite && cost[range].cost < 0) {
|
||||
coloringFailed = true;
|
||||
spill.set(range);
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, will spill.\n", range));
|
||||
} else {
|
||||
neighborColors.clear();
|
||||
|
||||
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
|
||||
for (Int32 i = vector->count - 1; i >= 0; --i) {
|
||||
RegisterName neighborColor = color[vector->neighbors[i]];
|
||||
if (neighborColor < 6) // FIX
|
||||
neighborColors.set(neighborColor);
|
||||
}
|
||||
|
||||
if (neighborColors.getSize() == 6) { // FIX
|
||||
coloringFailed = true;
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, ", range));
|
||||
|
||||
if (!Splits<RegisterPressure>::findSplit(registerAllocator, color, range)) {
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will spill.\n"));
|
||||
spill.set(range);
|
||||
} else
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will split.\n"));
|
||||
} else {
|
||||
for (Uint32 i = 0; i < 6; i++) // FIX
|
||||
if (!neighborColors.test(i)) {
|
||||
fprintf(stdout, "\twill color %d as %d\n", range, i);
|
||||
color[range] = RegisterName(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
if (coloringFailed) {
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring failed:\n"));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill spill: "));
|
||||
spill.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
} else {
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring succeeded:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++)
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\trange %d colored as %d\n", i, color[i]));
|
||||
}
|
||||
#endif
|
||||
|
||||
return !coloringFailed;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
RegisterName* Coloring<RegisterPressure>::simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack)
|
||||
{
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
SpillCost* spillCost = registerAllocator.spillCost;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
|
||||
Uint32* degree = new Uint32[rangeCount];
|
||||
for (RegisterName i = RegisterName(1); i < rangeCount; i = RegisterName(i + 1)) {
|
||||
InterferenceVector* vector = iGraph.getInterferenceVector(i);
|
||||
degree[i] = (vector != NULL) ? vector->count : 0;
|
||||
}
|
||||
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet low(pool, rangeCount);
|
||||
SparseSet high(pool, rangeCount);
|
||||
SparseSet highInfinite(pool, rangeCount);
|
||||
SparseSet preColored(pool, rangeCount);
|
||||
|
||||
// Get the precolored registers.
|
||||
//
|
||||
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
|
||||
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
|
||||
if (machinePtr->id != invalidID)
|
||||
preColored.set(name2range[getName(machinePtr->id)]);
|
||||
|
||||
// Insert the live ranges in the sets.
|
||||
//
|
||||
for (Uint32 range = 1; range < rangeCount; range++)
|
||||
if (!preColored.test(range))
|
||||
if (degree[range] < 6) // FIX
|
||||
low.set(range);
|
||||
else if (!spillCost[range].infinite)
|
||||
high.set(range);
|
||||
else
|
||||
highInfinite.set(range);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring sets:\n\tlow = "));
|
||||
low.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thigh = "));
|
||||
high.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thighInfinite = "));
|
||||
highInfinite.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tpreColored = "));
|
||||
preColored.printPretty(UT_LOG_MODULE(RegAlloc));
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
RegisterName* coloringStackPtr = coloringStack;
|
||||
|
||||
while (low.getSize() != 0 || high.getSize() != 0) {
|
||||
while (low.getSize() != 0) {
|
||||
RegisterName range = RegisterName(low.getOne());
|
||||
low.clear(range);
|
||||
*coloringStackPtr++ = range;
|
||||
|
||||
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
|
||||
for (Int32 i = (vector->count - 1); i >= 0; --i) {
|
||||
RegisterName neighbor = vector->neighbors[i];
|
||||
degree[neighbor]--;
|
||||
|
||||
if (degree[neighbor] < 6) // FIX
|
||||
if (high.test(neighbor)) {
|
||||
high.clear(neighbor);
|
||||
low.set(neighbor);
|
||||
} else if (highInfinite.test(neighbor)) {
|
||||
highInfinite.clear(neighbor);
|
||||
low.set(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (high.getSize() != 0) {
|
||||
RegisterName best = RegisterName(high.getOne());
|
||||
double bestCost = spillCost[best].cost;
|
||||
double bestDegree = degree[best];
|
||||
|
||||
// Choose the next best candidate.
|
||||
//
|
||||
for (SparseSet::iterator i = high.begin(); !high.done(i); i = high.advance(i)) {
|
||||
RegisterName range = RegisterName(high.get(i));
|
||||
double thisCost = spillCost[range].cost;
|
||||
double thisDegree = degree[range];
|
||||
|
||||
if (thisCost * bestDegree < bestCost * thisDegree) {
|
||||
best = range;
|
||||
bestCost = thisCost;
|
||||
bestDegree = thisDegree;
|
||||
}
|
||||
}
|
||||
|
||||
high.clear(best);
|
||||
low.set(best);
|
||||
}
|
||||
}
|
||||
assert(highInfinite.getSize() == 0);
|
||||
|
||||
delete degree;
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring stack:\n\t"));
|
||||
for (RegisterName* sp = coloringStack; sp < coloringStackPtr; ++sp)
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("%d ", *sp));
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\n"));
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
return coloringStackPtr;
|
||||
}
|
||||
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Coloring<RegisterPressure>::color(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
RegisterName* coloringStack = new RegisterName[registerAllocator.rangeCount];
|
||||
return select(registerAllocator, coloringStack, simplify(registerAllocator, coloringStack));
|
||||
}
|
||||
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal file
212
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
|
||||
#include "DominatorGraph.h"
|
||||
|
||||
DominatorGraph::DominatorGraph(ControlGraph& controlGraph) : controlGraph(controlGraph)
|
||||
{
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
GtoV = new Uint32[nNodes + 1];
|
||||
VtoG = new Uint32[nNodes + 1];
|
||||
|
||||
Uint32 v = 1;
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
VtoG[v] = n;
|
||||
GtoV[n] = v++;
|
||||
}
|
||||
|
||||
// Initialize all the 1-based arrays.
|
||||
//
|
||||
parent = new Uint32[v];
|
||||
semi = new Uint32[v];
|
||||
vertex = new Uint32[v];
|
||||
label = new Uint32[v];
|
||||
size = new Uint32[v];
|
||||
ancestor = new Uint32[v];
|
||||
child = new Uint32[v];
|
||||
dom = new Uint32[v];
|
||||
bucket = new DGLinkedList*[v];
|
||||
|
||||
memset(semi, '\0', v * sizeof(Uint32));
|
||||
memset(bucket, '\0', v * sizeof(DGLinkedList*));
|
||||
|
||||
vCount = v;
|
||||
|
||||
build();
|
||||
|
||||
delete parent;
|
||||
delete semi;
|
||||
delete vertex;
|
||||
delete label;
|
||||
delete size;
|
||||
delete ancestor;
|
||||
delete child;
|
||||
delete dom;
|
||||
delete bucket;
|
||||
}
|
||||
|
||||
Uint32 DominatorGraph::DFS(Uint32 vx, Uint32 n)
|
||||
{
|
||||
semi[vx] = ++n;
|
||||
vertex[n] = label[vx] = vx;
|
||||
ancestor[vx] = child[vx] = 0;
|
||||
size[vx] = 1;
|
||||
|
||||
|
||||
ControlNode& node = *controlGraph.dfsList[VtoG[vx]];
|
||||
ControlEdge* successorEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorPtr = node.getSuccessorsBegin(); successorPtr < successorEnd; successorPtr++) {
|
||||
Uint32 w = GtoV[successorPtr->getTarget().dfsNum];
|
||||
if (semi[w] == 0) {
|
||||
parent[w] = vx;
|
||||
n = DFS(w, n);
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void DominatorGraph::LINK(Uint32 vx, Uint32 w)
|
||||
{
|
||||
Uint32 s = w;
|
||||
|
||||
while (semi[label[w]] < semi[label[child[s]]]) {
|
||||
if (size[s] + size[child[child[s]]] >= (size[child[s]] << 1)) {
|
||||
ancestor[child[s]] = s;
|
||||
child[s] = child[child[s]];
|
||||
} else {
|
||||
size[child[s]] = size[s];
|
||||
s = ancestor[s] = child[s];
|
||||
}
|
||||
}
|
||||
label[s] = label[w];
|
||||
size[vx] += size[w];
|
||||
if(size[vx] < (size[w] << 1)) {
|
||||
Uint32 t = s;
|
||||
s = child[vx];
|
||||
child[vx] = t;
|
||||
}
|
||||
while( s != 0 ) {
|
||||
ancestor[s] = vx;
|
||||
s = child[s];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DominatorGraph::COMPRESS(Uint32 vx)
|
||||
{
|
||||
if(ancestor[ancestor[vx]] != 0) {
|
||||
COMPRESS(ancestor[vx]);
|
||||
if(semi[label[ancestor[vx]]] < semi[label[vx]])
|
||||
label[vx] = label[ancestor[vx]];
|
||||
ancestor[vx] = ancestor[ancestor[vx]];
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 DominatorGraph::EVAL(Uint32 vx)
|
||||
{
|
||||
if(ancestor[vx] == 0)
|
||||
return label[vx];
|
||||
COMPRESS(vx);
|
||||
return (semi[label[ancestor[vx]]] >= semi[label[vx]]) ? label[vx] : label[ancestor[vx]];
|
||||
}
|
||||
|
||||
void DominatorGraph::build()
|
||||
{
|
||||
Uint32 n = DFS(GtoV[0], 0);
|
||||
size[0] = label[0] = semi[0];
|
||||
|
||||
for (Uint32 i = n; i >= 2; i--) {
|
||||
Uint32 w = vertex[i];
|
||||
|
||||
ControlNode& node = *controlGraph.dfsList[VtoG[w]];
|
||||
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
||||
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
|
||||
Uint32 vx = GtoV[predecessors.get(p).getSource().dfsNum];
|
||||
Uint32 u = EVAL(vx);
|
||||
|
||||
if(semi[u] < semi[w])
|
||||
semi[w] = semi[u];
|
||||
}
|
||||
|
||||
DGLinkedList* elem = new DGLinkedList();
|
||||
elem->next = bucket[vertex[semi[w]]];
|
||||
elem->index = w;
|
||||
bucket[vertex[semi[w]]] = elem;
|
||||
|
||||
LINK(parent[w], w);
|
||||
|
||||
elem = bucket[parent[w]];
|
||||
while(elem != NULL) {
|
||||
Uint32 vx = elem->index;
|
||||
Uint32 u = EVAL(vx);
|
||||
dom[vx] = (semi[u] < semi[vx]) ? u : parent[w];
|
||||
elem = elem->next;
|
||||
}
|
||||
}
|
||||
|
||||
memset(size, '\0', n * sizeof(Uint32));
|
||||
Pool& pool = controlGraph.pool;
|
||||
nodes = new(pool) DGNode[n];
|
||||
|
||||
for(Uint32 j = 2; j <= n; j++) {
|
||||
Uint32 w = vertex[j];
|
||||
Uint32 d = dom[w];
|
||||
if(d != vertex[semi[w]]) {
|
||||
d = dom[d];
|
||||
dom[w] = d;
|
||||
}
|
||||
size[d]++;
|
||||
}
|
||||
dom[GtoV[0]] = 0;
|
||||
|
||||
for (Uint32 k = 1; k <= n; k++) {
|
||||
DGNode& node = nodes[VtoG[k]];
|
||||
Uint32 count = size[k];
|
||||
node.successorsEnd = node.successorsBegin = (count) ? new(pool) Uint32[count] : (Uint32*) 0;
|
||||
}
|
||||
|
||||
for (Uint32 l = 2; l <= n; l++)
|
||||
*(nodes[VtoG[dom[l]]].successorsEnd)++ = VtoG[l];
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
void DominatorGraph::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Dominator Graph:\n"));
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
for (Uint32 i = 0; i < nNodes; i++) {
|
||||
DGNode& node = nodes[i];
|
||||
if (node.successorsBegin != node.successorsEnd) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tN%d dominates ", i));
|
||||
for (Uint32* successorsPtr = node.successorsBegin; successorsPtr < node.successorsEnd; successorsPtr++)
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d ", *successorsPtr));
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/DominatorGraph.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DOMINATOR_GRAPH_H_
|
||||
#define _DOMINATOR_GRAPH_H_
|
||||
|
||||
#include "LogModule.h"
|
||||
|
||||
class ControlGraph;
|
||||
|
||||
struct DGNode
|
||||
{
|
||||
Uint32* successorsBegin;
|
||||
Uint32* successorsEnd;
|
||||
};
|
||||
|
||||
struct DGLinkedList
|
||||
{
|
||||
DGLinkedList* next;
|
||||
Uint32 index;
|
||||
};
|
||||
|
||||
class DominatorGraph
|
||||
{
|
||||
private:
|
||||
|
||||
ControlGraph& controlGraph;
|
||||
|
||||
Uint32 vCount;
|
||||
|
||||
Uint32* VtoG;
|
||||
Uint32* GtoV;
|
||||
Uint32* parent;
|
||||
Uint32* semi;
|
||||
Uint32* vertex;
|
||||
Uint32* label;
|
||||
Uint32* size;
|
||||
Uint32* ancestor;
|
||||
Uint32* child;
|
||||
Uint32* dom;
|
||||
DGLinkedList** bucket;
|
||||
DGNode* nodes;
|
||||
|
||||
private:
|
||||
|
||||
void build();
|
||||
|
||||
Uint32 DFS(Uint32 vx, Uint32 n);
|
||||
void LINK(Uint32 vx, Uint32 w);
|
||||
void COMPRESS(Uint32 vx);
|
||||
Uint32 EVAL(Uint32 vx);
|
||||
|
||||
public:
|
||||
|
||||
DominatorGraph(ControlGraph& controlGraph);
|
||||
|
||||
Uint32* getSuccessorsBegin(Uint32 n) const {return nodes[n].successorsBegin;}
|
||||
Uint32* getSuccessorsEnd(Uint32 n) const {return nodes[n].successorsEnd;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
#endif // _DOMINATOR_GRAPH_H_
|
||||
20
mozilla/ef/Compiler/RegisterAllocator/HashSet.cpp
Normal file
20
mozilla/ef/Compiler/RegisterAllocator/HashSet.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "HashSet.h"
|
||||
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal file
97
mozilla/ef/Compiler/RegisterAllocator/HashSet.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _HASH_SET_H_
|
||||
#define _HASH_SET_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include <string.h>
|
||||
|
||||
struct HashSetElement
|
||||
{
|
||||
Uint32 index;
|
||||
HashSetElement* next;
|
||||
};
|
||||
|
||||
class HashSet
|
||||
{
|
||||
private:
|
||||
|
||||
static const hashSize = 64;
|
||||
|
||||
// Return the hash code for the given element index.
|
||||
static Uint32 getHashCode(Uint32 index) {return index & (hashSize - 1);} // Could be better !
|
||||
|
||||
private:
|
||||
|
||||
Pool& allocationPool;
|
||||
HashSetElement** bucket;
|
||||
HashSetElement* free;
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
HashSet(const HashSet&);
|
||||
// No copy operator.
|
||||
void operator = (const HashSet&);
|
||||
|
||||
public:
|
||||
|
||||
// Create a new HashSet.
|
||||
inline HashSet(Pool& pool, Uint32 universeSize);
|
||||
|
||||
// Clear the hashset.
|
||||
void clear();
|
||||
// Clear the element for the given index.
|
||||
void clear(Uint32 index);
|
||||
// Set the element for the given index.
|
||||
void set(Uint32 index);
|
||||
// Return true if the element at index is a member.
|
||||
bool test(Uint32 index) const;
|
||||
// Union with the given hashset.
|
||||
inline void or(const HashSet& set);
|
||||
// Intersection with the given hashset.
|
||||
inline void and(const HashSet& set);
|
||||
// Difference with the given hashset.
|
||||
inline void difference(const HashSet& set);
|
||||
|
||||
// Logical operators.
|
||||
HashSet& operator |= (const HashSet& set) {or(set); return *this;}
|
||||
HashSet& operator &= (const HashSet& set) {and(set); return *this;}
|
||||
HashSet& operator -= (const HashSet& set) {difference(set); return *this;}
|
||||
|
||||
// Iterator to conform with the set API.
|
||||
typedef HashSetElement* iterator;
|
||||
// Return the iterator for the first element of this set.
|
||||
iterator begin() const;
|
||||
// Return the next iterator.
|
||||
iterator advance(iterator pos) const;
|
||||
// Return true if the iterator is at the end of the set.
|
||||
bool done(iterator pos) const {return pos == NULL;}
|
||||
};
|
||||
|
||||
|
||||
inline HashSet::HashSet(Pool& pool, Uint32 /*universeSize*/)
|
||||
: allocationPool(pool), free(NULL)
|
||||
{
|
||||
bucket = new(pool) HashSetElement*[hashSize];
|
||||
memset(bucket, '\0', sizeof(HashSetElement*));
|
||||
}
|
||||
|
||||
#endif // _HASH_SET_H_
|
||||
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal file
213
mozilla/ef/Compiler/RegisterAllocator/IndexedPool.h
Normal file
@@ -0,0 +1,213 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _INDEXED_POOL_H_
|
||||
#define _INDEXED_POOL_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IndexedPool<IndexedObjectSubclass> is an indexed pool of objects. The
|
||||
// template parameter 'IndexedObjectSubclass' must be a subclass of the struct
|
||||
// IndexedObject.
|
||||
//
|
||||
// When the indexed pool is ask to allocate and initialize a new object (using
|
||||
// the operator new(anIndexedPool) it will zero the memory used to store the
|
||||
// object and initialize the field 'index' of this object to its position in
|
||||
// the pool.
|
||||
//
|
||||
// An object allocated by the indexed pool can be freed by calling the method
|
||||
// IndexedPool::release(IndexedElement& objectIndex).
|
||||
//
|
||||
// example:
|
||||
//
|
||||
// IndexedPool<IndexedElement> elementPool;
|
||||
//
|
||||
// IndexedElement& element1 = *new(elementPool) IndexedElement();
|
||||
// IndexedElement& element2 = *new(elementPool) IndexedElement();
|
||||
//
|
||||
// indexedPool.release(element1);
|
||||
// IndexedElement& element3 = *new(elementPool) IndexedElement();
|
||||
//
|
||||
// At this point element1 is no longer a valid object, element2 is at
|
||||
// index 2 and element3 is at index 1.
|
||||
//
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IndexedObject -
|
||||
//
|
||||
|
||||
template<class Object>
|
||||
struct IndexedObject
|
||||
{
|
||||
Uint32 index; // Index in the pool.
|
||||
Object* next; // Used to link IndexedObject together.
|
||||
|
||||
Uint32 getIndex() {return index;}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// IndexedPool<IndexedObject> -
|
||||
//
|
||||
|
||||
template <class IndexedObject>
|
||||
class IndexedPool
|
||||
{
|
||||
private:
|
||||
|
||||
static const blockSize = 4; // Size of one block.
|
||||
|
||||
Uint32 nBlocks; // Number of blocks in the pool.
|
||||
IndexedObject** block; // Array of block pointers.
|
||||
IndexedObject* freeObjects; // Chained list of free IndexedObjects.
|
||||
Uint32 nextIndex; // Index of the next free object in the last block.
|
||||
|
||||
private:
|
||||
|
||||
void allocateAnotherBlock();
|
||||
IndexedObject& newObject();
|
||||
|
||||
public:
|
||||
|
||||
IndexedPool() : nBlocks(0), block(NULL), freeObjects(NULL), nextIndex(1) {}
|
||||
~IndexedPool();
|
||||
|
||||
IndexedObject& get(Uint32 index) const;
|
||||
void release(IndexedObject& object);
|
||||
|
||||
void setSize(Uint32 size) {assert(size < nextIndex); nextIndex = size;}
|
||||
|
||||
// Return the universe size.
|
||||
Uint32 getSize() {return nextIndex;}
|
||||
|
||||
friend void* operator new(size_t, IndexedPool<IndexedObject>& pool); // Needs to call newObject().
|
||||
};
|
||||
|
||||
// Free all the memory allocated for this object.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
IndexedPool<IndexedObject>::~IndexedPool()
|
||||
{
|
||||
for (Uint32 n = 0; n < nBlocks; n++)
|
||||
free(&((IndexedObject **) &block[n][n*blockSize])[-(n + 1)]);
|
||||
}
|
||||
|
||||
// Release the given. This object will be iserted in the chained
|
||||
// list of free IndexedObjects. To minimize the fragmentation the chained list
|
||||
// is ordered by ascending indexes.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
void IndexedPool<IndexedObject>::release(IndexedObject& object)
|
||||
{
|
||||
Uint32 index = object.index;
|
||||
IndexedObject* list = freeObjects;
|
||||
|
||||
assert(&object == &get(index)); // Make sure that object is owned by this pool.
|
||||
|
||||
if (list == NULL) { // The list is empty.
|
||||
freeObjects = &object;
|
||||
object.next = NULL;
|
||||
} else { // The list contains at least 1 element.
|
||||
if (index < list->index) { // insert as first element.
|
||||
freeObjects = &object;
|
||||
object.next = list;
|
||||
} else { // Find this object's place.
|
||||
while ((list->next) != NULL && (list->next->index < index))
|
||||
list = list->next;
|
||||
|
||||
object.next = list->next;
|
||||
list->next = &object;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Sanity check to be sure that the list is correctly ordered.
|
||||
for (IndexedObject* obj = freeObjects; obj != NULL; obj = obj->next)
|
||||
if (obj->next != NULL)
|
||||
assert(obj->index < obj->next->index);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a new block of IndexedObjects. We will allocate the memory to
|
||||
// store IndexedPool::blockSize IndexedObject and the new Array of block
|
||||
// pointers.
|
||||
// The newly created IndexedObjects will not be initialized.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
void IndexedPool<IndexedObject>::allocateAnotherBlock()
|
||||
{
|
||||
void* memory = (void *) malloc((nBlocks + 1) * sizeof(Uint32) + blockSize * sizeof(IndexedObject));
|
||||
|
||||
memcpy(memory, block, nBlocks * sizeof(Uint32));
|
||||
|
||||
block = (IndexedObject **) memory;
|
||||
IndexedObject* objects = (IndexedObject *) &block[nBlocks + 1];
|
||||
|
||||
block[nBlocks] = &objects[-(nBlocks * blockSize)];
|
||||
nBlocks++;
|
||||
}
|
||||
|
||||
// Return the IndexedObject at the position 'index' in the pool.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
IndexedObject& IndexedPool<IndexedObject>::get(Uint32 index) const
|
||||
{
|
||||
Uint32 blockIndex = index / blockSize;
|
||||
assert(blockIndex < nBlocks);
|
||||
|
||||
return block[blockIndex][index];
|
||||
}
|
||||
|
||||
// Return the reference of an unused object in the pool.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
IndexedObject& IndexedPool<IndexedObject>::newObject()
|
||||
{
|
||||
if (freeObjects != NULL) {
|
||||
IndexedObject& newObject = *freeObjects;
|
||||
freeObjects = newObject.next;
|
||||
return newObject;
|
||||
}
|
||||
|
||||
Uint32 nextIndex = this->nextIndex++;
|
||||
Uint32 blockIndex = nextIndex / blockSize;
|
||||
|
||||
while (blockIndex >= nBlocks)
|
||||
allocateAnotherBlock();
|
||||
|
||||
IndexedObject& newObject = block[blockIndex][nextIndex];
|
||||
newObject.index = nextIndex;
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
// Return the address of the next unsused object in the given
|
||||
// indexed pool. The field index of the newly allocated object
|
||||
// will be initialized to the corresponding index of this object
|
||||
// in the pool.
|
||||
//
|
||||
template <class IndexedObject>
|
||||
void* operator new(size_t size, IndexedPool<IndexedObject>& pool)
|
||||
{
|
||||
assert(size == sizeof(IndexedObject));
|
||||
return (void *) &pool.newObject();
|
||||
}
|
||||
|
||||
#endif // _INDEXED_POOL_H_
|
||||
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal file
258
mozilla/ef/Compiler/RegisterAllocator/InterferenceGraph.h
Normal file
@@ -0,0 +1,258 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _INTERFERENCE_GRAPH_H_
|
||||
#define _INTERFERENCE_GRAPH_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "Primitives.h"
|
||||
#include "Instruction.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "SparseSet.h"
|
||||
#include <string.h>
|
||||
|
||||
struct InterferenceVector
|
||||
{
|
||||
Uint32 count;
|
||||
InterferenceVector* next;
|
||||
RegisterName* neighbors;
|
||||
|
||||
InterferenceVector() : count(0), next(NULL) {}
|
||||
};
|
||||
|
||||
class RegisterAllocator;
|
||||
|
||||
template <class RegisterPressure>
|
||||
class InterferenceGraph
|
||||
{
|
||||
private:
|
||||
|
||||
RegisterAllocator& registerAllocator;
|
||||
|
||||
RegisterPressure::Set* interferences;
|
||||
InterferenceVector** vector;
|
||||
Uint32* offset;
|
||||
Uint32 rangeCount;
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
InterferenceGraph(const InterferenceGraph&);
|
||||
// No copy operator.
|
||||
void operator = (const InterferenceGraph&);
|
||||
|
||||
// Check if reg is a member of the universe.
|
||||
void checkMember(RegisterName name) {assert(name < rangeCount);}
|
||||
// Return the edge index for the interference between name1 and name2.
|
||||
Uint32 getEdgeIndex(RegisterName name1, RegisterName name2);
|
||||
|
||||
public:
|
||||
InterferenceGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
|
||||
|
||||
// Calculate the interferences.
|
||||
void build();
|
||||
// Return true if reg1 and reg2 interfere.
|
||||
bool interfere(RegisterName name1, RegisterName name2);
|
||||
// Return the interference vector for the given register or NULL if there is none.
|
||||
InterferenceVector* getInterferenceVector(RegisterName name) {return vector[name];}
|
||||
// Set the interference between name1 and name2.
|
||||
void setInterference(RegisterName name1, RegisterName name2);
|
||||
// Set the interference vector for the given register.
|
||||
void setInterferenceVector(RegisterName name, InterferenceVector* v) {vector[name] = v;}
|
||||
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the interferences.
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void InterferenceGraph<RegisterPressure>::build()
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
this->rangeCount = rangeCount;
|
||||
|
||||
// Initialize the structures.
|
||||
//
|
||||
offset = new(pool) Uint32[rangeCount + 1];
|
||||
vector = new(pool) InterferenceVector*[rangeCount];
|
||||
memset(vector, '\0', sizeof(InterferenceVector*) * rangeCount);
|
||||
|
||||
Uint32 o = 0;
|
||||
offset[0] = 0;
|
||||
for (Uint32 i = 1; i <= rangeCount; ++i) {
|
||||
offset[i] = o;
|
||||
o += i;
|
||||
}
|
||||
|
||||
interferences = new(pool) RegisterPressure::Set(pool, (rangeCount * rangeCount) / 2);
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
LivenessInfo<RegisterPressure> liveness = Liveness<RegisterPressure>::analysis(controlGraph, rangeCount, name2range);
|
||||
registerAllocator.liveness = liveness;
|
||||
SparseSet currentLive(pool, rangeCount);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
currentLive = liveness.liveOut[n];
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
// Handle the copy instruction to avoid unnecessary interference between the 2 registers.
|
||||
if ((instruction.getFlags() & ifCopy) != 0) {
|
||||
assert(useBegin != useEnd && useBegin[0].isRegister());
|
||||
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
|
||||
}
|
||||
|
||||
// Create the interferences.
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName define = name2range[definePtr->getRegisterName()];
|
||||
|
||||
for (SparseSet::iterator e = currentLive.begin(); !currentLive.done(e); e = currentLive.advance(e)) {
|
||||
RegisterName live = RegisterName(currentLive.get(e));
|
||||
|
||||
if ((live != define) && !interfere(live, define) && registerAllocator.canInterfere(live, define)) {
|
||||
|
||||
if (vector[define] == NULL)
|
||||
vector[define] = new(pool) InterferenceVector();
|
||||
vector[define]->count++;
|
||||
|
||||
if (vector[live] == NULL)
|
||||
vector[live] = new(pool) InterferenceVector();
|
||||
vector[live]->count++;
|
||||
|
||||
setInterference(live, define);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now update the liveness.
|
||||
//
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentLive.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
currentLive.set(name2range[usePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the memory to store the interferences.
|
||||
//
|
||||
for (Uint32 e = 0; e < rangeCount; e++)
|
||||
if (vector[e] != NULL) {
|
||||
InterferenceVector& v = *vector[e];
|
||||
v.neighbors = new(pool) RegisterName[v.count];
|
||||
v.count = 0;
|
||||
}
|
||||
|
||||
// Initialize the edges.
|
||||
//
|
||||
if (RegisterPressure::Set::isOrdered()) {
|
||||
RegisterName name1 = RegisterName(0);
|
||||
|
||||
for (RegisterPressure::Set::iterator i = interferences->begin(); !interferences->done(i); i = interferences->advance(i)) {
|
||||
Uint32 interferenceIndex = interferences->get(i);
|
||||
|
||||
while(interferenceIndex >= offset[name1 + 1])
|
||||
name1 = RegisterName(name1 + 1);
|
||||
|
||||
assert((interferenceIndex >= offset[name1]) && (interferenceIndex < offset[name1 + 1]));
|
||||
|
||||
RegisterName name2 = RegisterName(interferenceIndex - offset[name1]);
|
||||
|
||||
assert(interfere(name1, name2));
|
||||
|
||||
InterferenceVector& vector1 = *vector[name1];
|
||||
vector1.neighbors[vector1.count++] = name2;
|
||||
|
||||
InterferenceVector& vector2 = *vector[name2];
|
||||
vector2.neighbors[vector2.count++] = name1;
|
||||
}
|
||||
} else {
|
||||
trespass("not Implemented"); // FIX: need one more pass to initialize the vectors.
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
Uint32 InterferenceGraph<RegisterPressure>::getEdgeIndex(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
checkMember(name1); checkMember(name2);
|
||||
assert(name1 != name2); // This is not possible.
|
||||
return (name1 < name2) ? offset[name2] + name1 : offset[name1] + name2;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void InterferenceGraph<RegisterPressure>::setInterference(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
interferences->set(getEdgeIndex(name1, name2));
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool InterferenceGraph<RegisterPressure>::interfere(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
return interferences->test(getEdgeIndex(name1, name2));
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
template <class RegisterPressure>
|
||||
void InterferenceGraph<RegisterPressure>::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Vectors:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++) {
|
||||
if (vector[i] != NULL) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tvr%d: (", i));
|
||||
for (InterferenceVector* v = vector[i]; v != NULL; v = v->next)
|
||||
for (Uint32 j = 0; j < v->count; j++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", v->neighbors[j]));
|
||||
if (v->next != NULL || j != (v->count - 1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (","));
|
||||
}
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (")\n"));
|
||||
}
|
||||
}
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Matrix:\n"));
|
||||
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
|
||||
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && interfere(name1, name2)) ? '1' : '0'));
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
#endif // _INTERFERENCE_GRAPH_H_
|
||||
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal file
87
mozilla/ef/Compiler/RegisterAllocator/LiveRange.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIVE_RANGE_H_
|
||||
#define _LIVE_RANGE_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Primitives.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct LiveRange
|
||||
{
|
||||
static void build(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void LiveRange<RegisterPressure>::build(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
// Intialize the lookup table.
|
||||
//
|
||||
Uint32 nameCount = registerAllocator.nameCount;
|
||||
RegisterName* nameTable = new(registerAllocator.pool) RegisterName[2*nameCount];
|
||||
RegisterName* rangeName = &nameTable[nameCount];
|
||||
|
||||
init(rangeName, nameCount);
|
||||
|
||||
// Walk the graph.
|
||||
//
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
SparseSet destination(registerAllocator.pool, nameCount);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
|
||||
destination.clear();
|
||||
for (InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
||||
Instruction& phiNode = phiNodes.get(i);
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
|
||||
destination.set(findRoot(phiNode.getInstructionDefineBegin()[0].getRegisterName(), rangeName));
|
||||
}
|
||||
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
|
||||
RegisterName destinationName = phiNode.getInstructionDefineBegin()[0].getRegisterName();
|
||||
RegisterName destinationRoot = findRoot(destinationName, rangeName);
|
||||
|
||||
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
|
||||
assert(usePtr->isRegister());
|
||||
RegisterName sourceName = usePtr->getRegisterName();
|
||||
RegisterName sourceRoot = findRoot(sourceName, rangeName);
|
||||
|
||||
if (sourceRoot != destinationRoot && !destination.test(sourceRoot))
|
||||
rangeName[sourceRoot] = destinationRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerAllocator.rangeCount = compress(registerAllocator.name2range, rangeName, nameCount, nameCount);
|
||||
}
|
||||
|
||||
#endif // _LIVE_RANGE_H_
|
||||
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal file
163
mozilla/ef/Compiler/RegisterAllocator/LiveRangeGraph.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIVE_RANGE_GRAPH_
|
||||
#define _LIVE_RANGE_GRAPH_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
class RegisterAllocator;
|
||||
|
||||
template <class RegisterPressure>
|
||||
class LiveRangeGraph
|
||||
{
|
||||
private:
|
||||
|
||||
RegisterAllocator& registerAllocator;
|
||||
|
||||
RegisterPressure::Set* edges;
|
||||
Uint32 rangeCount;
|
||||
|
||||
public:
|
||||
//
|
||||
//
|
||||
LiveRangeGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
|
||||
|
||||
//
|
||||
//
|
||||
void build();
|
||||
|
||||
//
|
||||
//
|
||||
void addEdge(RegisterName name1, RegisterName name2);
|
||||
|
||||
//
|
||||
//
|
||||
bool haveEdge(RegisterName name1, RegisterName name2);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
//
|
||||
//
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void LiveRangeGraph<RegisterPressure>::build()
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
this->rangeCount = rangeCount;
|
||||
|
||||
edges = new(pool) RegisterPressure::Set(pool, rangeCount * rangeCount);
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
LivenessInfo<RegisterPressure>& liveness = registerAllocator.liveness;
|
||||
SparseSet currentLive(pool, rangeCount);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
currentLive = liveness.liveOut[n];
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
if ((instruction.getFlags() & ifCopy) != 0) {
|
||||
assert(useBegin != useEnd && useBegin[0].isRegister());
|
||||
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName define = name2range[definePtr->getRegisterName()];
|
||||
|
||||
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
|
||||
RegisterName live = RegisterName(currentLive.get(l));
|
||||
if (define != live && registerAllocator.canInterfere(define, live))
|
||||
addEdge(define, live);
|
||||
}
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentLive.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
currentLive.set(name2range[usePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName use = name2range[usePtr->getRegisterName()];
|
||||
|
||||
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
|
||||
RegisterName live = RegisterName(currentLive.get(l));
|
||||
if (use != live && registerAllocator.canInterfere(use, live))
|
||||
addEdge(use, live);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void LiveRangeGraph<RegisterPressure>::addEdge(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
assert(name1 != name2);
|
||||
edges->set(name1 * rangeCount + name2);
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool LiveRangeGraph<RegisterPressure>::haveEdge(RegisterName name1, RegisterName name2)
|
||||
{
|
||||
assert(name1 != name2);
|
||||
return edges->test(name1 * rangeCount + name2);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
template <class RegisterPressure>
|
||||
void LiveRangeGraph<RegisterPressure>::printPretty(LogModuleObject log)
|
||||
{
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Live ranges graph:\n"));
|
||||
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
|
||||
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && haveEdge(name1, name2)) ? '1' : '0'));
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
#endif // _LIVE_RANGE_GRAPH_
|
||||
21
mozilla/ef/Compiler/RegisterAllocator/Liveness.cpp
Normal file
21
mozilla/ef/Compiler/RegisterAllocator/Liveness.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Liveness.h"
|
||||
|
||||
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal file
301
mozilla/ef/Compiler/RegisterAllocator/Liveness.h
Normal file
@@ -0,0 +1,301 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LIVENESS_H_
|
||||
#define _LIVENESS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// LivenessInfo -
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct LivenessInfo
|
||||
{
|
||||
RegisterPressure::Set* liveIn;
|
||||
RegisterPressure::Set* liveOut;
|
||||
DEBUG_LOG_ONLY(Uint32 size);
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Liveness
|
||||
//
|
||||
// The liveness is defined by the following data-flow equations:
|
||||
//
|
||||
// LiveIn(n) = LocalLive(n) U (LiveOut(n) - Killed(n)).
|
||||
// LiveOut(n) = U LiveIn(s) (s a successor of n).
|
||||
//
|
||||
// where LocalLive(n) is the set of used registers in the block n, Killed(n)
|
||||
// is the set of defined registers in the block n, LiveIn(n) is the set of
|
||||
// live registers at the begining of the block n and LiveOut(n) is the set
|
||||
// of live registers at the end of the block n.
|
||||
//
|
||||
//
|
||||
// We will compute the liveness analysis in two stages:
|
||||
//
|
||||
// 1- Build LocalLive(n) (wich is an approximation of LiveIn(n)) and Killed(n)
|
||||
// for each block n.
|
||||
// 2- Perform a backward data-flow analysis to propagate the liveness information
|
||||
// through the entire control-flow graph.
|
||||
//
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct Liveness
|
||||
{
|
||||
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range);
|
||||
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 nameCount);
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
// Allocate the temporary sets.
|
||||
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
|
||||
|
||||
// Allocate the globals sets.
|
||||
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
|
||||
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
|
||||
|
||||
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
|
||||
//
|
||||
for (Uint32 n = 0; n < (nNodes - 1); n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLocalLive = liveIn[n];
|
||||
RegisterPressure::Set& currentKilled = killed[n];
|
||||
|
||||
// Find the instructions contributions to the sets LocalLive and Killed.
|
||||
//
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
Uint32 index = name2range[usePtr->getRegisterName()];
|
||||
|
||||
if (!currentKilled.test(index))
|
||||
currentLocalLive.set(index);
|
||||
}
|
||||
|
||||
// If a Virtualregister is 'defined' then we add it to the set Killed.
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentKilled.set(name2range[definePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
|
||||
// control-flow graph.
|
||||
//
|
||||
RegisterPressure::Set temp(pool, rangeCount);
|
||||
|
||||
bool changed;
|
||||
do {
|
||||
changed = false;
|
||||
|
||||
// For all nodes is this graph except the endNode.
|
||||
for (Int32 n = (nNodes - 2); n >= 0; n--) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLiveIn = liveIn[n];
|
||||
RegisterPressure::Set& currentLiveOut = liveOut[n];
|
||||
|
||||
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
|
||||
// temp will be the new LiveOut(n).
|
||||
Uint32 nSuccessors = node.nSuccessors();
|
||||
if (nSuccessors != 0) {
|
||||
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
|
||||
for (Uint32 s = 1; s < nSuccessors; s++)
|
||||
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
|
||||
} else
|
||||
temp.clear();
|
||||
|
||||
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
|
||||
// new LiveIn(n).
|
||||
if (currentLiveOut != temp) {
|
||||
currentLiveOut = temp;
|
||||
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
|
||||
temp |= currentLiveIn;
|
||||
|
||||
if (currentLiveIn != temp) {
|
||||
currentLiveIn = temp;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(changed);
|
||||
|
||||
LivenessInfo<RegisterPressure> liveness;
|
||||
liveness.liveIn = liveIn;
|
||||
liveness.liveOut = liveOut;
|
||||
DEBUG_LOG_ONLY(liveness.size = nNodes);
|
||||
return liveness;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 nameCount)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
// Allocate the temporary sets.
|
||||
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
RegisterPressure::Set* usedByPhiNodes = NULL;
|
||||
|
||||
// Allocate the globals sets.
|
||||
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
|
||||
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
|
||||
//
|
||||
for (Uint32 n = 0; n < (nNodes - 1); n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLocalLive = liveIn[n];
|
||||
RegisterPressure::Set& currentKilled = killed[n];
|
||||
|
||||
InstructionList& phiNodes = node.getPhiNodeInstructions();
|
||||
|
||||
if ((usedByPhiNodes == NULL) && !phiNodes.empty())
|
||||
usedByPhiNodes = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
|
||||
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
InstructionDefine& define = phiNode.getInstructionDefineBegin()[0];
|
||||
currentKilled.set(define.getRegisterName());
|
||||
|
||||
typedef DoublyLinkedList<ControlEdge> ControlEdgeList;
|
||||
const ControlEdgeList& predecessors = node.getPredecessors();
|
||||
ControlEdgeList::iterator p = predecessors.begin();
|
||||
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++, p = predecessors.advance(p))
|
||||
if (usePtr->isRegister())
|
||||
usedByPhiNodes[predecessors.get(p).getSource().dfsNum].set(usePtr->getRegisterName());
|
||||
}
|
||||
|
||||
// Find the instructions contributions to the sets LocalLive and Killed.
|
||||
//
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
Uint32 index = usePtr->getRegisterName();
|
||||
|
||||
if (!currentKilled.test(index))
|
||||
currentLocalLive.set(index);
|
||||
}
|
||||
|
||||
// If a Virtualregister is 'defined' then we add it to the set Killed.
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentKilled.set(definePtr->getRegisterName());
|
||||
}
|
||||
}
|
||||
|
||||
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
|
||||
// control-flow graph.
|
||||
//
|
||||
RegisterPressure::Set temp(pool, nameCount);
|
||||
|
||||
bool changed;
|
||||
do {
|
||||
changed = false;
|
||||
|
||||
// For all nodes is this graph except the endNode.
|
||||
for (Int32 n = (nNodes - 2); n >= 0; n--) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
RegisterPressure::Set& currentLiveIn = liveIn[n];
|
||||
RegisterPressure::Set& currentLiveOut = liveOut[n];
|
||||
|
||||
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
|
||||
// temp will be the new LiveOut(n).
|
||||
Uint32 nSuccessors = node.nSuccessors();
|
||||
if (nSuccessors != 0) {
|
||||
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
|
||||
for (Uint32 s = 1; s < nSuccessors; s++)
|
||||
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
|
||||
} else
|
||||
temp.clear();
|
||||
|
||||
// Insert the phiNodes contribution.
|
||||
if (usedByPhiNodes != NULL)
|
||||
temp |= usedByPhiNodes[n];
|
||||
|
||||
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
|
||||
// new LiveIn(n).
|
||||
if (currentLiveOut != temp) {
|
||||
currentLiveOut = temp;
|
||||
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
|
||||
temp |= currentLiveIn;
|
||||
|
||||
if (currentLiveIn != temp) {
|
||||
currentLiveIn = temp;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(changed);
|
||||
|
||||
LivenessInfo<RegisterPressure> liveness;
|
||||
liveness.liveIn = liveIn;
|
||||
liveness.liveOut = liveOut;
|
||||
DEBUG_LOG_ONLY(liveness.size = nNodes);
|
||||
return liveness;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
template <class RegisterPressure>
|
||||
void LivenessInfo<RegisterPressure>::printPretty(LogModuleObject log)
|
||||
{
|
||||
for (Uint32 n = 0; n < size; n++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Node N%d:\n\tliveIn = ", n));
|
||||
liveIn[n].printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tliveOut = "));
|
||||
liveOut[n].printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
|
||||
#endif // _LIVENESS_H_
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/Makefile
Normal file
@@ -0,0 +1,40 @@
|
||||
#! gmake
|
||||
|
||||
DEPTH = ../..
|
||||
|
||||
MODULE_NAME = RegisterAllocator
|
||||
|
||||
include $(DEPTH)/config/config.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I$(DEPTH)/Utilities/General \
|
||||
-I$(DEPTH)/Utilities/zlib \
|
||||
-I$(DEPTH)/Runtime/ClassReader \
|
||||
-I$(DEPTH)/Runtime/NativeMethods \
|
||||
-I$(DEPTH)/Runtime/System \
|
||||
-I$(DEPTH)/Runtime/ClassInfo \
|
||||
-I$(DEPTH)/Runtime/FileReader \
|
||||
-I$(DEPTH)/Compiler/PrimitiveGraph \
|
||||
-I$(DEPTH)/Compiler/FrontEnd \
|
||||
-I$(DEPTH)/Compiler/Optimizer \
|
||||
-I$(DEPTH)/Compiler/CodeGenerator \
|
||||
-I$(DEPTH)/Compiler/CodeGenerator/md \
|
||||
-I$(DEPTH)/Compiler/CodeGenerator/md/$(CPU_ARCH) \
|
||||
-I$(DEPTH)/Compiler/RegisterAllocator \
|
||||
-I$(DEPTH)/Driver/StandAloneJava \
|
||||
-I$(DEPTH)/Debugger \
|
||||
$(NULL)
|
||||
|
||||
CXXSRCS = \
|
||||
RegisterAllocator.cpp \
|
||||
RegisterAllocatorTools.cpp \
|
||||
DominatorGraph.cpp \
|
||||
VirtualRegister.cpp \
|
||||
BitSet.cpp \
|
||||
SparseSet.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
||||
include $(DEPTH)/config/rules.mk
|
||||
|
||||
libs:: $(MODULE)
|
||||
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal file
392
mozilla/ef/Compiler/RegisterAllocator/PhiNodeRemover.h
Normal file
@@ -0,0 +1,392 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _PHI_NODE_REMOVER_H_
|
||||
#define _PHI_NODE_REMOVER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "DominatorGraph.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "Liveness.h"
|
||||
#include "Instruction.h"
|
||||
#include "InstructionEmitter.h"
|
||||
#include "SparseSet.h"
|
||||
#include <string.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterNameNode -
|
||||
|
||||
struct RegisterNameNode
|
||||
{
|
||||
RegisterNameNode* next;
|
||||
RegisterName newName;
|
||||
Uint32 nextPushed;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// CopyData -
|
||||
|
||||
struct CopyData
|
||||
{
|
||||
RegisterName source;
|
||||
RegisterClassKind classKind;
|
||||
Uint32 useCount;
|
||||
bool isLiveOut;
|
||||
RegisterName sourceNameToUse;
|
||||
RegisterName temporaryName;
|
||||
RegisterNameNode* newName;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// PhiNodeRemover<RegisterPressure> -
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct PhiNodeRemover
|
||||
{
|
||||
// Replace the phi nodes by copy instructions.
|
||||
static void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
|
||||
};
|
||||
|
||||
// Split some of the critical edges and return true if there are still some
|
||||
// in the graph after that.
|
||||
//
|
||||
static bool splitCriticalEdges(ControlGraph& /*cg*/)
|
||||
{
|
||||
// FIX: not implemented.
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void pushName(Pool& pool, RegisterNameNode** stack, SparseSet& pushed, Uint32* nodeListPointer, RegisterName oldName, RegisterName newName)
|
||||
{
|
||||
RegisterNameNode& newNode = *new(pool) RegisterNameNode();
|
||||
|
||||
if (pushed.test(oldName))
|
||||
(*stack)->newName = newName;
|
||||
else {
|
||||
newNode.newName = newName;
|
||||
newNode.nextPushed = *nodeListPointer;
|
||||
*nodeListPointer = oldName;
|
||||
newNode.next = *stack;
|
||||
*stack = &newNode;
|
||||
pushed.set(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void PhiNodeRemover<RegisterPressure>::replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
// Initialize the local variables.
|
||||
//
|
||||
|
||||
// When we insert the copies we will also need to create new VirtualRegisters for
|
||||
// the insertion of temporaries. The maximum number of temporary register will not
|
||||
// exceed the number of phiNodes in the primitive graph.
|
||||
Uint32 nameCount = vrManager.getSize();
|
||||
Uint32 maxNameCount = nameCount;
|
||||
for (Uint32 n = 0; n < nNodes; n++)
|
||||
maxNameCount += nodes[n]->getPhiNodes().length();
|
||||
|
||||
// If the CFG contains some critical edges (backward edge which source has more than one
|
||||
// outgoing edge and destination has more than one incomimg edge) then we need the liveness
|
||||
// information to be able to insert temporary copies.
|
||||
RegisterPressure::Set* liveOut = NULL;
|
||||
if (splitCriticalEdges(controlGraph))
|
||||
liveOut = Liveness<LowRegisterPressure>::analysis(controlGraph, nameCount).liveOut;
|
||||
|
||||
DominatorGraph dGraph(controlGraph);
|
||||
|
||||
SparseSet pushed(pool, maxNameCount);
|
||||
SparseSet destinationList(pool, maxNameCount);
|
||||
SparseSet workList(pool, maxNameCount);
|
||||
|
||||
CopyData* copyStats = new(pool) CopyData[maxNameCount];
|
||||
memset(copyStats, '\0', maxNameCount*sizeof(CopyData));
|
||||
|
||||
struct NodeStack {
|
||||
Uint32* next;
|
||||
Uint32* limit;
|
||||
Uint32 pushedList;
|
||||
};
|
||||
|
||||
// Allocate the node stack and initialize the node stack pointer.
|
||||
NodeStack* nodeStack = new(pool) NodeStack[nNodes + 1];
|
||||
NodeStack* nodeStackPtr = nodeStack;
|
||||
|
||||
// We start by the begin node.
|
||||
Uint32 startNode = 0;
|
||||
Uint32* next = &startNode;
|
||||
Uint32* limit = &startNode + 1;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (next == limit) {
|
||||
// If there are no more node in the sibling, we have to pop the current
|
||||
// frame from the stack and update the copyStats of the pushed nodes.
|
||||
//
|
||||
if (nodeStackPtr == nodeStack)
|
||||
// We are at the bottom of the stack and there are no more nodes
|
||||
// to look at. We are done !
|
||||
break;
|
||||
|
||||
--nodeStackPtr;
|
||||
// We are done with all the children of this node in the dominator tree.
|
||||
// We need to update the copy information of all the new names pushed
|
||||
// during the walk over this node.
|
||||
Uint32 pushedList = nodeStackPtr->pushedList;
|
||||
while (pushedList != 0) {
|
||||
Uint32 nextName = copyStats[pushedList].newName->nextPushed;
|
||||
copyStats[pushedList].newName = copyStats[pushedList].newName->next;
|
||||
pushedList = nextName;
|
||||
}
|
||||
|
||||
// restore the previous frame.
|
||||
next = nodeStackPtr->next;
|
||||
limit = nodeStackPtr->limit;
|
||||
} else {
|
||||
Uint32 currentNode = *next++;
|
||||
Uint32 pushedList = 0;
|
||||
|
||||
|
||||
// Initialize the sets.
|
||||
pushed.clear();
|
||||
destinationList.clear();
|
||||
|
||||
// STEP1:
|
||||
// Walk the instruction list and to replace all the instruction uses with their new name.
|
||||
// If the instruction is a phi node and its defined register is alive at the end of this
|
||||
// block then we push the defined register into the stack.
|
||||
//
|
||||
ControlNode& node = *nodes[currentNode];
|
||||
RegisterPressure::Set* currentLiveOut = (liveOut != NULL) ? &liveOut[currentNode] : (RegisterPressure::Set*) 0;
|
||||
|
||||
InstructionList& phiNodes = node.getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
|
||||
assert(usePtr->isRegister());
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
|
||||
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
|
||||
usePtr->setRegisterName(copyStats[name].newName->newName);
|
||||
}
|
||||
|
||||
if (currentLiveOut != NULL) {
|
||||
// This is a phi node and we have to push its defined name if it is live
|
||||
// at the end of the node. We only need to do this if the CFG has critical edges.
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
|
||||
RegisterName name = phiNode.getInstructionDefineBegin()[0].getRegisterName();
|
||||
|
||||
if (currentLiveOut->test(name))
|
||||
pushName(pool, &(copyStats[name].newName), pushed, &pushedList, name, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
|
||||
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
|
||||
usePtr->setRegisterName(copyStats[name].newName->newName);
|
||||
}
|
||||
}
|
||||
|
||||
// STEP2:
|
||||
// Look at this node's successors' phiNodes. We keep track of the number of time
|
||||
// a VR will be used by another copy instruction and insert each definition into the
|
||||
// destinationList. This is the only pass over this node's successors as we will
|
||||
// get all the information we need in the CopyData structures.
|
||||
//
|
||||
ControlEdge* successorEdgeEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorEdgePtr = node.getSuccessorsBegin(); successorEdgePtr < successorEdgeEnd; successorEdgePtr++) {
|
||||
Uint32 useIndex = successorEdgePtr->getIndex();
|
||||
ControlNode& successor = successorEdgePtr->getTarget();
|
||||
|
||||
// Look at its phi nodes. The phi nodes are at the top of the instruction list. We exit
|
||||
// as soon as we find an instruction which is not a phi node
|
||||
InstructionList& phiNodes = successor.getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& phiNode = phiNodes.get(p);
|
||||
|
||||
assert((phiNode.getInstructionUseBegin() + useIndex) < phiNode.getInstructionUseEnd());
|
||||
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd());
|
||||
|
||||
InstructionUse& source = phiNode.getInstructionUseBegin()[useIndex];
|
||||
InstructionDefine& destination = phiNode.getInstructionDefineBegin()[0];
|
||||
|
||||
assert(source.isRegister() && destination.isRegister());
|
||||
|
||||
RegisterName sourceName = source.getRegisterName();
|
||||
RegisterName destinationName = destination.getRegisterName();
|
||||
|
||||
// Get the correct name for the source.
|
||||
if (copyStats[sourceName].newName != NULL)
|
||||
sourceName = copyStats[sourceName].newName->newName;
|
||||
|
||||
// Update the CopyData structures.
|
||||
if ((sourceName != rnInvalid) && (sourceName != destinationName)) {
|
||||
copyStats[destinationName].source = sourceName;
|
||||
copyStats[destinationName].classKind = destination.getRegisterClass();
|
||||
copyStats[destinationName].isLiveOut = (currentLiveOut != NULL) ? currentLiveOut->test(destinationName) : false;
|
||||
copyStats[destinationName].sourceNameToUse = destinationName;
|
||||
copyStats[sourceName].sourceNameToUse = sourceName;
|
||||
copyStats[sourceName].useCount++;
|
||||
destinationList.set(destinationName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// STEP3:
|
||||
// Insert into the worklist only the destination registers that will be not used in
|
||||
// another copy instruction in this block.
|
||||
//
|
||||
assert(workList.getSize() == 0);
|
||||
for (SparseSet::iterator d = destinationList.begin(); !destinationList.done(d); d = destinationList.advance(d)) {
|
||||
Uint32 dest = destinationList.get(d);
|
||||
if (copyStats[dest].useCount == 0)
|
||||
workList.set(dest);
|
||||
}
|
||||
|
||||
// STEP4:
|
||||
// Insert the copy instructions.
|
||||
//
|
||||
Uint32 destinationListSize = destinationList.getSize();
|
||||
InstructionList::iterator endOfTheNode = instructions.end();
|
||||
|
||||
// Find the right place to insert the copy instructions.
|
||||
if (destinationListSize != 0)
|
||||
while (instructions.get(endOfTheNode).getFlags() & ifControl)
|
||||
endOfTheNode = instructions.retreat(endOfTheNode);
|
||||
|
||||
while (destinationListSize != 0) {
|
||||
while(workList.getSize()) {
|
||||
RegisterName destinationName = RegisterName(workList.getOne());
|
||||
RegisterName sourceName = copyStats[destinationName].source;
|
||||
|
||||
workList.clear(destinationName);
|
||||
if (copyStats[destinationName].isLiveOut && !copyStats[destinationName].temporaryName) {
|
||||
// Lost copy problem.
|
||||
copyStats[destinationName].isLiveOut = false;
|
||||
|
||||
RegisterName sourceName = destinationName;
|
||||
RegisterClassKind classKind = copyStats[sourceName].classKind;
|
||||
RegisterName destinationName = getName(vrManager.newVirtualRegister(classKind));
|
||||
assert(destinationName < maxNameCount);
|
||||
|
||||
copyStats[destinationName].classKind = classKind;
|
||||
copyStats[sourceName].useCount = 0;
|
||||
|
||||
// We need to insert a copy to a temporary register to keep the
|
||||
// source register valid at the end of the node defining it.
|
||||
// This copy will be inserted right after the phi node defining it.
|
||||
RegisterName from = copyStats[sourceName].sourceNameToUse;
|
||||
Instruction* definingPhiNode = vrManager.getVirtualRegister(from).getDefiningInstruction();
|
||||
assert(definingPhiNode && (definingPhiNode->getFlags() & ifPhiNode) != 0);
|
||||
|
||||
RegisterID fromID = buildRegisterID(from, classKind);
|
||||
RegisterID toID = buildRegisterID(destinationName, classKind);
|
||||
Instruction& copy = emitter.newCopy(*definingPhiNode->getPrimitive(), fromID, toID);
|
||||
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
|
||||
definingPhiNode->getPrimitive()->getContainer()->getInstructions().addFirst(copy);
|
||||
|
||||
copyStats[sourceName].temporaryName = destinationName;
|
||||
copyStats[sourceName].sourceNameToUse = destinationName;
|
||||
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
|
||||
}
|
||||
|
||||
// Insert the copy instruction at the end of the current node.
|
||||
RegisterName from = copyStats[sourceName].sourceNameToUse;
|
||||
|
||||
RegisterClassKind classKind = copyStats[destinationName].classKind;
|
||||
RegisterID fromID = buildRegisterID(from, classKind);
|
||||
RegisterID toID = buildRegisterID(destinationName, classKind);
|
||||
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
|
||||
instructions.insertAfter(copy, endOfTheNode);
|
||||
endOfTheNode = instructions.advance(endOfTheNode);
|
||||
|
||||
copyStats[sourceName].useCount = 0;
|
||||
if (destinationList.test(sourceName) && copyStats[sourceName].isLiveOut)
|
||||
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
|
||||
copyStats[sourceName].isLiveOut = false;
|
||||
copyStats[sourceName].sourceNameToUse = destinationName;
|
||||
|
||||
if (destinationList.test(sourceName))
|
||||
workList.set(sourceName);
|
||||
destinationList.clear(destinationName);
|
||||
}
|
||||
|
||||
destinationListSize = destinationList.getSize();
|
||||
if (destinationListSize != 0) {
|
||||
RegisterName sourceName = RegisterName(destinationList.getOne());
|
||||
RegisterName destinationName;
|
||||
|
||||
if (!copyStats[sourceName].temporaryName) {
|
||||
// Cycle problem.
|
||||
RegisterClassKind classKind = copyStats[sourceName].classKind;
|
||||
destinationName = getName(vrManager.newVirtualRegister(classKind));
|
||||
assert(destinationName < maxNameCount);
|
||||
|
||||
copyStats[destinationName].classKind = classKind;
|
||||
copyStats[sourceName].temporaryName = destinationName;
|
||||
|
||||
// Insert the copy instruction at the end of the current node.
|
||||
RegisterName from = copyStats[sourceName].sourceNameToUse;
|
||||
|
||||
RegisterID fromID = buildRegisterID(from, classKind);
|
||||
RegisterID toID = buildRegisterID(destinationName, classKind);
|
||||
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
|
||||
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
|
||||
instructions.insertAfter(copy, endOfTheNode);
|
||||
endOfTheNode = instructions.advance(endOfTheNode);
|
||||
} else
|
||||
destinationName = copyStats[sourceName].temporaryName;
|
||||
|
||||
copyStats[sourceName].useCount = 0;
|
||||
copyStats[sourceName].isLiveOut = false;
|
||||
copyStats[sourceName].sourceNameToUse = destinationName;
|
||||
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
|
||||
|
||||
workList.set(sourceName);
|
||||
}
|
||||
}
|
||||
|
||||
nodeStackPtr->pushedList = pushedList;
|
||||
nodeStackPtr->next = next;
|
||||
nodeStackPtr->limit = limit;
|
||||
++nodeStackPtr;
|
||||
next = dGraph.getSuccessorsBegin(currentNode);
|
||||
limit = dGraph.getSuccessorsEnd(currentNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _PHI_NODE_REMOVER_H_
|
||||
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal file
155
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "LogModule.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterPressure.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
#include "PhiNodeRemover.h"
|
||||
#include "LiveRange.h"
|
||||
#include "Liveness.h"
|
||||
#include "InterferenceGraph.h"
|
||||
#include "LiveRangeGraph.h"
|
||||
#include "Coalescing.h"
|
||||
#include "Spilling.h"
|
||||
#include "Coloring.h"
|
||||
#include "Splits.h"
|
||||
|
||||
class Pool;
|
||||
class ControlGraph;
|
||||
class VirtualRegisterManager;
|
||||
class InstructionEmitter;
|
||||
|
||||
UT_DEFINE_LOG_MODULE(RegAlloc);
|
||||
|
||||
void RegisterAllocator::allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
|
||||
{
|
||||
// Insert the phi node instructions. We want to do this to have a single defined register per instruction.
|
||||
// If we keep the PhiNode (as a DataNode) and a PhiNode is of DoubleWordKind then we have to execute
|
||||
// some special code for the high word annotation.
|
||||
//
|
||||
RegisterAllocatorTools::insertPhiNodeInstructions(controlGraph, emitter);
|
||||
|
||||
// Perform some tests on the instruction graph.
|
||||
//
|
||||
DEBUG_ONLY(RegisterAllocatorTools::testTheInstructionGraph(controlGraph, vrManager));
|
||||
|
||||
// Replace the phi node instructions by their equivalent copy instructions.
|
||||
//
|
||||
PhiNodeRemover<LowRegisterPressure>::replacePhiNodes(controlGraph, vrManager, emitter);
|
||||
|
||||
// Do the register allocation.
|
||||
//
|
||||
RegisterAllocator registerAllocator(pool, controlGraph, vrManager, emitter);
|
||||
registerAllocator.doGraphColoring();
|
||||
}
|
||||
|
||||
void RegisterAllocator::doGraphColoring()
|
||||
{
|
||||
// Initialize the liverange map.
|
||||
//
|
||||
initLiveRanges();
|
||||
|
||||
// Build the live ranges. We do this to compress the number of RegisterNames
|
||||
// used in the insterference graph.
|
||||
//
|
||||
LiveRange<LowRegisterPressure>::build(*this);
|
||||
|
||||
// Remove unnecessary copies.
|
||||
//
|
||||
RegisterAllocatorTools::removeUnnecessaryCopies(*this);
|
||||
|
||||
for (Uint8 loop = 0; loop < 10; loop++) {
|
||||
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********* RegisterAllocator loop %d *********\n", loop));
|
||||
|
||||
while(true) {
|
||||
// Build the interference graph.
|
||||
//
|
||||
iGraph.build();
|
||||
|
||||
// Coalesce the copy instructions.
|
||||
//
|
||||
if (!Coalescing<LowRegisterPressure>::coalesce(*this))
|
||||
break;
|
||||
}
|
||||
|
||||
// Print the interference graph.
|
||||
//
|
||||
DEBUG_LOG_ONLY(iGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
|
||||
|
||||
// Calculate the spill costs.
|
||||
//
|
||||
Spilling<LowRegisterPressure>::calculateSpillCosts(*this);
|
||||
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSpillCosts(*this));
|
||||
|
||||
// Calculate the split costs.
|
||||
//
|
||||
Splits<LowRegisterPressure>::calculateSplitCosts(*this);
|
||||
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSplitCosts(*this));
|
||||
|
||||
// Build the live range graph.
|
||||
//
|
||||
lGraph.build();
|
||||
DEBUG_LOG_ONLY(lGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
|
||||
|
||||
// Color the graph. If it succeeds then we're done with the
|
||||
// register allocation.
|
||||
//
|
||||
if (Coloring<LowRegisterPressure>::color(*this)) {
|
||||
// Write the final colors in the instruction graph.
|
||||
//
|
||||
Coloring<LowRegisterPressure>::finalColoring(*this);
|
||||
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********** RegisterAllocator done **********\n"));
|
||||
DEBUG_LOG_ONLY(RegisterAllocatorTools::printInstructions(*this));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to spill some registers.
|
||||
//
|
||||
Spilling<LowRegisterPressure>::insertSpillCode(*this);
|
||||
|
||||
// Insert the split instructions.
|
||||
//
|
||||
Splits<LowRegisterPressure>::insertSplitCode(*this);
|
||||
|
||||
// Update the live ranges.
|
||||
//
|
||||
// FIX
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
RegisterAllocatorTools::updateInstructionGraph(*this);
|
||||
RegisterAllocatorTools::printInstructions(*this);
|
||||
#endif
|
||||
fprintf(stderr, "!!! Coloring failed after 10 loops !!!\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
void RegisterAllocator::initLiveRanges()
|
||||
{
|
||||
Uint32 count = this->nameCount;
|
||||
RegisterName* name2range = new(pool) RegisterName[nameCount];
|
||||
for (RegisterName r = RegisterName(1); r < count; r = RegisterName(r + 1))
|
||||
name2range[r] = r;
|
||||
this->name2range = name2range;
|
||||
rangeCount = count;
|
||||
}
|
||||
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal file
88
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocator.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_ALLOCATOR_H_
|
||||
#define _REGISTER_ALLOCATOR_H_
|
||||
|
||||
class Pool;
|
||||
class ControlGraph;
|
||||
class InstructionEmitter;
|
||||
struct SpillCost;
|
||||
struct SplitCost;
|
||||
|
||||
#include "Liveness.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "RegisterPressure.h" // This should included by Backend.cpp
|
||||
#include "InterferenceGraph.h"
|
||||
#include "LiveRangeGraph.h"
|
||||
|
||||
//template <class RegisterPressure>
|
||||
class RegisterAllocator
|
||||
{
|
||||
public:
|
||||
|
||||
Pool& pool; //
|
||||
ControlGraph& controlGraph; //
|
||||
VirtualRegisterManager& vrManager; //
|
||||
InstructionEmitter& emitter; //
|
||||
|
||||
RegisterName* name2range; //
|
||||
RegisterName* color; //
|
||||
SpillCost* spillCost; //
|
||||
SparseSet* willSpill; //
|
||||
SplitCost* splitCost; //
|
||||
NameLinkedList** splitAround; //
|
||||
InterferenceGraph<LowRegisterPressure> iGraph; //
|
||||
LiveRangeGraph<LowRegisterPressure> lGraph; //
|
||||
LivenessInfo<LowRegisterPressure> liveness; //
|
||||
Uint32 nameCount; //
|
||||
Uint32 rangeCount; //
|
||||
bool splitFound; //
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
//
|
||||
void doGraphColoring();
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
//
|
||||
inline RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
|
||||
|
||||
//
|
||||
//
|
||||
bool canInterfere(RegisterName /*name1*/, RegisterName /*name2*/) const {return true;}
|
||||
|
||||
//
|
||||
//
|
||||
void initLiveRanges();
|
||||
|
||||
//
|
||||
//
|
||||
static void allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
inline RegisterAllocator::RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
|
||||
: pool(pool), controlGraph(controlGraph), vrManager(vrManager), emitter(emitter), iGraph(*this), lGraph(*this), nameCount(vrManager.getSize()) {}
|
||||
|
||||
#endif // _REGISTER_ALLOCATOR_H_
|
||||
|
||||
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal file
355
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "LogModule.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Primitives.h"
|
||||
#include "InstructionEmitter.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "Spilling.h"
|
||||
#include "Splits.h"
|
||||
#include "BitSet.h"
|
||||
|
||||
UT_EXTERN_LOG_MODULE(RegAlloc);
|
||||
|
||||
#ifdef DEBUG
|
||||
void RegisterAllocatorTools::testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
|
||||
{
|
||||
// Test the declared VirtualRegisters. The register allocator tries to condense the register universe.
|
||||
// Any gap in the VirtualRegister names will be a loss of efficiency !!!!
|
||||
|
||||
Uint32 nameCount = vrManager.getSize();
|
||||
BitSet registerSeen(controlGraph.pool, nameCount);
|
||||
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
registerSeen.set(usePtr->getRegisterName());
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
registerSeen.set(definePtr->getRegisterName());
|
||||
}
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& instruction = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
registerSeen.set(usePtr->getRegisterName());
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
registerSeen.set(definePtr->getRegisterName());
|
||||
}
|
||||
}
|
||||
|
||||
bool renameRegisters = false;
|
||||
for (BitSet::iterator i = registerSeen.nextZero(0); !registerSeen.done(i); i = registerSeen.nextZero(i)) {
|
||||
renameRegisters = true;
|
||||
fprintf(stderr,
|
||||
"WARNING: The VirtualRegister vr%d has been allocated during CodeGeneration but\n"
|
||||
" is never used nor defined by any instruction in the instruction graph\n"
|
||||
" PLEASE FIX \n",
|
||||
i);
|
||||
}
|
||||
if (renameRegisters) {
|
||||
Instruction** definingInstruction = new Instruction*[nameCount];
|
||||
memset(definingInstruction, '\0', nameCount * sizeof(Instruction*));
|
||||
RegisterName* newName = new RegisterName[nameCount];
|
||||
memset(newName, '\0', nameCount * sizeof(RegisterName));
|
||||
RegisterName nextName = RegisterName(1);
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
usePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName name = definePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
definePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
}
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& instruction = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName name = usePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
usePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName name = definePtr->getRegisterName();
|
||||
if (newName[name] == rnInvalid) {
|
||||
newName[name] = nextName;
|
||||
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
|
||||
nextName = RegisterName(nextName + 1);
|
||||
}
|
||||
definePtr->setRegisterName(newName[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vrManager.setSize(nextName);
|
||||
|
||||
for (RegisterName r = RegisterName(1); r < nextName; r = RegisterName(r + 1))
|
||||
vrManager.getVirtualRegister(r).definingInstruction = definingInstruction[r];
|
||||
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("RegisterMap:\n"));
|
||||
for (Uint32 i = 1; i < nameCount; i++)
|
||||
if (newName[i] != 0)
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d becomes vr%d.\n", i, newName[i]));
|
||||
else
|
||||
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d is dead.\n", i));
|
||||
|
||||
|
||||
delete newName;
|
||||
delete definingInstruction;
|
||||
}
|
||||
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void RegisterAllocatorTools::removeUnnecessaryCopies(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i);) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
i = instructions.advance(i);
|
||||
|
||||
if (instruction.getFlags() & ifCopy) {
|
||||
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
|
||||
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
|
||||
|
||||
RegisterName source = name2range[instruction.getInstructionUseBegin()[0].getRegisterName()];
|
||||
RegisterName destination = name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()];
|
||||
|
||||
if (source == destination)
|
||||
instruction.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocatorTools::updateInstructionGraph(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
|
||||
}
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
|
||||
Instruction& instruction = phiNodes.get(p);
|
||||
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
|
||||
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RegisterAllocatorTools::insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter)
|
||||
{
|
||||
Pool& pool = controlGraph.pool;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
|
||||
|
||||
if (!phiNodes.empty()) {
|
||||
|
||||
// Set the index of the incoming edges.
|
||||
Uint32 index = 0;
|
||||
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
|
||||
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p))
|
||||
predecessors.get(p).setIndex(index++);
|
||||
|
||||
// Insert the phi node instruction in the instruction list.
|
||||
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
||||
PhiNode& phiNode = phiNodes.get(i);
|
||||
ValueKind kind = phiNode.getKind();
|
||||
|
||||
if (!isStorableKind(kind))
|
||||
continue;
|
||||
|
||||
RegisterClassKind classKind = rckGeneral; // FIX: get class kind from phi node kind.
|
||||
Uint32 nInputs = phiNode.nInputs();
|
||||
|
||||
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
|
||||
|
||||
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drLow);
|
||||
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
|
||||
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drLow);
|
||||
|
||||
node.addPhiNodeInstruction(phiNodeInstruction);
|
||||
|
||||
if (isDoublewordKind(kind)) {
|
||||
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
|
||||
|
||||
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drHigh);
|
||||
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
|
||||
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drHigh);
|
||||
|
||||
node.addPhiNodeInstruction(phiNodeInstruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
|
||||
void RegisterAllocatorTools::printSpillCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
SpillCost* cost = registerAllocator.spillCost;
|
||||
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Spill costs:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : ", i));
|
||||
if (cost[i].infinite)
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("infinite\n"));
|
||||
else
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%f\n", cost[i].cost));
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterAllocatorTools::printSplitCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
SplitCost* cost = registerAllocator.splitCost;
|
||||
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Split costs:\n"));
|
||||
for (Uint32 i = 1; i < rangeCount; i++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : loads = %f stores = %f\n", i, cost[i].loads, cost[i].stores));
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterAllocatorTools::printInstructions(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
|
||||
ControlNode** nodes = registerAllocator.controlGraph.dfsList;
|
||||
Uint32 nNodes = registerAllocator.controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d:\n", n));
|
||||
|
||||
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
|
||||
if (!phiNodes.empty()) {
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" PhiNodes:\n", n));
|
||||
for(InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
|
||||
phiNodes.get(i).printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
if (!instructions.empty())
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" Instructions:\n", n));
|
||||
}
|
||||
|
||||
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
|
||||
instructions.get(i).printPretty(log);
|
||||
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal file
117
mozilla/ef/Compiler/RegisterAllocator/RegisterAllocatorTools.h
Normal file
@@ -0,0 +1,117 @@
|
||||
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
|
||||
//
|
||||
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
|
||||
// NETSCAPE COMMUNICATIONS CORPORATION
|
||||
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
|
||||
// Reserved. Use of this Source Code is subject to the terms of the
|
||||
// applicable license agreement from Netscape Communications Corporation.
|
||||
// The copyright notice(s) in this Source Code does not indicate actual or
|
||||
// intended publication of this Source Code.
|
||||
//
|
||||
// $Id: RegisterAllocatorTools.h,v 1.1.2.1 1999-03-02 16:12:05 fur%netscape.com Exp $
|
||||
//
|
||||
|
||||
#ifndef _REGISTER_ALLOCATOR_TOOLS_H_
|
||||
#define _REGISTER_ALLOCATOR_TOOLS_H_
|
||||
|
||||
#include "LogModule.h"
|
||||
#include "RegisterTypes.h"
|
||||
#include <string.h>
|
||||
|
||||
class RegisterAllocator;
|
||||
class ControlGraph;
|
||||
class InstructionEmitter;
|
||||
class VirtualRegisterManager;
|
||||
|
||||
struct RegisterAllocatorTools
|
||||
{
|
||||
//
|
||||
//
|
||||
static void insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter);
|
||||
|
||||
//
|
||||
//
|
||||
static void updateInstructionGraph(RegisterAllocator& registerAllocator);
|
||||
|
||||
//
|
||||
//
|
||||
static void removeUnnecessaryCopies(RegisterAllocator& registerAllocator);
|
||||
|
||||
#ifdef DEBUG
|
||||
//
|
||||
//
|
||||
static void testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
|
||||
#endif // DEBUG
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
//
|
||||
//
|
||||
static void printInstructions(RegisterAllocator& registerAllocator);
|
||||
|
||||
//
|
||||
//
|
||||
static void printSpillCosts(RegisterAllocator& registerAllocator);
|
||||
|
||||
//
|
||||
//
|
||||
static void printSplitCosts(RegisterAllocator& registerAllocator);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
//
|
||||
// FIX: this should go in a class (LookupTable ?)
|
||||
//
|
||||
|
||||
inline RegisterName findRoot(RegisterName name, RegisterName* table)
|
||||
{
|
||||
RegisterName* stack = table;
|
||||
RegisterName* stackPtr = stack;
|
||||
|
||||
RegisterName newName;
|
||||
while((newName = table[name]) != name) {
|
||||
*--stackPtr = name;
|
||||
name = newName;
|
||||
}
|
||||
|
||||
while (stackPtr != stack)
|
||||
table[*stackPtr++] = name;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
inline void init(RegisterName* table, Uint32 nameCount)
|
||||
{
|
||||
for (RegisterName r = RegisterName(0); r < nameCount; r = RegisterName(r + 1))
|
||||
table[r] = r;
|
||||
}
|
||||
|
||||
inline Uint32 compress(RegisterName* name2range, RegisterName* table, Uint32 nameCount, Uint32 tableSize)
|
||||
{
|
||||
RegisterName* liveRange = new RegisterName[tableSize];
|
||||
memset(liveRange, '\0', tableSize * sizeof(RegisterName));
|
||||
|
||||
// Update the lookup table.
|
||||
for (RegisterName r = RegisterName(1); r < tableSize; r = RegisterName(r + 1))
|
||||
findRoot(r, table);
|
||||
|
||||
// Count the liveranges.
|
||||
Uint32 liveRangeCount = 1;
|
||||
for (RegisterName s = RegisterName(1); s < tableSize; s = RegisterName(s + 1))
|
||||
if (table[s] == s)
|
||||
liveRange[s] = RegisterName(liveRangeCount++);
|
||||
|
||||
for (RegisterName t = RegisterName(1); t < nameCount; t = RegisterName(t + 1))
|
||||
name2range[t] = liveRange[table[name2range[t]]];
|
||||
|
||||
return liveRangeCount;
|
||||
}
|
||||
|
||||
inline double doLog10(Uint32 power)
|
||||
{
|
||||
double log = 1.0;
|
||||
while (power--)
|
||||
log *= 10.0;
|
||||
return log;
|
||||
}
|
||||
|
||||
#endif // _REGISTER_ALLOCATOR_TOOLS_H_
|
||||
38
mozilla/ef/Compiler/RegisterAllocator/RegisterAssigner.h
Normal file
38
mozilla/ef/Compiler/RegisterAllocator/RegisterAssigner.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_ASSIGNER_H_
|
||||
#define _REGISTER_ASSIGNER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
|
||||
class FastBitMatrix;
|
||||
|
||||
class RegisterAssigner
|
||||
{
|
||||
protected:
|
||||
VirtualRegisterManager& vRegManager;
|
||||
|
||||
public:
|
||||
RegisterAssigner(VirtualRegisterManager& vrMan) : vRegManager(vrMan) {}
|
||||
|
||||
virtual bool assignRegisters(FastBitMatrix& interferenceMatrix) = 0;
|
||||
};
|
||||
|
||||
#endif /* _REGISTER_ASSIGNER_H_ */
|
||||
25
mozilla/ef/Compiler/RegisterAllocator/RegisterClass.h
Normal file
25
mozilla/ef/Compiler/RegisterAllocator/RegisterClass.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_CLASS_H_
|
||||
#define _REGISTER_CLASS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "RegisterTypes.h"
|
||||
|
||||
#endif // _REGISTER_CLASS_H_
|
||||
37
mozilla/ef/Compiler/RegisterAllocator/RegisterPressure.h
Normal file
37
mozilla/ef/Compiler/RegisterAllocator/RegisterPressure.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_PRESSURE_H_
|
||||
#define _REGISTER_PRESSURE_H_
|
||||
|
||||
#include "BitSet.h"
|
||||
#include "HashSet.h"
|
||||
|
||||
struct LowRegisterPressure
|
||||
{
|
||||
typedef BitSet Set;
|
||||
static const bool setIsOrdered = true;
|
||||
};
|
||||
|
||||
struct HighRegisterPressure
|
||||
{
|
||||
typedef HashSet Set;
|
||||
static const bool setIsOrdered = false;
|
||||
};
|
||||
|
||||
#endif // _REGISTER_PRESSURE_H_
|
||||
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal file
104
mozilla/ef/Compiler/RegisterAllocator/RegisterTypes.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _REGISTER_TYPES_H_
|
||||
#define _REGISTER_TYPES_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterName -
|
||||
//
|
||||
|
||||
enum RegisterName {
|
||||
rnInvalid = 0,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterClassKind -
|
||||
//
|
||||
|
||||
enum RegisterClassKind {
|
||||
rckInvalid = 0,
|
||||
rckGeneral,
|
||||
rckStackSlot,
|
||||
|
||||
nRegisterClassKind
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterID -
|
||||
//
|
||||
|
||||
enum RegisterID {
|
||||
invalidID = 0
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// RegisterKind -
|
||||
//
|
||||
|
||||
enum RegisterKind {
|
||||
rkCallerSave = 0,
|
||||
rkCalleeSave,
|
||||
};
|
||||
|
||||
struct NameLinkedList {
|
||||
RegisterName name;
|
||||
NameLinkedList* next;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
const registerNameMask = 0x03ffffff;
|
||||
const coloredRegisterMask = 0x04000000;
|
||||
const machineRegisterMask = 0x08000000;
|
||||
const registerClassMask = 0xf0000000;
|
||||
|
||||
const registerNameShift = 0;
|
||||
const coloredRegisterShift = 26;
|
||||
const machineRegisterShift = 27;
|
||||
const registerClassShift = 28;
|
||||
|
||||
#else // DEBUG
|
||||
|
||||
const registerNameMask = 0x0fffffff;
|
||||
const registerClassMask = 0xf0000000;
|
||||
|
||||
const registerNameShift = 0;
|
||||
const registerClassShift = 28;
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
|
||||
inline RegisterClassKind getClass(RegisterID registerID) {return RegisterClassKind((registerID & registerClassMask) >> registerClassShift);}
|
||||
inline RegisterName getName(RegisterID registerID) {return RegisterName((registerID & registerNameMask) >> registerNameShift);}
|
||||
inline void setClass(RegisterID& registerID, RegisterClassKind classKind) {registerID = RegisterID((registerID & ~registerClassMask) | ((classKind << registerClassShift) & registerClassMask));}
|
||||
inline void setName(RegisterID& registerID, RegisterName name) {assert((name & ~registerNameMask) == 0); registerID = RegisterID((registerID & ~registerNameMask) | ((name << registerNameShift) & registerNameMask));}
|
||||
inline RegisterID buildRegisterID(RegisterName name, RegisterClassKind classKind) {return RegisterID(((classKind << registerClassShift) & registerClassMask) | ((name << registerNameShift) & registerNameMask));}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
inline bool isMachineRegister(RegisterID rid) {return (rid & machineRegisterMask) != 0;}
|
||||
inline void setMachineRegister(RegisterID& rid) {rid = RegisterID(rid | machineRegisterMask);}
|
||||
inline bool isColoredRegister(RegisterID rid) {return (rid & coloredRegisterMask) != 0;}
|
||||
inline void setColoredRegister(RegisterID& rid) {rid = RegisterID(rid | coloredRegisterMask);}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
#endif // _REGISTER_TYPES_H_
|
||||
32
mozilla/ef/Compiler/RegisterAllocator/SSATools.cpp
Normal file
32
mozilla/ef/Compiler/RegisterAllocator/SSATools.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "SSATools.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "Liveness.h"
|
||||
|
||||
void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
|
||||
{
|
||||
if (!controlGraph.hasBackEdges)
|
||||
return;
|
||||
|
||||
Liveness liveness(controlGraph.pool);
|
||||
liveness.buildLivenessAnalysis(controlGraph, vrManager);
|
||||
}
|
||||
29
mozilla/ef/Compiler/RegisterAllocator/SSATools.h
Normal file
29
mozilla/ef/Compiler/RegisterAllocator/SSATools.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SSA_TOOLS_H_
|
||||
#define _SSA_TOOLS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
|
||||
class ControlGraph;
|
||||
class VirtualRegisterManager;
|
||||
|
||||
extern void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
|
||||
|
||||
#endif // _SSA_TOOLS_H_
|
||||
37
mozilla/ef/Compiler/RegisterAllocator/SparseSet.cpp
Normal file
37
mozilla/ef/Compiler/RegisterAllocator/SparseSet.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "SparseSet.h"
|
||||
#include "BitSet.h"
|
||||
#include "Pool.h"
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the set.
|
||||
//
|
||||
void SparseSet::printPretty(LogModuleObject log)
|
||||
{
|
||||
Pool pool;
|
||||
BitSet set(pool, universeSize);
|
||||
|
||||
for (Uint32 i = 0; i < count; i++)
|
||||
set.set(node[i].element);
|
||||
|
||||
set.printPretty(log);
|
||||
}
|
||||
#endif // DEBUG_LOG
|
||||
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal file
168
mozilla/ef/Compiler/RegisterAllocator/SparseSet.h
Normal file
@@ -0,0 +1,168 @@
|
||||
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
|
||||
//
|
||||
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
|
||||
// NETSCAPE COMMUNICATIONS CORPORATION
|
||||
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
|
||||
// Reserved. Use of this Source Code is subject to the terms of the
|
||||
// applicable license agreement from Netscape Communications Corporation.
|
||||
// The copyright notice(s) in this Source Code does not indicate actual or
|
||||
// intended publication of this Source Code.
|
||||
//
|
||||
// $Id: SparseSet.h,v 1.1.2.1 1999-03-02 16:12:07 fur%netscape.com Exp $
|
||||
//
|
||||
|
||||
#ifndef _SPARSE_SET_H_
|
||||
#define _SPARSE_SET_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "Pool.h"
|
||||
#include "LogModule.h"
|
||||
#include "BitSet.h"
|
||||
|
||||
class SparseSet
|
||||
{
|
||||
private:
|
||||
|
||||
struct Node {
|
||||
Uint32 element;
|
||||
Uint32 stackIndex;
|
||||
};
|
||||
|
||||
Node* node;
|
||||
Uint32 count;
|
||||
Uint32 universeSize;
|
||||
|
||||
private:
|
||||
|
||||
// No copy constructor.
|
||||
SparseSet(const SparseSet&);
|
||||
|
||||
// Check if the given set's universe is of the same size than this universe.
|
||||
void checkUniverseCompatibility(const SparseSet& set) const {assert(set.universeSize == universeSize);}
|
||||
// Check if pos is valid for this set's universe.
|
||||
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
|
||||
|
||||
public:
|
||||
|
||||
SparseSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {node = new(pool) Node[universeSize]; clear();}
|
||||
|
||||
// Clear the sparse set.
|
||||
void clear() {count = 0;}
|
||||
// Clear the element at index.
|
||||
inline void clear(Uint32 index);
|
||||
// Set the element at index.
|
||||
inline void set(Uint32 index);
|
||||
// Return true if the element at index is set.
|
||||
inline bool test(Uint32 index) const;
|
||||
// Union with the given sparse set.
|
||||
inline void or(const SparseSet& set);
|
||||
// Intersection with the given sparse set.
|
||||
inline void and(const SparseSet& set);
|
||||
// Difference with the given sparse set.
|
||||
inline void difference(const SparseSet& set);
|
||||
// Copy set.
|
||||
inline SparseSet& operator = (const SparseSet& set);
|
||||
inline SparseSet& operator = (const BitSet& set);
|
||||
// Return true if the sparse sets are identical.
|
||||
friend bool operator == (const SparseSet& set1, const SparseSet& set2);
|
||||
// Return true if the sparse sets are different.
|
||||
friend bool operator != (const SparseSet& set1, const SparseSet& set2);
|
||||
|
||||
// Logical operators.
|
||||
SparseSet& operator |= (const SparseSet& set) {or(set); return *this;}
|
||||
SparseSet& operator &= (const SparseSet& set) {and(set); return *this;}
|
||||
SparseSet& operator -= (const SparseSet& set) {difference(set); return *this;}
|
||||
|
||||
// Iterator to conform with the set API.
|
||||
typedef Int32 iterator;
|
||||
// Return the iterator for the first element of this set.
|
||||
iterator begin() const {return count - 1;}
|
||||
// Return the next iterator.
|
||||
iterator advance(iterator pos) const {return --pos;}
|
||||
// Return true if the iterator is at the end of the set.
|
||||
bool done(iterator pos) const {return pos < 0;}
|
||||
// Return the element for the given iterator;
|
||||
Uint32 get(iterator pos) const {return node[pos].element;}
|
||||
// Return one element of this set.
|
||||
Uint32 getOne() const {assert(count > 0); return node[0].element;}
|
||||
// Return the size of this set.
|
||||
Uint32 getSize() const {return count;}
|
||||
|
||||
#ifdef DEBUG_LOG
|
||||
// Print the set.
|
||||
void printPretty(LogModuleObject log);
|
||||
#endif // DEBUG_LOG
|
||||
};
|
||||
|
||||
inline void SparseSet::clear(Uint32 element)
|
||||
{
|
||||
checkMember(element);
|
||||
Uint32 count = this->count;
|
||||
Node* node = this->node;
|
||||
|
||||
Uint32 stackIndex = node[element].stackIndex;
|
||||
|
||||
if ((stackIndex < count) && (node[stackIndex].element == element)) {
|
||||
Uint32 stackTop = node[count - 1].element;
|
||||
|
||||
node[stackIndex].element = stackTop;
|
||||
node[stackTop].stackIndex = stackIndex;
|
||||
this->count = count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline void SparseSet::set(Uint32 element)
|
||||
{
|
||||
checkMember(element);
|
||||
Uint32 count = this->count;
|
||||
Node* node = this->node;
|
||||
|
||||
Uint32 stackIndex = node[element].stackIndex;
|
||||
|
||||
if ((stackIndex >= count) || (node[stackIndex].element != element)) {
|
||||
node[count].element = element;
|
||||
node[element].stackIndex = count;
|
||||
this->count = count + 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool SparseSet::test(Uint32 element) const
|
||||
{
|
||||
checkMember(element);
|
||||
Node* node = this->node;
|
||||
|
||||
Uint32 stackIndex = node[element].stackIndex;
|
||||
return ((stackIndex < count) && (node[stackIndex].element == element));
|
||||
}
|
||||
|
||||
inline SparseSet& SparseSet::operator = (const SparseSet& set)
|
||||
{
|
||||
checkUniverseCompatibility(set);
|
||||
Uint32 sourceCount = set.getSize();
|
||||
Node* node = this->node;
|
||||
|
||||
memcpy(node, set.node, sourceCount * sizeof(Node));
|
||||
|
||||
for (Uint32 i = 0; i < sourceCount; i++) {
|
||||
Uint32 element = node[i].element;
|
||||
node[element].stackIndex = i;
|
||||
}
|
||||
|
||||
count = sourceCount;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline SparseSet& SparseSet::operator = (const BitSet& set)
|
||||
{
|
||||
// FIX: there's room for optimization here.
|
||||
assert(universeSize == set.getSize());
|
||||
|
||||
clear();
|
||||
for (Int32 i = set.firstOne(); i != -1; i = set.nextOne(i))
|
||||
this->set(i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // _SPARSE_SET_H_
|
||||
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal file
270
mozilla/ef/Compiler/RegisterAllocator/Spilling.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef NEW_LAURENTM_CODE
|
||||
#define INCLUDE_EMITTER
|
||||
#include "CpuInfo.h"
|
||||
#include "Fundamentals.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "InstructionEmitter.h"
|
||||
#include "Spilling.h"
|
||||
|
||||
|
||||
void Spilling::
|
||||
insertSpillCode(ControlNode** dfsList, Uint32 nNodes)
|
||||
{
|
||||
PRUint32 nVirtualRegisters = vRegManager.count();
|
||||
FastBitSet currentLive(vRegManager.pool, nVirtualRegisters);
|
||||
FastBitSet usedInThisInstruction(vRegManager.pool, nVirtualRegisters);
|
||||
RegisterFifo grNeedLoad(nVirtualRegisters);
|
||||
RegisterFifo fpNeedLoad(nVirtualRegisters);
|
||||
|
||||
for (PRInt32 n = nNodes - 1; n >= 0; n--)
|
||||
{
|
||||
PR_ASSERT(grNeedLoad.empty() & fpNeedLoad.empty());
|
||||
ControlNode& node = *dfsList[n];
|
||||
|
||||
currentLive = node.liveAtEnd;
|
||||
|
||||
PRUint32 nGeneralAlive = 0;
|
||||
PRUint32 nFloatingPointAlive = 0;
|
||||
|
||||
// Get the number of registers alive at the end of this node.
|
||||
for (PRInt32 j = currentLive.firstOne(); j != -1; j = currentLive.nextOne(j))
|
||||
{
|
||||
VirtualRegister& vReg = vRegManager.getVirtualRegister(j);
|
||||
if (vReg.spillInfo.willSpill)
|
||||
{
|
||||
currentLive.clear(j);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
nGeneralAlive++;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
nFloatingPointAlive++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if(node.dfsNum == 8) printf("\n________Begin Node %d________\n", node.dfsNum);
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i))
|
||||
{
|
||||
Instruction& instruction = instructions.get(i);
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* defPtr;
|
||||
|
||||
// if(node.dfsNum == 8) { printf("\n");
|
||||
// instruction.printPretty(stdout);
|
||||
// printf("\n"); }
|
||||
|
||||
// Handle definitions
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = defPtr->getVirtualRegister();
|
||||
currentLive.clear(vReg.getRegisterIndex());
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
nGeneralAlive--;
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
nFloatingPointAlive--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for deaths
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = usePtr->getVirtualRegister();
|
||||
if (!currentLive.test(vReg.getRegisterIndex()))
|
||||
// This is the last use of this register.
|
||||
{
|
||||
currentLive.set(vReg.getRegisterIndex());
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
nGeneralAlive++;
|
||||
while (/*(nGeneralAlive > NUMBER_OF_GREGISTERS) &&*/ !grNeedLoad.empty())
|
||||
{
|
||||
PRUint32 toLoad = grNeedLoad.get();
|
||||
currentLive.clear(toLoad);
|
||||
nGeneralAlive--;
|
||||
|
||||
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
|
||||
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
|
||||
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
|
||||
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
|
||||
nReg.releaseSelf();
|
||||
}
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
nFloatingPointAlive++;
|
||||
while (/*(nFloatingPointAlive > NUMBER_OF_FPREGISTERS) &&*/ !fpNeedLoad.empty())
|
||||
{
|
||||
PRUint32 toLoad = fpNeedLoad.get();
|
||||
currentLive.clear(toLoad);
|
||||
nFloatingPointAlive--;
|
||||
|
||||
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
|
||||
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
|
||||
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
|
||||
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
|
||||
nReg.releaseSelf();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle uses
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = usePtr->getVirtualRegister();
|
||||
PRUint32 registerIndex = vReg.getRegisterIndex();
|
||||
|
||||
if (vReg.spillInfo.willSpill) {
|
||||
#if defined(GENERATE_FOR_X86)
|
||||
if (!instruction.switchUseToSpill((usePtr - useBegin), *vReg.equivalentRegister[vrcStackSlot]))
|
||||
#endif
|
||||
{
|
||||
switch (vReg.getClass())
|
||||
{
|
||||
case vrcInteger:
|
||||
if (!grNeedLoad.test(registerIndex))
|
||||
{
|
||||
grNeedLoad.put(registerIndex);
|
||||
VirtualRegister& alias = vRegManager.newVirtualRegister(vrcInteger);
|
||||
if (vReg.isPreColored())
|
||||
alias.preColorRegister(vReg.getPreColor());
|
||||
/* if (vReg.hasSpecialInterference) {
|
||||
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
|
||||
alias.specialInterference = vReg.specialInterference;
|
||||
alias.hasSpecialInterference = true;
|
||||
} */
|
||||
vReg.setAlias(alias);
|
||||
vReg.retainSelf();
|
||||
}
|
||||
break;
|
||||
case vrcFloatingPoint:
|
||||
case vrcFixedPoint:
|
||||
if (!fpNeedLoad.test(registerIndex))
|
||||
{
|
||||
fpNeedLoad.put(registerIndex);
|
||||
VirtualRegister& alias = vRegManager.newVirtualRegister(vReg.getClass());
|
||||
if (vReg.isPreColored())
|
||||
alias.preColorRegister(vReg.getPreColor());
|
||||
/*if (vReg.hasSpecialInterference) {
|
||||
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
|
||||
alias.specialInterference = vReg.specialInterference;
|
||||
alias.hasSpecialInterference = true;
|
||||
} */
|
||||
vReg.setAlias(alias);
|
||||
vReg.retainSelf();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
usePtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
|
||||
usedInThisInstruction.set(registerIndex);
|
||||
vReg.spillInfo.lastUsingInstruction = &instruction;
|
||||
}
|
||||
currentLive.clear(registerIndex);
|
||||
} else { // will not spill
|
||||
currentLive.set(registerIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle definitions
|
||||
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
|
||||
if (defPtr->isVirtualRegister())
|
||||
{
|
||||
VirtualRegister& vReg = defPtr->getVirtualRegister();
|
||||
|
||||
if (vReg.spillInfo.willSpill)
|
||||
#if defined(GENERATE_FOR_X86)
|
||||
if (!instruction.switchDefineToSpill((defPtr - defBegin), *vReg.equivalentRegister[vrcStackSlot]))
|
||||
#endif
|
||||
{
|
||||
if (usedInThisInstruction.test(vReg.getRegisterIndex()))
|
||||
// this virtualRegister was used in this instruction and is also defined. We need to move
|
||||
// this virtual register to its alias first and then save it to memory.
|
||||
{
|
||||
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
|
||||
vReg.getAlias(), *vReg.equivalentRegister[vrcStackSlot]);
|
||||
defPtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
|
||||
}
|
||||
else
|
||||
{
|
||||
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
|
||||
vReg, *vReg.equivalentRegister[vrcStackSlot]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!grNeedLoad.empty())
|
||||
{
|
||||
PRUint32 nl = grNeedLoad.get();
|
||||
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
|
||||
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
|
||||
|
||||
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
|
||||
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
|
||||
nlReg.releaseSelf();
|
||||
}
|
||||
while (!fpNeedLoad.empty())
|
||||
{
|
||||
PRUint32 nl = fpNeedLoad.get();
|
||||
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
|
||||
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
|
||||
|
||||
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
|
||||
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
|
||||
nlReg.releaseSelf();
|
||||
}
|
||||
|
||||
// if(node.dfsNum == 8) printf("\n________End Node %d________\n", node.dfsNum);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal file
269
mozilla/ef/Compiler/RegisterAllocator/Spilling.h
Normal file
@@ -0,0 +1,269 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SPILLING_H_
|
||||
#define _SPILLING_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "SparseSet.h"
|
||||
|
||||
template <class RegisterPressure>
|
||||
class Spilling
|
||||
{
|
||||
private:
|
||||
static void insertStoreAfter(Instruction& instruction, RegisterName name);
|
||||
static void insertLoadBefore(Instruction& instruction, RegisterName name);
|
||||
|
||||
public:
|
||||
static void calculateSpillCosts(RegisterAllocator& registerAllocator);
|
||||
static void insertSpillCode(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
struct SpillCost
|
||||
{
|
||||
double loads;
|
||||
double stores;
|
||||
double copies;
|
||||
double cost;
|
||||
bool infinite;
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::insertSpillCode(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet currentLive(pool, rangeCount);
|
||||
SparseSet needLoad(pool, rangeCount);
|
||||
SparseSet mustSpill(pool, rangeCount);
|
||||
SparseSet& willSpill = *registerAllocator.willSpill;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
|
||||
needLoad.clear();
|
||||
currentLive = liveOut[n];
|
||||
mustSpill = currentLive;
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i);) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
i = instructions.retreat(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
bool foundLiveDefine = false;
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
if (currentLive.test(name2range[definePtr->getRegisterName()])) {
|
||||
foundLiveDefine = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
foundLiveDefine = true;
|
||||
break;
|
||||
}
|
||||
if (defineBegin != defineEnd && !foundLiveDefine) {
|
||||
fprintf(stderr, "!!! Removed instruction because it was only defining unused registers !!!\n");
|
||||
instruction.remove();
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName range = name2range[definePtr->getRegisterName()];
|
||||
#ifdef DEBUG
|
||||
if (needLoad.test(range))
|
||||
if (!mustSpill.test(range) && registerAllocator.spillCost[range].infinite && willSpill.test(range)) {
|
||||
fprintf(stderr, "Tried to spill a register with infinite spill cost\n");
|
||||
abort();
|
||||
}
|
||||
#endif // DEBUG
|
||||
if (willSpill.test(range))
|
||||
insertStoreAfter(instruction, range);
|
||||
|
||||
needLoad.clear(range);
|
||||
}
|
||||
|
||||
if (instruction.getFlags() & ifCopy)
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
if (!currentLive.test(range))
|
||||
for (SparseSet::iterator r = needLoad.begin(); !needLoad.done(r); r = needLoad.advance(r)) {
|
||||
RegisterName load = RegisterName(needLoad.get(r));
|
||||
if (willSpill.test(load))
|
||||
insertLoadBefore(instruction, load);
|
||||
mustSpill.set(load);
|
||||
}
|
||||
needLoad.clear();
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
currentLive.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
currentLive.set(range);
|
||||
needLoad.set(range);
|
||||
}
|
||||
}
|
||||
|
||||
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
|
||||
RegisterName load = RegisterName(needLoad.get(l));
|
||||
if (willSpill.test(load))
|
||||
insertLoadBefore(instructions.first(), load);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::insertLoadBefore(Instruction& /*instruction*/, RegisterName name)
|
||||
{
|
||||
fprintf(stdout, "will insert load for range %d\n", name);
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::insertStoreAfter(Instruction& /*instruction*/, RegisterName name)
|
||||
{
|
||||
fprintf(stdout, "will insert store for range %d\n", name);
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Spilling<RegisterPressure>::calculateSpillCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
Pool& pool = registerAllocator.pool;
|
||||
SparseSet live(pool, rangeCount);
|
||||
SparseSet needLoad(pool, rangeCount);
|
||||
SparseSet mustSpill(pool, rangeCount);
|
||||
|
||||
SparseSet alreadyStored(pool, rangeCount); // FIX: should get this from previous spilling.
|
||||
|
||||
SpillCost* cost = new SpillCost[rangeCount];
|
||||
memset(cost, '\0', rangeCount * sizeof(SpillCost));
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
|
||||
double weight = doLog10(node.loopDepth);
|
||||
|
||||
needLoad.clear();
|
||||
live = liveOut[n];
|
||||
mustSpill = live;
|
||||
|
||||
InstructionList& instructions = nodes[n]->getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister()) {
|
||||
RegisterName range = name2range[definePtr->getRegisterName()];
|
||||
|
||||
if (needLoad.test(range))
|
||||
if (!mustSpill.test(range))
|
||||
cost[range].infinite = true;
|
||||
|
||||
if ((false /* !rematerializable(range) */ || !needLoad.test(range)) && !alreadyStored.test(range))
|
||||
cost[range].stores += weight;
|
||||
|
||||
needLoad.clear(range);
|
||||
}
|
||||
|
||||
if (instruction.getFlags() & ifCopy)
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
if (!live.test(name2range[usePtr->getRegisterName()])) {
|
||||
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
|
||||
Uint32 range = needLoad.get(l);
|
||||
cost[range].loads += weight;
|
||||
mustSpill.set(range);
|
||||
}
|
||||
needLoad.clear();
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
live.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
|
||||
live.set(range);
|
||||
needLoad.set(range);
|
||||
}
|
||||
|
||||
if (instruction.getFlags() & ifCopy) {
|
||||
assert(useBegin != useEnd && useBegin[0].isRegister());
|
||||
assert(defineBegin != defineEnd && defineBegin[0].isRegister());
|
||||
|
||||
RegisterName source = name2range[useBegin[0].getRegisterName()];
|
||||
RegisterName destination = name2range[defineBegin[0].getRegisterName()];
|
||||
|
||||
cost[source].copies += weight;
|
||||
cost[destination].copies += weight;
|
||||
}
|
||||
}
|
||||
|
||||
for (SparseSet::iterator s = needLoad.begin(); !needLoad.done(s); s = needLoad.advance(s))
|
||||
cost[needLoad.get(s)].loads += weight;
|
||||
}
|
||||
|
||||
for (Uint32 r = 0; r < rangeCount; r++) {
|
||||
SpillCost& c = cost[r];
|
||||
c.cost = 2 * (c.loads + c.stores) - c.copies;
|
||||
}
|
||||
|
||||
registerAllocator.spillCost = cost;
|
||||
}
|
||||
|
||||
#endif // _SPILLING_H_
|
||||
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal file
239
mozilla/ef/Compiler/RegisterAllocator/Splits.h
Normal file
@@ -0,0 +1,239 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SPLITS_H_
|
||||
#define _SPLITS_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include <string.h>
|
||||
#include "Pool.h"
|
||||
#include "ControlGraph.h"
|
||||
#include "ControlNodes.h"
|
||||
#include "Instruction.h"
|
||||
#include "RegisterAllocator.h"
|
||||
#include "RegisterAllocatorTools.h"
|
||||
|
||||
UT_EXTERN_LOG_MODULE(RegAlloc);
|
||||
|
||||
template <class RegisterPressure>
|
||||
struct Splits
|
||||
{
|
||||
static void calculateSplitCosts(RegisterAllocator& registerAllocator);
|
||||
static bool findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range);
|
||||
static void insertSplitCode(RegisterAllocator& registerAllocator);
|
||||
};
|
||||
|
||||
struct SplitCost
|
||||
{
|
||||
double loads;
|
||||
double stores;
|
||||
};
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Splits<RegisterPressure>::insertSplitCode(RegisterAllocator& /*registerAllocator*/)
|
||||
{
|
||||
// FIX
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
bool Splits<RegisterPressure>::findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range)
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
NameLinkedList** neighborsWithColor = new(pool) NameLinkedList*[6]; // FIX
|
||||
memset(neighborsWithColor, '\0', 6 * sizeof(NameLinkedList*));
|
||||
|
||||
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
|
||||
|
||||
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
|
||||
for (Int32 i = vector->count - 1; i >=0; --i) {
|
||||
RegisterName neighbor = vector->neighbors[i];
|
||||
RegisterName c = color[neighbor];
|
||||
|
||||
if (c < 6) { // FIX
|
||||
NameLinkedList* node = new(pool) NameLinkedList();
|
||||
node->name = neighbor;
|
||||
node->next = neighborsWithColor[c];
|
||||
neighborsWithColor[c] = node;
|
||||
}
|
||||
}
|
||||
|
||||
bool splitAroundName = true;
|
||||
|
||||
LiveRangeGraph<RegisterPressure>& lGraph = registerAllocator.lGraph;
|
||||
RegisterName bestColor = RegisterName(6); // FIX
|
||||
double bestCost = registerAllocator.spillCost[range].cost;
|
||||
SplitCost* splitCost = registerAllocator.splitCost;
|
||||
|
||||
for (RegisterName i = RegisterName(0); i < 6; i = RegisterName(i + 1)) { // FIX
|
||||
|
||||
double splitAroundNameCost = 0.0;
|
||||
bool canSplitAroundName = true;
|
||||
|
||||
SplitCost& sCost = splitCost[range];
|
||||
double addedCost = 2.0 * (sCost.stores + sCost.loads);
|
||||
|
||||
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
|
||||
RegisterName neighbor = node->name;
|
||||
if (lGraph.haveEdge(neighbor, range)) {
|
||||
canSplitAroundName = false;
|
||||
break;
|
||||
} else
|
||||
splitAroundNameCost += addedCost;
|
||||
}
|
||||
if (canSplitAroundName && splitAroundNameCost < bestCost) {
|
||||
bestCost = splitAroundNameCost;
|
||||
bestColor = i;
|
||||
splitAroundName = true;
|
||||
}
|
||||
|
||||
double splitAroundColorCost = 0.0;
|
||||
bool canSplitAroundColor = true;
|
||||
|
||||
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
|
||||
RegisterName neighbor = node->name;
|
||||
if (lGraph.haveEdge(range, neighbor)) {
|
||||
canSplitAroundColor = false;
|
||||
break;
|
||||
} else {
|
||||
SplitCost& sCost = splitCost[neighbor];
|
||||
double addedCost = 2.0 * (sCost.stores + sCost.loads);
|
||||
splitAroundColorCost += addedCost;
|
||||
}
|
||||
}
|
||||
if (canSplitAroundColor && splitAroundColorCost < bestCost) {
|
||||
bestCost = splitAroundColorCost;
|
||||
bestColor = i;
|
||||
splitAroundName = false;
|
||||
}
|
||||
}
|
||||
if (bestColor < RegisterName(6)) {
|
||||
color[range] = bestColor;
|
||||
registerAllocator.splitFound = true;
|
||||
|
||||
NameLinkedList** splitAround = registerAllocator.splitAround;
|
||||
|
||||
if (splitAroundName)
|
||||
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
|
||||
NameLinkedList* newNode = new(pool) NameLinkedList();
|
||||
newNode->name = node->name;
|
||||
newNode->next = splitAround[range];
|
||||
splitAround[range] = newNode;
|
||||
}
|
||||
else
|
||||
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
|
||||
NameLinkedList* newNode = new(pool) NameLinkedList();
|
||||
RegisterName neighbor = node->name;
|
||||
newNode->name = range;
|
||||
newNode->next = splitAround[neighbor];
|
||||
splitAround[neighbor] = newNode;
|
||||
}
|
||||
|
||||
trespass("Found a split");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class RegisterPressure>
|
||||
void Splits<RegisterPressure>::calculateSplitCosts(RegisterAllocator& registerAllocator)
|
||||
{
|
||||
Pool& pool = registerAllocator.pool;
|
||||
Uint32 rangeCount = registerAllocator.rangeCount;
|
||||
RegisterName* name2range = registerAllocator.name2range;
|
||||
|
||||
SplitCost* splitCost = new(pool) SplitCost[rangeCount];
|
||||
memset(splitCost, '\0', rangeCount * sizeof(SplitCost));
|
||||
|
||||
SparseSet live(pool, rangeCount);
|
||||
RegisterPressure::Set* liveIn = registerAllocator.liveness.liveIn;
|
||||
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
|
||||
|
||||
ControlGraph& controlGraph = registerAllocator.controlGraph;
|
||||
ControlNode** nodes = controlGraph.dfsList;
|
||||
Uint32 nNodes = controlGraph.nNodes;
|
||||
|
||||
for (Uint32 n = 0; n < nNodes; n++) {
|
||||
ControlNode& node = *nodes[n];
|
||||
double weight = doLog10(node.loopDepth);
|
||||
|
||||
live = liveOut[n];
|
||||
|
||||
ControlEdge* successorsEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++) {
|
||||
ControlNode& successor = successorsPtr->getTarget();
|
||||
|
||||
if (successor.getControlKind() != ckEnd) {
|
||||
RegisterPressure::Set& successorLiveIn = liveIn[successor.dfsNum];
|
||||
|
||||
for (SparseSet::iterator i = live.begin(); !live.done(i); i = live.advance(i)) {
|
||||
RegisterName name = RegisterName(live.get(i));
|
||||
if (!successorLiveIn.test(name))
|
||||
splitCost[name].loads += doLog10(successor.loopDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InstructionList& instructions = node.getInstructions();
|
||||
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
|
||||
Instruction& instruction = instructions.get(i);
|
||||
|
||||
InstructionUse* useBegin = instruction.getInstructionUseBegin();
|
||||
InstructionUse* useEnd = instruction.getInstructionUseEnd();
|
||||
InstructionUse* usePtr;
|
||||
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
|
||||
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
|
||||
InstructionDefine* definePtr;
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
splitCost[name2range[definePtr->getRegisterName()]].stores += weight;
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister()) {
|
||||
RegisterName range = name2range[usePtr->getRegisterName()];
|
||||
if (!live.test(range)) {
|
||||
if (&instruction != &instructions.last())
|
||||
splitCost[range].loads += weight;
|
||||
else {
|
||||
ControlEdge* successorsEnd = node.getSuccessorsEnd();
|
||||
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++)
|
||||
splitCost[range].loads += doLog10(successorsPtr->getTarget().loopDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
|
||||
if (definePtr->isRegister())
|
||||
live.clear(name2range[definePtr->getRegisterName()]);
|
||||
|
||||
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
|
||||
if (usePtr->isRegister())
|
||||
live.set(name2range[usePtr->getRegisterName()]);
|
||||
}
|
||||
}
|
||||
|
||||
NameLinkedList** splitAround = new(pool) NameLinkedList*[rangeCount];
|
||||
memset(splitAround, '\0', rangeCount * sizeof(NameLinkedList*));
|
||||
registerAllocator.splitAround = splitAround;
|
||||
|
||||
registerAllocator.splitCost = splitCost;
|
||||
registerAllocator.splitFound = false;
|
||||
}
|
||||
|
||||
#endif // _SPLITS_H_
|
||||
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal file
186
mozilla/ef/Compiler/RegisterAllocator/Timer.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "HashTable.h"
|
||||
#include "Timer.h"
|
||||
#include "Pool.h"
|
||||
|
||||
static Pool pool; // Pool for the Timer class.
|
||||
static HashTable<TimerEntry*> timerEntries(pool); // Timers hashtable.
|
||||
|
||||
const nTimersInABlock = 128; // Number of timers in a block.
|
||||
static PRTime *timers = new(pool) PRTime[nTimersInABlock]; // A block of timers.
|
||||
static Uint8 nextTimer = 0; // nextAvailableTimer.
|
||||
|
||||
//
|
||||
// Calibrate the call to PR_Now().
|
||||
//
|
||||
static PRTime calibrate()
|
||||
{
|
||||
PRTime t = PR_Now();
|
||||
PRTime& a = *new(pool) PRTime();
|
||||
|
||||
// Call 10 times the PR_Now() function.
|
||||
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
|
||||
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
|
||||
t = (PR_Now() - t + 9) / 10;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static PRTime adjust = calibrate();
|
||||
|
||||
//
|
||||
// Return the named timer..
|
||||
//
|
||||
TimerEntry& Timer::getTimerEntry(const char* name)
|
||||
{
|
||||
if (!timerEntries.exists(name)) {
|
||||
TimerEntry* newEntry = new(pool) TimerEntry();
|
||||
newEntry->accumulator = 0;
|
||||
newEntry->running = false;
|
||||
timerEntries.add(name, newEntry);
|
||||
}
|
||||
|
||||
return *timerEntries[name];
|
||||
}
|
||||
|
||||
//
|
||||
// Return a reference to a new timer.
|
||||
//
|
||||
PRTime& Timer::getNewTimer()
|
||||
{
|
||||
if (nextTimer >= nTimersInABlock) {
|
||||
timers = new(pool) PRTime[nTimersInABlock];
|
||||
nextTimer = 0;
|
||||
}
|
||||
return timers[nextTimer++];
|
||||
}
|
||||
|
||||
static Uint32 timersAreFrozen = 0;
|
||||
|
||||
//
|
||||
// Start the named timer.
|
||||
//
|
||||
void Timer::start(const char* name)
|
||||
{
|
||||
if (timersAreFrozen)
|
||||
return;
|
||||
|
||||
freezeTimers();
|
||||
|
||||
TimerEntry& timer = getTimerEntry(name);
|
||||
PR_ASSERT(!timer.running);
|
||||
|
||||
timer.accumulator = 0;
|
||||
timer.running = true;
|
||||
timer.done = false;
|
||||
|
||||
unfreezeTimers();
|
||||
}
|
||||
|
||||
//
|
||||
// Stop the named timer.
|
||||
//
|
||||
void Timer::stop(const char* name)
|
||||
{
|
||||
if (timersAreFrozen)
|
||||
return;
|
||||
|
||||
freezeTimers();
|
||||
|
||||
TimerEntry& timer = getTimerEntry(name);
|
||||
PR_ASSERT(timer.running);
|
||||
timer.running = false;
|
||||
timer.done = true;
|
||||
|
||||
unfreezeTimers();
|
||||
}
|
||||
|
||||
//
|
||||
// Freeze all the running timers.
|
||||
//
|
||||
void Timer::freezeTimers()
|
||||
{
|
||||
PRTime when = PR_Now() - adjust;
|
||||
|
||||
if (timersAreFrozen == 0) {
|
||||
Vector<TimerEntry*> entries = timerEntries;
|
||||
Uint32 count = entries.size();
|
||||
|
||||
for (Uint32 i = 0; i < count; i++) {
|
||||
TimerEntry& entry = *entries[i];
|
||||
if (entry.running) {
|
||||
entry.accumulator += (when - *entry.startTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
timersAreFrozen++;
|
||||
}
|
||||
|
||||
//
|
||||
// Unfreeze all the running timers.
|
||||
//
|
||||
void Timer::unfreezeTimers()
|
||||
{
|
||||
PR_ASSERT(timersAreFrozen != 0);
|
||||
timersAreFrozen--;
|
||||
|
||||
if (timersAreFrozen == 0) {
|
||||
Vector<TimerEntry *> entries = timerEntries;
|
||||
Uint32 count = entries.size();
|
||||
|
||||
PRTime& newStart = getNewTimer();
|
||||
|
||||
for (Uint32 i = 0; i < count; i++) {
|
||||
TimerEntry& entry = *entries[i];
|
||||
if (entry.running) {
|
||||
entry.startTime = &newStart;
|
||||
}
|
||||
}
|
||||
|
||||
newStart = PR_Now();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Print the named timer in the file f.
|
||||
//
|
||||
void Timer::print(FILE* f, const char *name)
|
||||
{
|
||||
if (timersAreFrozen)
|
||||
return;
|
||||
|
||||
freezeTimers();
|
||||
|
||||
TimerEntry& timer = getTimerEntry(name);
|
||||
|
||||
PR_ASSERT(timer.done);
|
||||
PRTime elapsed = timer.accumulator;
|
||||
|
||||
if (elapsed >> 32) {
|
||||
fprintf(f, "[timer %s out of range]\n", name);
|
||||
} else {
|
||||
fprintf(f, "[%dus in %s]\n", Uint32(elapsed), name);
|
||||
}
|
||||
fflush(f);
|
||||
|
||||
unfreezeTimers();
|
||||
}
|
||||
|
||||
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal file
80
mozilla/ef/Compiler/RegisterAllocator/Timer.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _TIMER_H_
|
||||
#define _TIMER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "HashTable.h"
|
||||
#include "prtime.h"
|
||||
|
||||
//
|
||||
// Naming convention:
|
||||
// As the class Timer contains only static methods, the timer's name should start with the
|
||||
// module name. Otherwise starting 2 timers with the same name will assert.
|
||||
//
|
||||
|
||||
#ifndef NO_TIMER
|
||||
|
||||
struct TimerEntry
|
||||
{
|
||||
PRTime *startTime; // Current time when we start the timer.
|
||||
PRTime accumulator; // Time spent in this timer.
|
||||
bool running; // True if the timer is running.
|
||||
bool done; // True if the timer was running and was stopped.
|
||||
};
|
||||
|
||||
class Timer
|
||||
{
|
||||
private:
|
||||
|
||||
// Return the named timer.
|
||||
static TimerEntry& getTimerEntry(const char* name);
|
||||
// Return a reference to a new Timer.
|
||||
static PRTime& getNewTimer();
|
||||
|
||||
public:
|
||||
|
||||
// Start the timer.
|
||||
static void start(const char* name);
|
||||
// Stop the timer.
|
||||
static void stop(const char* name);
|
||||
// Freeze all the running timers.
|
||||
static void freezeTimers();
|
||||
// Unfreeze all the running timers.
|
||||
static void unfreezeTimers();
|
||||
// Print the timer.
|
||||
static void print(FILE* f, const char *name);
|
||||
};
|
||||
|
||||
inline void startTimer(const char* name) {Timer::start(name);}
|
||||
inline void stopTimer(const char* name) {Timer::stop(name); Timer::print(stdout, name);}
|
||||
#define START_TIMER_SAFE Timer::freezeTimers();
|
||||
#define END_TIMER_SAFE Timer::unfreezeTimers();
|
||||
#define TIMER_SAFE(x) START_TIMER_SAFE x; END_TIMER_SAFE
|
||||
|
||||
#else /* NO_TIMER */
|
||||
|
||||
inline void startTimer(const char* /*name*/) {}
|
||||
inline void stopTimer(const char* /*name*/) {}
|
||||
#define START_TIMER_SAFE
|
||||
#define END_TIMER_SAFE
|
||||
#define TIMER_SAFE(x) x;
|
||||
|
||||
#endif /* NO_TIMER */
|
||||
#endif /* _TIMER_H_ */
|
||||
40
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.cpp
Normal file
40
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "VirtualRegister.h"
|
||||
#include "Instruction.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegister -
|
||||
|
||||
#ifdef MANUAL_TEMPLATES
|
||||
template class IndexedPool<VirtualRegister>;
|
||||
#endif
|
||||
|
||||
// Set the defining instruction.
|
||||
//
|
||||
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
|
||||
{
|
||||
if (definingInstruction != NULL) {
|
||||
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
|
||||
return;
|
||||
}
|
||||
definingInstruction = &instruction;
|
||||
}
|
||||
|
||||
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal file
116
mozilla/ef/Compiler/RegisterAllocator/VirtualRegister.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public License
|
||||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||||
* http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||||
* for the specific language governing rights and limitations under the
|
||||
* NPL.
|
||||
*
|
||||
* The Initial Developer of this code under the NPL is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||||
* Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VIRTUAL_REGISTER_H_
|
||||
#define _VIRTUAL_REGISTER_H_
|
||||
|
||||
#include "Fundamentals.h"
|
||||
#include "IndexedPool.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "RegisterTypes.h"
|
||||
#include "RegisterClass.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegister - 24b
|
||||
|
||||
class Instruction;
|
||||
|
||||
class VirtualRegister : public IndexedObject<VirtualRegister>
|
||||
{
|
||||
public:
|
||||
|
||||
Instruction* definingInstruction; // Instruction defining this VR.
|
||||
|
||||
// Initialize a VR of the given classKind.
|
||||
VirtualRegister(RegisterClassKind /*classKind*/) : definingInstruction(NULL) {}
|
||||
|
||||
// Return the defining instruction for this VR.
|
||||
Instruction* getDefiningInstruction() const {return definingInstruction;}
|
||||
// Set the defining instruction.
|
||||
void setDefiningInstruction(Instruction& insn);
|
||||
};
|
||||
|
||||
// Return true if the VirtualRegisters are equals. The only way 2 VRs can be equal is if
|
||||
// they have the same index. If they have the same index then they are at the same
|
||||
// address in the indexed pool.
|
||||
//
|
||||
inline bool operator == (const VirtualRegister& regA, const VirtualRegister& regB) {return ®A == ®B;}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// VirtualRegisterManager -
|
||||
|
||||
struct PreColoredRegister
|
||||
{
|
||||
RegisterID id;
|
||||
RegisterName color;
|
||||
};
|
||||
|
||||
class VirtualRegisterManager
|
||||
{
|
||||
private:
|
||||
|
||||
IndexedPool<VirtualRegister> registerPool;
|
||||
PreColoredRegister machineRegister[6];
|
||||
|
||||
public:
|
||||
VirtualRegisterManager()
|
||||
{
|
||||
for (Uint32 i = 0; i < 6; i++)
|
||||
machineRegister[i].id = invalidID;
|
||||
}
|
||||
|
||||
// Return the VirtualRegister at the given index.
|
||||
VirtualRegister& getVirtualRegister(RegisterName name) const {return registerPool.get(name);}
|
||||
|
||||
// Return a new VirtualRegister.
|
||||
RegisterID newVirtualRegister(RegisterClassKind classKind)
|
||||
{
|
||||
VirtualRegister& vReg = *new(registerPool) VirtualRegister(classKind);
|
||||
RegisterID rid;
|
||||
|
||||
setName(rid, RegisterName(vReg.getIndex()));
|
||||
setClass(rid, classKind);
|
||||
return rid;
|
||||
}
|
||||
|
||||
RegisterID newMachineRegister(RegisterName name, RegisterClassKind classKind)
|
||||
{
|
||||
RegisterID rid = machineRegister[name].id;
|
||||
|
||||
if (rid == invalidID) {
|
||||
rid = newVirtualRegister(classKind);
|
||||
DEBUG_ONLY(setMachineRegister(rid));
|
||||
machineRegister[name].id = rid;
|
||||
machineRegister[name].color = name;
|
||||
}
|
||||
|
||||
return rid;
|
||||
}
|
||||
|
||||
PreColoredRegister* getMachineRegistersBegin() const {return (PreColoredRegister*) machineRegister;} // FIX
|
||||
PreColoredRegister* getMachineRegistersEnd() const {return (PreColoredRegister*) &machineRegister[6];} // FIX
|
||||
|
||||
// Return the VirtualRegister universe size.
|
||||
Uint32 getSize() {return registerPool.getSize();}
|
||||
|
||||
void setSize(Uint32 size) {registerPool.setSize(size);}
|
||||
};
|
||||
|
||||
#endif // _VIRTUAL_REGISTER_H_
|
||||
@@ -1,217 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#define kBlockHeadSize offsetof(MMgc::FixedAlloc::FixedBlock, items)
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
FixedAlloc::FixedAlloc(int itemSize)
|
||||
{
|
||||
m_heap = GCHeap::GetGCHeap();
|
||||
|
||||
m_firstBlock = NULL;
|
||||
m_lastBlock = NULL;
|
||||
m_firstFree = NULL;
|
||||
m_maxAlloc = 0;
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
itemSize += DebugSize();
|
||||
#endif
|
||||
|
||||
m_itemSize = itemSize;
|
||||
|
||||
// The number of items per block is kBlockSize minus
|
||||
// the # of pointers at the base of each page.
|
||||
size_t usableSpace = GCHeap::kBlockSize - kBlockHeadSize;
|
||||
m_itemsPerBlock = usableSpace / m_itemSize;
|
||||
}
|
||||
|
||||
FixedAlloc::~FixedAlloc()
|
||||
{
|
||||
// Free all of the blocks
|
||||
while (m_firstBlock) {
|
||||
#ifdef MEMORY_INFO
|
||||
if(m_firstBlock->numAlloc > 0) {
|
||||
// go through every memory location, if the fourth 4 bytes cast as
|
||||
// an integer isn't 0xedededed then its allocated space and the integer is
|
||||
// an index into the stack trace table, the first 4 bytes will contain
|
||||
// the freelist pointer for free'd items (which is why the trace index is
|
||||
// stored in the second 4)
|
||||
// first 4 bytes - free list pointer
|
||||
// 2nd 4 bytes - alloc stack trace
|
||||
// 3rd 4 bytes - free stack trace
|
||||
// 4th 4 bytes - 0xedededed if freed correctly
|
||||
unsigned int *mem = (unsigned int*) m_firstBlock->items;
|
||||
unsigned int itemNum = 0;
|
||||
while(itemNum++ < m_itemsPerBlock) {
|
||||
unsigned int fourthInt = *(mem+3);
|
||||
if(fourthInt != 0xedededed) {
|
||||
GCDebugMsg(false, "Leaked %d byte item. Addr: 0x%x\n", GetItemSize(), mem+2);
|
||||
PrintStackTraceByIndex(*(mem+1));
|
||||
}
|
||||
mem += (m_itemSize / sizeof(int));
|
||||
}
|
||||
GCAssert(false);
|
||||
}
|
||||
|
||||
// go through every item on the free list and make sure it wasn't written to
|
||||
// after being poisoned.
|
||||
void *item = m_firstBlock->firstFree;
|
||||
while(item) {
|
||||
for(int i=3, n=(m_firstBlock->size>>2)-1; i<n; i++)
|
||||
{
|
||||
unsigned int data = ((int*)item)[i];
|
||||
if(data != 0xedededed)
|
||||
{
|
||||
GCDebugMsg(false, "Object 0x%x was written to after it was deleted, allocation trace:");
|
||||
PrintStackTrace((int*)item+2);
|
||||
GCDebugMsg(false, "Deletion trace:");
|
||||
PrintStackTrace((int*)item+3);
|
||||
GCDebugMsg(true, "Deleted item write violation!");
|
||||
}
|
||||
}
|
||||
// next free item
|
||||
item = *((void**)item);
|
||||
}
|
||||
#endif
|
||||
FreeChunk(m_firstBlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t FixedAlloc::Allocated()
|
||||
{
|
||||
size_t bytes = 0;
|
||||
FixedBlock *b = m_firstBlock;
|
||||
while(b)
|
||||
{
|
||||
bytes += b->numAlloc * b->size;
|
||||
b = b->next;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
FixedAlloc::FixedBlock* FixedAlloc::CreateChunk()
|
||||
{
|
||||
// Allocate a new block
|
||||
m_maxAlloc += m_itemsPerBlock;
|
||||
|
||||
FixedBlock* b = (FixedBlock*) m_heap->Alloc(1, true, false);
|
||||
|
||||
GCAssert(m_itemSize <= 0xffff);
|
||||
b->numAlloc = 0;
|
||||
b->size = (uint16)m_itemSize;
|
||||
b->firstFree = 0;
|
||||
b->nextItem = b->items;
|
||||
b->alloc = this;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// deleted and unused memory is 0xed'd, this is important for leak diagnostics
|
||||
memset(b->items, 0xed, m_itemSize * m_itemsPerBlock);
|
||||
#endif
|
||||
|
||||
// Link the block at the end of the list
|
||||
b->prev = m_lastBlock;
|
||||
b->next = 0;
|
||||
if (m_lastBlock) {
|
||||
m_lastBlock->next = b;
|
||||
}
|
||||
if (!m_firstBlock) {
|
||||
m_firstBlock = b;
|
||||
}
|
||||
m_lastBlock = b;
|
||||
|
||||
// Add our new ChunkBlock to the firstFree list (which should be empty)
|
||||
if (m_firstFree)
|
||||
{
|
||||
GCAssert(m_firstFree->prevFree == 0);
|
||||
m_firstFree->prevFree = b;
|
||||
}
|
||||
b->nextFree = m_firstFree;
|
||||
b->prevFree = 0;
|
||||
m_firstFree = b;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void FixedAlloc::FreeChunk(FixedBlock* b)
|
||||
{
|
||||
m_maxAlloc -= m_itemsPerBlock;
|
||||
|
||||
// Unlink the block from the list
|
||||
if (b == m_firstBlock) {
|
||||
m_firstBlock = b->next;
|
||||
} else {
|
||||
b->prev->next = b->next;
|
||||
}
|
||||
|
||||
if (b == m_lastBlock) {
|
||||
m_lastBlock = b->prev;
|
||||
} else {
|
||||
b->next->prev = b->prev;
|
||||
}
|
||||
|
||||
// If this is the first free block, pick a new one...
|
||||
if ( m_firstFree == b )
|
||||
m_firstFree = b->nextFree;
|
||||
else if (b->prevFree)
|
||||
b->prevFree->nextFree = b->nextFree;
|
||||
|
||||
if (b->nextFree)
|
||||
b->nextFree->prevFree = b->prevFree;
|
||||
|
||||
// Free the memory
|
||||
m_heap->Free(b);
|
||||
}
|
||||
|
||||
size_t FixedAlloc::GetItemSize() const
|
||||
{
|
||||
return m_itemSize - DebugSize();
|
||||
}
|
||||
|
||||
void *FastAllocator::operator new[](size_t size)
|
||||
{
|
||||
return FixedMalloc::GetInstance()->Alloc(size);
|
||||
}
|
||||
|
||||
void FastAllocator::operator delete [](void *item)
|
||||
{
|
||||
FixedMalloc::GetInstance()->Free(item);
|
||||
}
|
||||
}
|
||||
@@ -1,299 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __FixedAlloc__
|
||||
#define __FixedAlloc__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* This is a fast, fixed-size memory allocator for manually freed
|
||||
* objects.
|
||||
*
|
||||
* Memory is allocated from the system in 4096 byte chunks
|
||||
* via the GCHeap class. Not that this won't work well for
|
||||
* large objects (>400 bytes). For that, we have the
|
||||
* FixedAllocLarge allocator which will allocate multiple
|
||||
* pages at a time to minimize waste.
|
||||
*/
|
||||
class FixedAlloc : public GCAllocObject
|
||||
{
|
||||
friend class FixedMalloc;
|
||||
friend class FastAllocator;
|
||||
friend class GC;
|
||||
public:
|
||||
FixedAlloc(int itemSize);
|
||||
~FixedAlloc();
|
||||
|
||||
inline void* Alloc(size_t size)
|
||||
{
|
||||
(void)size;
|
||||
|
||||
GCAssertMsg(((size_t)m_itemSize >= size), "allocator itemsize too small");
|
||||
|
||||
if(!m_firstFree) {
|
||||
if(CreateChunk() == NULL) {
|
||||
GCAssertMsg(false, "Out of memory!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FixedBlock* b = m_firstFree;
|
||||
GCAssert(b && !IsFull(b));
|
||||
|
||||
b->numAlloc++;
|
||||
|
||||
// Consume the free list if available
|
||||
void *item = NULL;
|
||||
if (b->firstFree) {
|
||||
item = b->firstFree;
|
||||
b->firstFree = *((void**)item);
|
||||
// assert that the freelist hasn't been tampered with (by writing to the first 4 bytes)
|
||||
GCAssert(b->firstFree == NULL ||
|
||||
(b->firstFree >= b->items &&
|
||||
(((intptr)b->firstFree - (intptr)b->items) % b->size) == 0 &&
|
||||
(intptr) b->firstFree < ((intptr)b & ~0xfff) + GCHeap::kBlockSize));
|
||||
#ifdef MEMORY_INFO
|
||||
// ensure previously used item wasn't written to
|
||||
// -1 because write back pointer space isn't poisoned.
|
||||
for(int i=3, n=(b->size>>2)-1; i<n; i++)
|
||||
{
|
||||
int data = ((int*)item)[i];
|
||||
if(data != (int)0xedededed)
|
||||
{
|
||||
GCDebugMsg(false, "Object 0x%x was written to after it was deleted, allocation trace:", (int*)item+2);
|
||||
PrintStackTrace((int*)item+2);
|
||||
GCDebugMsg(false, "Deletion trace:");
|
||||
PrintStackTrace((int*)item+3);
|
||||
GCDebugMsg(true, "Deleted item write violation!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
// Take next item from end of block
|
||||
item = b->nextItem;
|
||||
GCAssert(item != 0);
|
||||
if(!IsFull(b)) {
|
||||
// There are more items at the end of the block
|
||||
b->nextItem = (void *) ((intptr)item+m_itemSize);
|
||||
#ifdef MEMORY_INFO
|
||||
// space made in ctor
|
||||
item = DebugDecorate(item, size + DebugSize(), 6);
|
||||
memset(item, 0xfa, size);
|
||||
#endif
|
||||
return item;
|
||||
}
|
||||
b->nextItem = 0;
|
||||
}
|
||||
|
||||
|
||||
// If we're out of free items, be sure to remove ourselves from the
|
||||
// list of blocks with free items.
|
||||
if (IsFull(b)) {
|
||||
m_firstFree = b->nextFree;
|
||||
b->nextFree = NULL;
|
||||
GCAssert(b->prevFree == NULL);
|
||||
|
||||
if (m_firstFree)
|
||||
m_firstFree->prevFree = 0;
|
||||
else
|
||||
CreateChunk();
|
||||
}
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
// space made in ctor
|
||||
item = DebugDecorate(item, size + DebugSize(), 6);
|
||||
memset(item, 0xfa, size);
|
||||
#endif
|
||||
|
||||
GCAssertMsg(item != NULL, "Out of memory");
|
||||
return item;
|
||||
}
|
||||
|
||||
static inline void Free(void *item)
|
||||
{
|
||||
FixedBlock *b = (FixedBlock*) ((uint32)item & ~0xFFF);
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
item = DebugFree(item, 0xED, 6);
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
// ensure that we are freeing a pointer on a item boundary
|
||||
GCAssert(((intptr)item - (intptr)b->items) % b->alloc->m_itemSize == 0);
|
||||
#endif
|
||||
|
||||
// Add this item to the free list
|
||||
*((void**)item) = b->firstFree;
|
||||
b->firstFree = item;
|
||||
|
||||
// We were full but now we have a free spot, add us to the free block list.
|
||||
if (b->numAlloc == b->alloc->m_itemsPerBlock)
|
||||
{
|
||||
GCAssert(!b->nextFree && !b->prevFree);
|
||||
b->nextFree = b->alloc->m_firstFree;
|
||||
if (b->alloc->m_firstFree)
|
||||
b->alloc->m_firstFree->prevFree = b;
|
||||
b->alloc->m_firstFree = b;
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
else // we should already be on the free list
|
||||
{
|
||||
GCAssert ((b == b->alloc->m_firstFree) || b->prevFree);
|
||||
}
|
||||
#endif
|
||||
|
||||
b->numAlloc--;
|
||||
|
||||
if(b->numAlloc == 0) {
|
||||
b->alloc->FreeChunk(b);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Allocated();
|
||||
|
||||
size_t GetItemSize() const;
|
||||
int GetMaxAlloc() const { return m_maxAlloc; }
|
||||
|
||||
static FixedAlloc *GetFixedAlloc(void *item)
|
||||
{
|
||||
FixedBlock *b = (FixedBlock*) ((uint32)item & ~0xFFF);
|
||||
#ifdef _DEBUG
|
||||
// Attempt to sanity check this ptr: numAllocs * size should be less than kBlockSize
|
||||
GCAssertMsg(((b->numAlloc * b->size) < GCHeap::kBlockSize), "Size called on ptr not part of FixedBlock");
|
||||
#endif
|
||||
return b->alloc;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct FixedBlock
|
||||
{
|
||||
void* firstFree; // first item on free list
|
||||
void* nextItem; // next free item
|
||||
FixedBlock* next;
|
||||
FixedBlock* prev;
|
||||
uint16 numAlloc;
|
||||
uint16 size;
|
||||
FixedBlock *prevFree;
|
||||
FixedBlock *nextFree;
|
||||
FixedAlloc *alloc;
|
||||
char items[1];
|
||||
};
|
||||
|
||||
GCHeap *m_heap;
|
||||
unsigned int m_itemsPerBlock;
|
||||
size_t m_itemSize;
|
||||
|
||||
// The list of chunk blocks
|
||||
FixedBlock* m_firstBlock;
|
||||
FixedBlock* m_lastBlock;
|
||||
|
||||
// The lowest priority block that has free items
|
||||
FixedBlock* m_firstFree;
|
||||
|
||||
int m_maxAlloc;
|
||||
|
||||
bool IsFull(FixedBlock *b) const { return b->numAlloc == m_itemsPerBlock; }
|
||||
FixedBlock* CreateChunk();
|
||||
void FreeChunk(FixedBlock* b);
|
||||
|
||||
static inline size_t Size(const void *item)
|
||||
{
|
||||
FixedBlock *b = (FixedBlock*) ((uint32)item & ~0xFFF);
|
||||
#ifdef _DEBUG
|
||||
// Attempt to sanity check this ptr: numAllocs * size should be less than kBlockSize
|
||||
GCAssertMsg(((b->numAlloc * b->size) < GCHeap::kBlockSize), "Size called on ptr not part of FixedBlock");
|
||||
#endif
|
||||
return b->size;
|
||||
}
|
||||
};
|
||||
|
||||
class FixedAllocSafe : public FixedAlloc
|
||||
{
|
||||
public:
|
||||
FixedAllocSafe(int itemSize) : FixedAlloc(itemSize) {}
|
||||
|
||||
void* Alloc(size_t size)
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCAcquireSpinlock lock(m_spinlock);
|
||||
#endif
|
||||
return FixedAlloc::Alloc(size);
|
||||
}
|
||||
|
||||
void Free(void *ptr)
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCAcquireSpinlock lock(m_spinlock);
|
||||
#endif
|
||||
FixedAlloc::Free(ptr);
|
||||
}
|
||||
|
||||
static FixedAllocSafe *GetFixedAllocSafe(void *item)
|
||||
{
|
||||
return (FixedAllocSafe*) FixedAlloc::GetFixedAlloc(item);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCSpinLock m_spinlock;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* classes that need fast lock free allocation should subclass this and pass
|
||||
* a FixedAlloc * to the new parameter. One new/delete are lock free, scalar
|
||||
* allocations use the normal locked general size allocator.
|
||||
*/
|
||||
class FastAllocator
|
||||
{
|
||||
public:
|
||||
static void *operator new(size_t size, FixedAlloc *alloc)
|
||||
{
|
||||
return alloc->Alloc(size);
|
||||
}
|
||||
|
||||
static void operator delete (void *item)
|
||||
{
|
||||
FixedAlloc::Free(item);
|
||||
}
|
||||
|
||||
// allow array allocation as well
|
||||
static void *operator new[](size_t size);
|
||||
static void operator delete [](void *item);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __FixedAlloc__ */
|
||||
@@ -1,141 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
// For memset
|
||||
#include <string.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
FixedMalloc *FixedMalloc::instance = NULL;
|
||||
|
||||
// Size classes for our Malloc. We start with a 4 byte allocator and then from
|
||||
// 8 to 128, size classes are spaced evenly 8 bytes apart, then from 128 to 1968 they
|
||||
int16 FixedMalloc::kSizeClasses[kNumSizeClasses] = {
|
||||
4, 8, 16, 24, 32, 40, 48, 56, 64, 72, //0-9
|
||||
80, 88, 96, 104, 112, 120, 128, 144, 160, 176, //10-19
|
||||
184, 192, 200, 208, 224, 232, 248, 264, 288, 312, //20-29
|
||||
336, 368, 400, 448, 504, 576, 672, 808, 1016, 1352, //30-39
|
||||
2032, //40
|
||||
};
|
||||
// This is an index which indicates that allocator i should be used
|
||||
// if kSizeClassIndex[i] items fit into a 4096 byte page.
|
||||
uint8 FixedMalloc::kSizeClassIndex[32] = {
|
||||
40, 40, 40, 39, 38, 37, 36, 35, 34, 33, //0-10
|
||||
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, //10-19
|
||||
22, 21, 20, 19, 19, 18, 18, 18, 17, 17, //20-29
|
||||
17, 16 //30-31
|
||||
};
|
||||
|
||||
void FixedMalloc::Init()
|
||||
{
|
||||
GCAssert(instance == NULL);
|
||||
instance = new FixedMalloc();
|
||||
}
|
||||
|
||||
void FixedMalloc::Destroy()
|
||||
{
|
||||
GCAssert(instance != NULL);
|
||||
delete instance;
|
||||
instance = NULL;
|
||||
}
|
||||
|
||||
FixedMalloc::FixedMalloc()
|
||||
{
|
||||
m_heap = GCHeap::GetGCHeap();
|
||||
// Create all the allocators up front (not lazy)
|
||||
// so that we don't have to check the pointers for
|
||||
// NULL on every allocation.
|
||||
for (int i=0; i<kNumSizeClasses; i++) {
|
||||
// FIXME: by default FixedAlloc uses 4K chunks, for the
|
||||
// more common size classes maybe we should use 8/16/32.
|
||||
// FIXME: we could use FixedAllocLarge for the bigger size
|
||||
// classes but how to call the right Free would need to be work out
|
||||
m_allocs[i] = new FixedAllocSafe(kSizeClasses[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FixedMalloc::~FixedMalloc()
|
||||
{
|
||||
for (int i=0; i<kNumSizeClasses; i++) {
|
||||
FixedAllocSafe *a = m_allocs[i];
|
||||
delete a;
|
||||
}
|
||||
}
|
||||
|
||||
size_t FixedMalloc::Allocated()
|
||||
{
|
||||
size_t bytes = 0;
|
||||
for (int i=0; i<kNumSizeClasses; i++) {
|
||||
FixedAllocSafe *a = m_allocs[i];
|
||||
bytes += a->Allocated();
|
||||
}
|
||||
// FIXME: what about big blocks?
|
||||
return bytes;
|
||||
}
|
||||
|
||||
FixedAllocSafe *FixedMalloc::FindSizeClass(size_t size) const
|
||||
{
|
||||
GCAssertMsg(size > 0, "cannot allocate a 0 sized block\n");
|
||||
|
||||
size_t size8 = (size+7)&~7; // round up to multiple of 8
|
||||
|
||||
// Buckets up to 128 are spaced evenly at 8 bytes.
|
||||
if (size <= 128) {
|
||||
unsigned index = size > 4 ? size8 >> 3 : 0;
|
||||
FixedAllocSafe *a = m_allocs[index];
|
||||
// make sure I fit
|
||||
GCAssert(size <= a->GetItemSize());
|
||||
|
||||
// make sure I don't fit
|
||||
GCAssert(index == 0 || size > m_allocs[index-1]->GetItemSize());
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
// This is the fast lookup table implementation to
|
||||
// find the right allocator.
|
||||
// FIXME: do this w/o division!
|
||||
unsigned index = kSizeClassIndex[kPageUsableSpace/size8];
|
||||
|
||||
// assert that I fit
|
||||
GCAssert(size <= m_allocs[index]->GetItemSize());
|
||||
|
||||
// assert that I don't fit (makes sure we don't waste space
|
||||
GCAssert(size > m_allocs[index-1]->GetItemSize());
|
||||
|
||||
return m_allocs[index];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __Malloc__
|
||||
#define __Malloc__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* A general purpose memory allocator using size classes
|
||||
*/
|
||||
class FixedMalloc : public GCAllocObject
|
||||
{
|
||||
friend class GC;
|
||||
public:
|
||||
static void Init();
|
||||
static void Destroy();
|
||||
/**
|
||||
* return the number of bytes of memory issued
|
||||
*/
|
||||
size_t Allocated();
|
||||
static FixedMalloc *GetInstance() { return instance; }
|
||||
|
||||
inline void* Alloc(size_t size)
|
||||
{
|
||||
void *item;
|
||||
GCAssert(size + 3 > size);
|
||||
// overflow detection
|
||||
if(size+3 < size)
|
||||
return NULL;
|
||||
size = (size+3)&~3;
|
||||
if (size <= (size_t)kLargestAlloc) {
|
||||
item = FindSizeClass(size)->Alloc(size);
|
||||
} else {
|
||||
item = LargeAlloc(size);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
inline void Free(void *item)
|
||||
{
|
||||
if(item == 0)
|
||||
return;
|
||||
|
||||
// small things are never allocated on the 4K boundary b/c the block
|
||||
// header structure is stored there, large things always are
|
||||
if(IsLargeAlloc(item)) {
|
||||
LargeFree(item);
|
||||
} else {
|
||||
FixedAllocSafe::GetFixedAllocSafe(item)->Free(item);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t Size(const void *item)
|
||||
{
|
||||
size_t size;
|
||||
if(IsLargeAlloc(item)) {
|
||||
size = LargeSize(item);
|
||||
} else {
|
||||
size = FixedAlloc::Size(item);
|
||||
}
|
||||
#ifdef MEMORY_INFO
|
||||
size -= DebugSize();
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
// private:
|
||||
FixedMalloc();
|
||||
~FixedMalloc();
|
||||
static FixedMalloc *instance;
|
||||
const static int kLargestAlloc = 2032;
|
||||
const static int kNumSizeClasses = 41;
|
||||
const static int kPageUsableSpace = GCHeap::kBlockSize - offsetof(MMgc::FixedAlloc::FixedBlock, items);
|
||||
|
||||
static int16 kSizeClasses[kNumSizeClasses];
|
||||
static uint8 kSizeClassIndex[32];
|
||||
|
||||
GCHeap *m_heap;
|
||||
FixedAllocSafe *m_allocs[kNumSizeClasses];
|
||||
FixedAllocSafe *FindSizeClass(size_t size) const;
|
||||
|
||||
static bool IsLargeAlloc(const void *item)
|
||||
{
|
||||
// space made in ctor
|
||||
item = GetRealPointer(item);
|
||||
return ((intptr) item & 0xFFF) == 0;
|
||||
}
|
||||
|
||||
inline void *LargeAlloc(size_t size)
|
||||
{
|
||||
size += DebugSize();
|
||||
size_t blocksNeeded = ((size+0xfff)&~0xfff) >> 12;
|
||||
void *item = m_heap->Alloc(blocksNeeded, true, false);
|
||||
if(!item)
|
||||
{
|
||||
GCAssertMsg(item != NULL, "Large allocation of %d blocks failed!");
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MEMORY_INFO
|
||||
item = DebugDecorate(item, size, 5);
|
||||
memset(item, 0xfb, size - DebugSize());
|
||||
#endif
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
inline void LargeFree(void *item)
|
||||
{
|
||||
#ifdef MEMORY_INFO
|
||||
item = DebugFree(item, 0xed, 5);
|
||||
#endif
|
||||
m_heap->Free(item);
|
||||
}
|
||||
|
||||
static size_t LargeSize(const void *item)
|
||||
{
|
||||
return GCHeap::GetGCHeap()->Size(item) * GCHeap::kBlockSize;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif /* __Malloc__ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,608 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
GCAlloc::GCAlloc(GC* gc, int itemSize, bool containsPointers, bool isRC, int sizeClassIndex) :
|
||||
GCAllocBase(gc),
|
||||
containsPointers(containsPointers),
|
||||
containsRCObjects(isRC),
|
||||
m_sizeClassIndex(sizeClassIndex)
|
||||
{
|
||||
// Round itemSize to the nearest boundary of 8
|
||||
itemSize = (itemSize+7)&~7;
|
||||
|
||||
m_firstBlock = NULL;
|
||||
m_lastBlock = NULL;
|
||||
m_firstFree = NULL;
|
||||
m_numAlloc = 0;
|
||||
m_maxAlloc = 0;
|
||||
m_itemSize = itemSize;
|
||||
m_numBlocks = 0;
|
||||
|
||||
// The number of items per block is kBlockSize minus
|
||||
// the # of pointers at the base of each page.
|
||||
|
||||
m_itemsPerBlock = (kBlockSize - sizeof(GCBlock)) / m_itemSize;
|
||||
|
||||
m_numBitmapBytes = (m_itemsPerBlock>>1) + (m_itemsPerBlock & 1);
|
||||
// round up to 4 bytes so we can go through the bits 8 items at a time
|
||||
m_numBitmapBytes = (m_numBitmapBytes+3)&~3;
|
||||
|
||||
GCAssert(m_numBitmapBytes<<1 >= m_itemsPerBlock);
|
||||
|
||||
int usedSpace = m_itemsPerBlock * m_itemSize + sizeof(GCBlock);
|
||||
GCAssert(usedSpace <= kBlockSize);
|
||||
GCAssert(kBlockSize - usedSpace < (int)m_itemSize);
|
||||
if(kBlockSize - usedSpace >= m_numBitmapBytes) {
|
||||
m_bitsInPage = true;
|
||||
} else {
|
||||
m_bitsInPage = false;
|
||||
}
|
||||
|
||||
// compute values that let us avoid division
|
||||
GCAssert(m_itemSize <= 0xffff);
|
||||
ComputeMultiplyShift((uint16)m_itemSize, multiple, shift);
|
||||
}
|
||||
|
||||
GCAlloc::~GCAlloc()
|
||||
{
|
||||
// Free all of the blocks
|
||||
GCAssertMsg(GetNumAlloc() == 0, "You have leaks");
|
||||
|
||||
while (m_firstBlock) {
|
||||
if(((intptr)m_firstBlock->bits & 0xfff) == 0)
|
||||
m_gc->GetGCHeap()->Free(m_firstBlock->bits);
|
||||
#ifdef _DEBUG
|
||||
// go through every item on the free list and make sure it wasn't written to
|
||||
// after being poisoned.
|
||||
void *item = m_firstBlock->firstFree;
|
||||
while(item) {
|
||||
for(int i=3, n=(m_firstBlock->size>>2)-1; i<n; i++)
|
||||
{
|
||||
int data = ((int*)item)[i];
|
||||
if(data != 0xbabababa && data != 0xcacacaca)
|
||||
{
|
||||
GCDebugMsg(false, "Object 0x%x was written to after it was deleted, allocation trace:");
|
||||
PrintStackTrace((int*)item+2);
|
||||
GCDebugMsg(false, "Deletion trace:");
|
||||
PrintStackTrace((int*)item+3);
|
||||
GCDebugMsg(true, "Deleted item write violation!");
|
||||
}
|
||||
}
|
||||
// next free item
|
||||
item = *((void**)item);
|
||||
}
|
||||
#endif
|
||||
GCBlock *b = m_firstBlock;
|
||||
UnlinkChunk(b);
|
||||
FreeChunk(b);
|
||||
}
|
||||
}
|
||||
|
||||
GCAlloc::GCBlock* GCAlloc::CreateChunk()
|
||||
{
|
||||
// Get space in the bitmap. Do this before allocating the actual block,
|
||||
// since we might call GC::AllocBlock for more bitmap space and thus
|
||||
// cause some incremental marking.
|
||||
uint32* bits = NULL;
|
||||
|
||||
if(!m_bitsInPage)
|
||||
bits = m_gc->GetBits(m_numBitmapBytes, m_sizeClassIndex);
|
||||
|
||||
// Allocate a new block
|
||||
m_maxAlloc += m_itemsPerBlock;
|
||||
m_numBlocks++;
|
||||
|
||||
int numBlocks = kBlockSize/GCHeap::kBlockSize;
|
||||
GCBlock* b = (GCBlock*) m_gc->AllocBlock(numBlocks, GC::kGCAllocPage);
|
||||
|
||||
b->gc = m_gc;
|
||||
b->alloc = this;
|
||||
b->size = m_itemSize;
|
||||
b->needsSweeping = false;
|
||||
b->bits = m_bitsInPage ? (uint32*)((char*)b + sizeof(GCBlock)) : bits;
|
||||
|
||||
// Link the block at the end of the list
|
||||
b->prev = m_lastBlock;
|
||||
b->next = 0;
|
||||
|
||||
if (m_lastBlock) {
|
||||
m_lastBlock->next = b;
|
||||
}
|
||||
if (!m_firstBlock) {
|
||||
m_firstBlock = b;
|
||||
}
|
||||
m_lastBlock = b;
|
||||
|
||||
// Add our new ChunkBlock to the firstFree list (which should be empty)
|
||||
if (m_firstFree)
|
||||
{
|
||||
GCAssert(m_firstFree->prevFree == 0);
|
||||
m_firstFree->prevFree = b;
|
||||
}
|
||||
b->nextFree = m_firstFree;
|
||||
b->prevFree = 0;
|
||||
m_firstFree = b;
|
||||
|
||||
// calculate back from end (better alignment, no dead space at end)
|
||||
b->items = (char*)b+GCHeap::kBlockSize - m_itemsPerBlock * m_itemSize;
|
||||
b->nextItem = b->items;
|
||||
b->numItems = 0;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void GCAlloc::UnlinkChunk(GCBlock *b)
|
||||
{
|
||||
m_maxAlloc -= m_itemsPerBlock;
|
||||
m_numBlocks--;
|
||||
|
||||
// Unlink the block from the list
|
||||
if (b == m_firstBlock) {
|
||||
m_firstBlock = b->next;
|
||||
} else {
|
||||
b->prev->next = b->next;
|
||||
}
|
||||
|
||||
if (b == m_lastBlock) {
|
||||
m_lastBlock = b->prev;
|
||||
} else {
|
||||
b->next->prev = b->prev;
|
||||
}
|
||||
|
||||
if(b->nextFree || b->prevFree || b == m_firstFree) {
|
||||
RemoveFromFreeList(b);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
b->next = b->prev = NULL;
|
||||
b->nextFree = b->prevFree = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GCAlloc::FreeChunk(GCBlock* b)
|
||||
{
|
||||
GCAssert(b->numItems == 0);
|
||||
if(!m_bitsInPage) {
|
||||
memset(b->GetBits(), 0, m_numBitmapBytes);
|
||||
m_gc->FreeBits(b->GetBits(), m_sizeClassIndex);
|
||||
b->bits = NULL;
|
||||
}
|
||||
|
||||
// Free the memory
|
||||
m_gc->FreeBlock(b, 1);
|
||||
}
|
||||
|
||||
void* GCAlloc::Alloc(size_t size, int flags)
|
||||
{
|
||||
(void)size;
|
||||
GCAssertMsg(((size_t)m_itemSize >= size), "allocator itemsize too small");
|
||||
start:
|
||||
if (m_firstFree == NULL) {
|
||||
if (CreateChunk() == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
GCBlock* b = m_firstFree;
|
||||
|
||||
// lazy sweeping
|
||||
if(b->needsSweeping) {
|
||||
if(!GC::useNewSweep || !m_gc->collecting) {
|
||||
if(Sweep(b)) {
|
||||
if(GC::useNewSweep) {
|
||||
UnlinkChunk(b);
|
||||
FreeChunk(b);
|
||||
}
|
||||
goto start;
|
||||
}
|
||||
} else if(b->IsFull()) {
|
||||
// we are collecting (possibly a Finalize allocation) so we can't
|
||||
// sweep the page yet (because objects can examine other objects during
|
||||
// finalize and Sweep poisons. So if we don't have any items (hence
|
||||
// the IsFull()) we have to create a use a different chunk creating a new
|
||||
// one if necessary
|
||||
b = m_firstFree->nextFree;
|
||||
if(!b) {
|
||||
CreateChunk();
|
||||
b = m_firstFree;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GCAssert(b && !b->IsFull());
|
||||
|
||||
void *item;
|
||||
if(b->firstFree) {
|
||||
item = b->firstFree;
|
||||
b->firstFree = *((void**)item);
|
||||
// clear free list pointer, the rest was zero'd in free
|
||||
*(int*) item = 0;
|
||||
#ifdef MEMORY_INFO
|
||||
// ensure previously used item wasn't written to
|
||||
// -1 because write back pointer space isn't poisoned.
|
||||
for(int i=3, n=(b->size>>2)-1; i<n; i++)
|
||||
{
|
||||
int data = ((int*)item)[i];
|
||||
if(data != 0xcacacaca && data != 0xbabababa)
|
||||
{
|
||||
GCDebugMsg(false, "Object 0x%x was written to after it was deleted, allocation trace:", item);
|
||||
PrintStackTrace((int*)item+2);
|
||||
GCDebugMsg(false, "Deletion trace:");
|
||||
PrintStackTrace((int*)item+3);
|
||||
GCDebugMsg(true, "Deleted item write violation!");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
item = b->nextItem;
|
||||
if(((int)((char*)item + b->size) & 0xfff) != 0) {
|
||||
b->nextItem = (char*)item + b->size;
|
||||
} else {
|
||||
b->nextItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// set up bits, items start out white and whether they need finalization
|
||||
// is determined by the caller
|
||||
|
||||
// make sure we ended up in the right place
|
||||
GCAssert(((flags&GC::kContainsPointers) != 0) == ContainsPointers());
|
||||
|
||||
// this assumes what we assert
|
||||
GCAssert((unsigned long)GC::kFinalize == (unsigned long)GCAlloc::kFinalize);
|
||||
int index = GetIndex(b, item);
|
||||
|
||||
GCAssert(index >= 0);
|
||||
|
||||
ClearBits(b, index, 0xf);
|
||||
SetBit(b, index, flags & kFinalize);
|
||||
|
||||
b->numItems++;
|
||||
#ifdef MEMORY_INFO
|
||||
m_numAlloc++;
|
||||
#endif
|
||||
|
||||
// If we're out of free items, be sure to remove ourselves from the
|
||||
// list of blocks with free items.
|
||||
if (b->IsFull()) {
|
||||
m_firstFree = b->nextFree;
|
||||
b->nextFree = NULL;
|
||||
GCAssert(b->prevFree == NULL);
|
||||
|
||||
if (m_firstFree)
|
||||
m_firstFree->prevFree = 0;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void GCAlloc::Free(void *item)
|
||||
{
|
||||
GCBlock *b = (GCBlock*) ((intptr) item & ~0xFFF);
|
||||
GCAlloc *a = b->alloc;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// check that its not already been freed
|
||||
void *free = b->firstFree;
|
||||
while(free) {
|
||||
GCAssert(free != item);
|
||||
free = *((void**) free);
|
||||
}
|
||||
#endif
|
||||
|
||||
int index = GetIndex(b, item);
|
||||
if(GetBit(b, index, kHasWeakRef)) {
|
||||
b->gc->ClearWeakRef(GetUserPointer(item));
|
||||
}
|
||||
|
||||
if(GC::useNewSweep && b->needsSweeping) {
|
||||
b->alloc->Sweep(b);
|
||||
}
|
||||
|
||||
if(b->IsFull()) {
|
||||
a->AddToFreeList(b);
|
||||
}
|
||||
|
||||
b->FreeItem(item, index);
|
||||
|
||||
if(b->numItems == 0 && !a->IsLastFreeBlock(b)) {
|
||||
a->UnlinkChunk(b);
|
||||
a->FreeChunk(b);
|
||||
}
|
||||
}
|
||||
|
||||
void GCAlloc::Finalize()
|
||||
{
|
||||
// Go through every item of every block. Look for items
|
||||
// that are in use but not marked as reachable, and delete
|
||||
// them.
|
||||
|
||||
GCBlock *next = NULL;
|
||||
for (GCBlock* b = m_firstBlock; b != NULL; b = next)
|
||||
{
|
||||
// we can unlink block below
|
||||
next = b->next;
|
||||
static uint32 kMarkBits = 0x11111111;
|
||||
static uint32 kFinalizeAndWeakRefBits = 0xcccccccc;
|
||||
GCAssert(kMark == 0x1 && kFinalize == 0x4 && kHasWeakRef == 0x8);
|
||||
|
||||
int numMarkedItems = 0;
|
||||
|
||||
// TODO: MMX version for IA32
|
||||
uint32 *bits = (uint32*) b->GetBits();
|
||||
uint32 count = b->nextItem ? GetIndex(b, b->nextItem) : m_itemsPerBlock;
|
||||
// round up to eight
|
||||
count = (count+7)&~7;
|
||||
for(int i=0, n=count>>3; i < n; i++)
|
||||
{
|
||||
uint32 b8 = bits[i];
|
||||
uint32 unmarkedFinalizeAndWeakRefMask = ((~b8&kMarkBits) << 2) | ((~b8&kMarkBits) << 3);
|
||||
uint32 finalizeAndWeakRefBits = b8&kFinalizeAndWeakRefBits;
|
||||
// check the finalize and weak ref bits of unmarked objects
|
||||
if((unmarkedFinalizeAndWeakRefMask & finalizeAndWeakRefBits) != 0)
|
||||
{
|
||||
uint32 marks = b8;
|
||||
for(int j=0; j<8;j++,marks>>=4)
|
||||
{
|
||||
if(marks & kMark || !(marks & (kFinalize|kHasWeakRef)))
|
||||
continue;
|
||||
|
||||
void* item = (char*)b->items + m_itemSize*((i*8)+j);
|
||||
|
||||
if (marks & kFinalize)
|
||||
{
|
||||
GCFinalizedObject *obj = (GCFinalizedObject*)GetUserPointer(item);
|
||||
GCAssert(*(int*)obj != 0);
|
||||
obj->~GCFinalizedObject();
|
||||
|
||||
#if defined(_DEBUG) && defined(MMGC_DRC)
|
||||
if(b->alloc->IsRCObject()) {
|
||||
m_gc->RCObjectZeroCheck((RCObject*)obj);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (marks & kHasWeakRef) {
|
||||
b->gc->ClearWeakRef(GetUserPointer(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numMarkedItems += CountBits(b8 & kMarkBits);
|
||||
}
|
||||
|
||||
if(GC::useNewSweep && numMarkedItems == 0 && !IsLastFreeBlock(b)) {
|
||||
// add to list of block to be returned to the Heap after finalization
|
||||
// we don't do this during finalization b/c we want finalizers to be able
|
||||
// to reference the memory of other objects being finalized
|
||||
next = b->next;
|
||||
UnlinkChunk(b);
|
||||
b->gc->AddToSweepList(b);
|
||||
} else if(numMarkedItems == b->numItems) {
|
||||
// nothing changed on this page
|
||||
continue;
|
||||
} else if(GC::useNewSweep) {
|
||||
// free'ing some items but not all
|
||||
b->needsSweeping = true;
|
||||
|
||||
if(b->IsFull())
|
||||
AddToFreeList(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GCAlloc::Sweep(GCBlock *b)
|
||||
{
|
||||
bool wasFull = b->IsFull();
|
||||
|
||||
// Mark all the items on the free list so we don't try free them again
|
||||
// TODO: see if we can avoid this somehow
|
||||
void *item = b->firstFree;
|
||||
while (item != NULL) {
|
||||
SetMark(item);
|
||||
item = *((void**)item);
|
||||
}
|
||||
|
||||
// TODO: MMX version for IA32
|
||||
uint32 *bits = (uint32*) b->GetBits();
|
||||
uint32 count = b->nextItem ? GetIndex(b, b->nextItem) : m_itemsPerBlock;
|
||||
// round up to eight
|
||||
int numInts = ((count+7)&~7) >> 3;
|
||||
for(int i=0, n=numInts; i < n; i++)
|
||||
{
|
||||
uint32 b8 = bits[i];
|
||||
uint32 marks = b8;
|
||||
int subCount = i==(n-1) ? ((count-1)&7)+1 : 8;
|
||||
for(int j=0; j<subCount;j++,marks>>=4)
|
||||
{
|
||||
if(marks & kMark)
|
||||
continue;
|
||||
|
||||
item = (char*)b->items + m_itemSize*(i*8+j);
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
DebugFreeReverse(item, 0xba, 4);
|
||||
#endif
|
||||
b->FreeItem(item, (i*8+j));
|
||||
}
|
||||
}
|
||||
|
||||
b->needsSweeping = false;
|
||||
|
||||
if((b == m_firstFree || b->prevFree != NULL) && // on freelist
|
||||
b->numItems == 0 && // empty
|
||||
!IsLastFreeBlock(b))
|
||||
{
|
||||
// take this page out of service
|
||||
return true;
|
||||
} else if(!GC::useNewSweep && !b->IsFull() && wasFull) {
|
||||
AddToFreeList(b);
|
||||
}
|
||||
|
||||
if(!GC::useNewSweep && b->numItems == 0) {
|
||||
UnlinkChunk(b);
|
||||
FreeChunk(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GCAlloc::Sweep(bool force)
|
||||
{
|
||||
// Go through every item of every block. Look for items
|
||||
// that are in use but not marked as reachable, and delete
|
||||
// them.
|
||||
GCBlock* next;
|
||||
for (GCBlock* b = m_firstBlock; b != NULL; b = next)
|
||||
{
|
||||
next = b->next;
|
||||
bool wasFull = b->IsFull();
|
||||
// if we aren't forcing and the block wasn't full (ie its
|
||||
// still on the free list) then just set a flag, the Sweep
|
||||
// will happen the next time Alloc is called and b is firstFree
|
||||
if(!force && !wasFull) {
|
||||
b->needsSweeping = true;
|
||||
} else {
|
||||
Sweep(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GCAlloc::ClearMarks()
|
||||
{
|
||||
GCBlock *block = m_firstBlock;
|
||||
start:
|
||||
while (block) {
|
||||
GCBlock *next = block->next;
|
||||
|
||||
if(block->needsSweeping) {
|
||||
if(Sweep(block)) {
|
||||
if(GC::useNewSweep) {
|
||||
UnlinkChunk(block);
|
||||
FreeChunk(block);
|
||||
}
|
||||
block = next;
|
||||
goto start;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all the mark bits
|
||||
// FIXME: can we do this in sweep instead?
|
||||
uint32 *pbits = (uint32*)block->GetBits();
|
||||
const static uint32 mq32 = 0x33333333;
|
||||
GCAssert((kMark|kQueued) == 0x3);
|
||||
// TODO: MMX version for IA32
|
||||
for(int i=0, n=m_numBitmapBytes>>2; i < n; i++) {
|
||||
pbits[i] &= ~mq32;
|
||||
}
|
||||
|
||||
// Advance to next block
|
||||
block = next;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
int GCAlloc::ConservativeGetMark(const void *item, bool bogusPointerReturnValue)
|
||||
{
|
||||
GCBlock *block = (GCBlock*) ((intptr) item & ~0xFFF);
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
item = GetRealPointer(item);
|
||||
#endif
|
||||
|
||||
// guard against bogus pointers to the block header
|
||||
if (item < block->items)
|
||||
return bogusPointerReturnValue;
|
||||
|
||||
// floor value to start of item
|
||||
// FIXME: do this w/o division if we can
|
||||
int itemNum = GetIndex(block, item);
|
||||
|
||||
// skip pointers into dead space at end of block
|
||||
if (itemNum > block->alloc->m_itemsPerBlock - 1)
|
||||
return bogusPointerReturnValue;
|
||||
|
||||
// skip pointers into objects
|
||||
if(block->items + itemNum * block->size != item)
|
||||
return bogusPointerReturnValue;
|
||||
|
||||
return GetMark(item);
|
||||
}
|
||||
|
||||
// allows us to avoid division in GetItemIndex, kudos to Tinic
|
||||
void GCAlloc::ComputeMultiplyShift(uint16 d, uint16 &muli, uint16 &shft)
|
||||
{
|
||||
uint32 s = 0;
|
||||
uint32 n = 0;
|
||||
uint32 m = 0;
|
||||
for ( ; n < ( 1 << 13 ) ; s++) {
|
||||
m = n;
|
||||
n = ( ( 1 << ( s + 1 ) ) / d ) + 1;
|
||||
}
|
||||
shft = (uint16) s - 1;
|
||||
muli = (uint16) m;
|
||||
}
|
||||
|
||||
void GCAlloc::GCBlock::FreeItem(void *item, int index)
|
||||
{
|
||||
GCAssert(alloc->m_numAlloc != 0);
|
||||
|
||||
void *oldFree = firstFree;
|
||||
firstFree = item;
|
||||
#ifdef MEMORY_INFO
|
||||
alloc->m_numAlloc--;
|
||||
#endif
|
||||
numItems--;
|
||||
|
||||
// clear all bits
|
||||
ClearBits(this, index, 0xf);
|
||||
|
||||
#ifndef _DEBUG
|
||||
// memset rest of item not including free list pointer, in _DEBUG
|
||||
// we poison the memory (and clear in Alloc)
|
||||
// FIXME: can we do something faster with MMX here?
|
||||
if(!alloc->IsRCObject())
|
||||
memset((char*)item, 0, size);
|
||||
#endif
|
||||
// Add this item to the free list
|
||||
*((void**)item) = oldFree;
|
||||
}
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCAlloc__
|
||||
#define __GCAlloc__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
*
|
||||
* This is a fast, fixed-size memory allocator for garbage-collected
|
||||
* objects.
|
||||
*
|
||||
* Memory is allocated from the system on 4096-byte aligned boundaries,
|
||||
* which corresponds to the size of an OS page in Windows XP. Allocation
|
||||
* of pages is performed via the GCPageAlloc class.
|
||||
*
|
||||
* In each 4096-byte block, there is a block header with marked bits,
|
||||
* finalize bits, the pointer to the next free item and "recycling"
|
||||
* free item linked list.
|
||||
*
|
||||
* The bits of the "marked" bitmap are controlled by the SetMark method.
|
||||
*
|
||||
* The bits of the "finalize" bitmap are set when an item is
|
||||
* allocated. The value for the finalize bit is passed in as a
|
||||
* parameter to the allocation call.
|
||||
*
|
||||
* When the Sweep method is invoked, all objects that are not marked
|
||||
* with the specified mark flag are disposed of. If the corresponding
|
||||
* finalize bit is set, the GCObject destructor is invoked on that
|
||||
* item.
|
||||
*
|
||||
* When an allocation is requested and there are no more free
|
||||
* entries, GCAlloc will request that a garbage collection take
|
||||
* place. It will allocate new blocks if more than 20% of its
|
||||
* blocks are used after the collection, targeting a 5:1
|
||||
* heap size / minimim heap size ratio.
|
||||
*
|
||||
*/
|
||||
class GCAlloc : public GCAllocBase
|
||||
{
|
||||
friend class GC;
|
||||
public:
|
||||
enum ItemBit { kMark=1, kQueued=2, kFinalize=4, kHasWeakRef=8 };
|
||||
|
||||
GCAlloc(GC* gc, int itemSize, bool containsPointers, bool isRC, int sizeClassIndex);
|
||||
~GCAlloc();
|
||||
|
||||
void* Alloc(size_t size, int flags);
|
||||
static void Free(void *ptr);
|
||||
void Finalize();
|
||||
void Sweep(bool force=false);
|
||||
size_t GetItemSize() { return m_itemSize; }
|
||||
void ClearMarks();
|
||||
|
||||
static int SetMark(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return SetBit(block, GetIndex(block, item), kMark);
|
||||
}
|
||||
|
||||
static int SetQueued(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return SetBit(block, GetIndex(block, item), kQueued);
|
||||
}
|
||||
|
||||
static int SetFinalize(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return SetBit(block, GetIndex(block, item), kFinalize);
|
||||
}
|
||||
|
||||
static int IsWhite(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
|
||||
// not a real item
|
||||
if(item < block->items)
|
||||
return false;
|
||||
|
||||
if(FindBeginning(item) != item)
|
||||
return false;
|
||||
|
||||
return IsWhite(block, GetIndex(block, item));
|
||||
}
|
||||
|
||||
|
||||
static int GetMark(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
|
||||
// Return the "marked" bit
|
||||
return GetBit(block, GetIndex(block, item), kMark);
|
||||
}
|
||||
|
||||
static void *FindBeginning(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
|
||||
return block->items + block->size * GetIndex(block, item);
|
||||
}
|
||||
|
||||
static void ClearFinalized(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
ClearBits(block, GetIndex(block, item), kFinalize);
|
||||
}
|
||||
|
||||
static int IsFinalized(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return GetBit(block, GetIndex(block, item), kFinalize);
|
||||
}
|
||||
static int HasWeakRef(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return GetBit(block, GetIndex(block, item), kHasWeakRef);
|
||||
}
|
||||
|
||||
static bool ContainsPointers(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return block->alloc->ContainsPointers();
|
||||
}
|
||||
|
||||
static bool IsRCObject(const void *item)
|
||||
{
|
||||
// Zero low 12 bits of address to get to the Block header
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
return item >= block->items && block->alloc->IsRCObject();
|
||||
}
|
||||
|
||||
static bool IsUnmarkedPointer(const void *val);
|
||||
|
||||
int GetNumAlloc() const { return m_numAlloc; }
|
||||
int GetMaxAlloc() const { return m_maxAlloc; }
|
||||
int GetNumBlocks() const { return m_numBlocks; }
|
||||
|
||||
bool ContainsPointers() const { return containsPointers; }
|
||||
bool IsRCObject() const { return containsRCObjects; }
|
||||
|
||||
void GetBitsPages(void **pages);
|
||||
|
||||
static void SetHasWeakRef(const void *item, bool to)
|
||||
{
|
||||
GCBlock *block = (GCBlock*) ((uint32)item & ~0xFFF);
|
||||
if(to) {
|
||||
SetBit(block, GetIndex(block, item), kHasWeakRef);
|
||||
} else {
|
||||
ClearBits(block, GetIndex(block, item), kHasWeakRef);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const static int kBlockSize = 4096;
|
||||
|
||||
struct GCBlock;
|
||||
|
||||
friend struct GCAlloc::GCBlock;
|
||||
|
||||
struct GCBlock
|
||||
{
|
||||
GC *gc;
|
||||
uint32 size;
|
||||
GCAlloc *alloc;
|
||||
char* nextItem;
|
||||
void* firstFree; // first item on free list
|
||||
GCBlock* next;
|
||||
GCBlock* prev;
|
||||
GCBlock *prevFree;
|
||||
GCBlock *nextFree;
|
||||
uint32* bits;
|
||||
short numItems;
|
||||
bool needsSweeping;
|
||||
char *items;
|
||||
|
||||
int GetCount() const
|
||||
{
|
||||
if (nextItem) {
|
||||
return GCAlloc::GetIndex(this, nextItem);
|
||||
} else {
|
||||
return alloc->m_itemsPerBlock;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 *GetBits() const
|
||||
{
|
||||
return bits;
|
||||
}
|
||||
|
||||
void FreeItem(void *item, int index);
|
||||
|
||||
bool IsFull()
|
||||
{
|
||||
bool full = (nextItem == firstFree);
|
||||
// the only time nextItem and firstFree should be equal is when they
|
||||
// are both zero which is also when we are full, assert to be sure
|
||||
GCAssert(!full || nextItem==0);
|
||||
GCAssert(!full || numItems == alloc->m_itemsPerBlock);
|
||||
return full;
|
||||
}
|
||||
};
|
||||
|
||||
// The list of chunk blocks
|
||||
GCBlock* m_firstBlock;
|
||||
GCBlock* m_lastBlock;
|
||||
|
||||
// The lowest priority block that has free items
|
||||
GCBlock* m_firstFree;
|
||||
|
||||
int m_itemsPerBlock;
|
||||
size_t m_itemSize;
|
||||
int m_numBitmapBytes;
|
||||
int m_sizeClassIndex;
|
||||
|
||||
bool m_bitsInPage;
|
||||
|
||||
int m_maxAlloc;
|
||||
int m_numAlloc;
|
||||
int m_numBlocks;
|
||||
|
||||
// fast divide numbers
|
||||
uint16 multiple;
|
||||
uint16 shift;
|
||||
|
||||
bool containsPointers;
|
||||
bool containsRCObjects;
|
||||
|
||||
|
||||
|
||||
GCBlock* CreateChunk();
|
||||
void UnlinkChunk(GCBlock *b);
|
||||
void FreeChunk(GCBlock* b);
|
||||
void AddToFreeList(GCBlock *b)
|
||||
{
|
||||
GCAssert(b->nextFree == NULL && b->prevFree == NULL);
|
||||
b->prevFree = NULL;
|
||||
b->nextFree = m_firstFree;
|
||||
if (m_firstFree) {
|
||||
GCAssert(m_firstFree->prevFree == 0);
|
||||
m_firstFree->prevFree = b;
|
||||
}
|
||||
m_firstFree = b;
|
||||
}
|
||||
|
||||
void RemoveFromFreeList(GCBlock *b)
|
||||
{
|
||||
GCAssert(m_firstFree == b || b->prevFree != NULL);
|
||||
if ( m_firstFree == b )
|
||||
m_firstFree = b->nextFree;
|
||||
else
|
||||
b->prevFree->nextFree = b->nextFree;
|
||||
|
||||
if (b->nextFree)
|
||||
b->nextFree->prevFree = b->prevFree;
|
||||
}
|
||||
bool Sweep(GCBlock *b);
|
||||
|
||||
bool IsLastFreeBlock(GCBlock *b) { return m_firstFree == NULL || (m_firstFree == b && b->nextFree == NULL); }
|
||||
|
||||
static int ConservativeGetMark(const void *item, bool bogusPointerReturnValue);
|
||||
|
||||
static int GetIndex(const GCBlock *block, const void *item)
|
||||
{
|
||||
int index = (((char*) item - block->items) * block->alloc->multiple) >> block->alloc->shift;
|
||||
#ifdef _DEBUG
|
||||
GCAssert(((char*) item - block->items) / block->size == (uint32) index);
|
||||
#endif
|
||||
return index;
|
||||
}
|
||||
|
||||
static int IsWhite(GCBlock *block, int index)
|
||||
{
|
||||
return (block->GetBits()[index>>3] & ((kMark|kQueued)<<((index&7)<<2))) == 0;
|
||||
}
|
||||
|
||||
static int SetBit(GCBlock *block, int index, int bit)
|
||||
{
|
||||
int mask = bit << ((index&7)<<2);
|
||||
int set = (block->GetBits()[index>>3] & mask);
|
||||
block->GetBits()[index>>3] |= mask;
|
||||
return set;
|
||||
}
|
||||
|
||||
static int GetBit(GCBlock *block, int index, int bit)
|
||||
{
|
||||
int mask = bit << ((index&7)<<2);
|
||||
return block->GetBits()[index>>3] & mask;
|
||||
}
|
||||
|
||||
static void ClearBits(GCBlock *block, int index, int bits)
|
||||
{
|
||||
int mask = bits << ((index&7)<<2);
|
||||
block->GetBits()[index>>3] &= ~mask;
|
||||
}
|
||||
|
||||
void ComputeMultiplyShift(uint16 d, uint16 &muli, uint16 &shft);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCAlloc__ */
|
||||
@@ -1,71 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
#include "GCDebug.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/* Returns the number of bits set in val.
|
||||
* For a derivation of this algorithm, see
|
||||
* "Algorithms and data structures with applications to
|
||||
* graphics and geometry", by Jurg Nievergelt and Klaus Hinrichs,
|
||||
* Prentice Hall, 1993.
|
||||
*/
|
||||
int GCAllocBase::CountBits(uint32 value)
|
||||
{
|
||||
value -= (value & 0xaaaaaaaaL) >> 1;
|
||||
value = (value & 0x33333333L) + ((value >> 2) & 0x33333333L);
|
||||
value = (value + (value >> 4)) & 0x0f0f0f0fL;
|
||||
value += value >> 8;
|
||||
value += value >> 16;
|
||||
return (int)value & 0xff;
|
||||
}
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
void GCAllocBase::WriteBackPointer(const void *item, const void *container, size_t itemSize)
|
||||
{
|
||||
GCAssert(container != NULL);
|
||||
int *p = (int*) item;
|
||||
size_t size = *p++;
|
||||
if(size && size <= itemSize) {
|
||||
// skip traceIndex + data + endMarker
|
||||
p += (2 + (size>>2));
|
||||
GCAssert(sizeof(int) == sizeof(void*));
|
||||
*p = (int) container;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCAllocBase__
|
||||
#define __GCAllocBase__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
class GC;
|
||||
|
||||
/**
|
||||
* This is a base class for the GC allocators.
|
||||
*/
|
||||
class GCAllocBase : public GCAllocObject
|
||||
{
|
||||
public:
|
||||
GCAllocBase(GC *gc) { m_gc = gc; }
|
||||
virtual ~GCAllocBase() {}
|
||||
|
||||
|
||||
#ifdef MMGC_IA32
|
||||
static inline uint32 FindOneBit(uint32 value)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
_asm
|
||||
{
|
||||
bsr eax,[value];
|
||||
}
|
||||
#else
|
||||
// DBC - This gets rid of a compiler warning and matchs PPC results where value = 0
|
||||
register int result = ~0;
|
||||
|
||||
if (value)
|
||||
{
|
||||
asm (
|
||||
"bsr %1, %0"
|
||||
: "=r" (result)
|
||||
: "m"(value)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MMGC_PPC
|
||||
static inline int FindOneBit(uint32 value)
|
||||
{
|
||||
register int index;
|
||||
#ifdef DARWIN
|
||||
asm ("cntlzw %0,%1" : "=r" (index) : "r" (value));
|
||||
#else
|
||||
register uint32 in = value;
|
||||
asm { cntlzw index, in; }
|
||||
#endif
|
||||
return 31-index;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int CountBits(uint32 value);
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
// debugging routine that records who marked who, can be used to
|
||||
// answer the question, how did I get marked? also could be used to
|
||||
// find false positives by verifying the back pointer chain gets back
|
||||
// to a GC root
|
||||
static void WriteBackPointer(const void *item, const void *container, size_t itemSize);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
GC *m_gc;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCAllocBase__ */
|
||||
@@ -1,59 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCAllocObject__
|
||||
#define __GCAllocObject__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* GCAllocObject is a base class for allocated objects. MMgc
|
||||
* cannot have any dependency on the C runtime library, because
|
||||
* Flash Player does not. MMgc also cannot rely on global
|
||||
* operator new and delete, because it may be used to implement
|
||||
* them! So, GCAllocObject provides a simple operator new and
|
||||
* delete implementation for classes used internally by MMgc.
|
||||
*
|
||||
* The implementation of GCAllocObject is platform-dependent.
|
||||
*/
|
||||
class GCAllocObject
|
||||
{
|
||||
public:
|
||||
void* operator new (size_t size);
|
||||
void* operator new [] (size_t size);
|
||||
void operator delete (void *ptr);
|
||||
void operator delete [] (void *ptr);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCAllocObject__ */
|
||||
@@ -1,81 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
#if TARGET_API_MAC_CARBON
|
||||
void* GCAllocObject::operator new (size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void* GCAllocObject::operator new[] (size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete (void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete[](void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#else
|
||||
void* GCAllocObject::operator new (size_t size)
|
||||
{
|
||||
return NewPtr(size);
|
||||
}
|
||||
|
||||
void* GCAllocObject::operator new[] (size_t size)
|
||||
{
|
||||
return NewPtr(size);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete (void *ptr)
|
||||
{
|
||||
DisposePtr((char*) ptr);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete[](void *ptr)
|
||||
{
|
||||
DisposePtr((char*) ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
void* GCAllocObject::operator new (size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void* GCAllocObject::operator new[] (size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete (void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete [] (void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
void* GCAllocObject::operator new (size_t size)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
}
|
||||
|
||||
void* GCAllocObject::operator new[] (size_t size)
|
||||
{
|
||||
return HeapAlloc(GetProcessHeap(), 0, size);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete (void *ptr)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ptr);
|
||||
}
|
||||
|
||||
void GCAllocObject::operator delete [] (void *ptr)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#ifndef __GCDebug__
|
||||
#define __GCDebug__
|
||||
|
||||
#include "GCTypes.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MAC
|
||||
typedef const unsigned char* ConstStr255Param;
|
||||
extern "C"
|
||||
{
|
||||
#if defined(TARGET_RT_MAC_MACHO) // DBC
|
||||
//extern pascal void DebugStr(ConstStr255Param aStr);
|
||||
#else
|
||||
// extern pascal void DebugStr(ConstStr255Param aStr) = 0xABFF;
|
||||
extern pascal void SysBreakStr(ConstStr255Param aStr) = {0x303C, 0xFE15, 0xA9C9};
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
void GCDebugMsg(bool debuggerBreak, const char* format, ...);
|
||||
void GCDebugMsg(const char* msg, bool debuggerBreak);
|
||||
void GCDebugMsg(const wchar* msg, bool debuggerBreak);
|
||||
|
||||
#ifdef _DEBUG
|
||||
inline void _GCAssertMsg(int32 assertion, const char* msg)
|
||||
{
|
||||
if (assertion == 0)
|
||||
GCDebugMsg(msg, true);
|
||||
}
|
||||
|
||||
#define GCAssertMsg(x,y) do { _GCAssertMsg((x), (y)); } while (0) /* no semi */
|
||||
|
||||
#define GCAssert(x) _GCAssert((x), __LINE__,__FILE__)
|
||||
#define _GCAssert(x, line_, file_) __GCAssert((x), line_, file_)
|
||||
#define __GCAssert(x, line_, file_) do { _GCAssertMsg((x), "Assertion failed: \"" #x "\" (" #file_ ":" #line_ ")"); } while (0) /* no semi */
|
||||
|
||||
#else
|
||||
#define GCAssertMsg(x,y) do { } while (0) /* no semi */
|
||||
#define GCAssert(x) do { } while (0) /* no semi */
|
||||
#endif
|
||||
|
||||
/*************************************************************************/
|
||||
/******************************* Debugging *******************************/
|
||||
/*************************************************************************/
|
||||
|
||||
/* This mess serves to define the DebugMsg function on each platform.
|
||||
* DebugMsg is only defined when the Debug flag is turned on; it halts
|
||||
* program execution and drops into the debugger with the given message.
|
||||
* We define it as in inline so that when you fall into the debugger,
|
||||
* you're in the function that issued the call and not in a "DebugMsg"
|
||||
* subroutine.
|
||||
*/
|
||||
#ifdef _MAC
|
||||
// WARNING: this function is NOT THREAD SAFE
|
||||
/*plugin_export*/ ConstStr255Param MakePascalMsg(const char* theString);
|
||||
|
||||
#if SOFT_ASSERTS
|
||||
inline void DebugMsg_(const char* /*msg*/) { }
|
||||
#else
|
||||
#ifdef powerc
|
||||
inline void DebugMsg_(const char* msg) { DebugStr(MakePascalMsg(msg)); }
|
||||
#else
|
||||
inline void DebugMsg_(const char* msg) { SysBreakStr(MakePascalMsg(msg)); }
|
||||
#endif
|
||||
#endif // SOFT_ASSERTS
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif /* __GCDebug__ */
|
||||
@@ -1,123 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#ifndef __MWERKS__
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
#ifndef __MACH__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
void GCDebugMsg(bool debuggerBreak, const char* format, ...)
|
||||
{
|
||||
char buf[4096];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
#if TARGET_API_MAC_CARBON
|
||||
vsprintf(buf, format, args);
|
||||
#else
|
||||
char *bufptr = buf;
|
||||
// copied from flashstring
|
||||
while (*format) {
|
||||
if (*format == '%') {
|
||||
switch (*++format) {
|
||||
case 's':
|
||||
strcpy(bufptr, va_arg(args, char *));
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
int i = va_arg(args, int);
|
||||
if (!i) {
|
||||
*bufptr++ = '0';
|
||||
} else {
|
||||
if (i < 0) {
|
||||
*bufptr++ = '-';
|
||||
i = -i;
|
||||
}
|
||||
int n = 0;
|
||||
char m_buf[128];
|
||||
while (i > 0) {
|
||||
int v = (i % 10);
|
||||
m_buf[n++] = (v<10) ? (v+'0') : (v-10+'a');
|
||||
i /= 10;
|
||||
}
|
||||
char* c = m_buf+n;
|
||||
while (n--) {
|
||||
*bufptr++ = (*--c);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
*bufptr++ = va_arg(args, char);
|
||||
break;
|
||||
case 0:
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
*bufptr = *format;
|
||||
}
|
||||
format++;
|
||||
bufptr++;
|
||||
}
|
||||
#endif
|
||||
va_end(args);
|
||||
GCDebugMsg(buf, debuggerBreak);
|
||||
}
|
||||
|
||||
void GCDebugMsg(const char* p, bool debugBreak)
|
||||
{
|
||||
char buf[256];
|
||||
strcpy(buf, p);
|
||||
if(debugBreak) {
|
||||
#if TARGET_API_MAC_CARBON
|
||||
::CopyCStringToPascal(buf, (StringPtr)buf);
|
||||
#else
|
||||
c2pstr(buf);
|
||||
#endif
|
||||
DebugStr((StringPtr) buf);
|
||||
} else {
|
||||
CFStringRef cfStr = ::CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
|
||||
::CFShow(cfStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
void GCDebugMsg(bool debuggerBreak, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void GCDebugMsg(const char* p, bool debugBreak)
|
||||
{
|
||||
fprintf(stderr, "%s\n", p);
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <malloc.h>
|
||||
#include <strsafe.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
/******************************* Debugging *******************************/
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MB_SERVICE_NOTIFICATION
|
||||
#define MB_SERVICE_NOTIFICATION 0x00200000L
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
static const bool logToStdErr = true;
|
||||
|
||||
void GCDebugMsg(bool debuggerBreak, const char *format, ...)
|
||||
{
|
||||
// [ggrossman 09.24.04]
|
||||
// Changed this to _DEBUG only because we don't link to
|
||||
// CRT in Release builds, so vsprintf is unavailable!!
|
||||
#ifdef _DEBUG
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
int bufferSize = _vscprintf(format, argptr)+1;
|
||||
|
||||
char *buffer = (char*)alloca(bufferSize+2);
|
||||
if (buffer) {
|
||||
StringCbVPrintf(buffer, bufferSize+1, format, argptr);
|
||||
GCDebugMsg(buffer, debuggerBreak);
|
||||
}
|
||||
#else
|
||||
(void)debuggerBreak;
|
||||
(void)format;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GCDebugMsg(const char* msg, bool debugBreak)
|
||||
{
|
||||
OutputDebugString(msg);
|
||||
if(logToStdErr) {
|
||||
fprintf( stderr, "%s\n", msg );
|
||||
}
|
||||
|
||||
if (debugBreak) {
|
||||
DebugBreak();
|
||||
}
|
||||
}
|
||||
|
||||
void GCDebugMsg(const wchar* msg, bool debugBreak)
|
||||
{
|
||||
OutputDebugStringW((LPCWSTR)msg);
|
||||
if(logToStdErr) {
|
||||
fprintf( stderr, "%S\n", msg );
|
||||
}
|
||||
|
||||
if (debugBreak) {
|
||||
DebugBreak();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
const void *GCHashtable::DELETED = (const void*)1;
|
||||
|
||||
GCHashtable::GCHashtable(unsigned int capacity)
|
||||
{
|
||||
tableSize = capacity*2;
|
||||
table = new const void*[tableSize];
|
||||
memset(table, 0, tableSize * sizeof(void*));
|
||||
numValues = 0;
|
||||
numDeleted = 0;
|
||||
}
|
||||
|
||||
GCHashtable::~GCHashtable()
|
||||
{
|
||||
delete [] table;
|
||||
table = 0;
|
||||
tableSize = 0;
|
||||
numDeleted = 0;
|
||||
numValues = 0;
|
||||
}
|
||||
|
||||
void GCHashtable::put(const void *key, const void *value)
|
||||
{
|
||||
int i = find(key, table, tableSize);
|
||||
if (table[i] != key) {
|
||||
// .75 load factor, note we don't take numDeleted into account
|
||||
// we want to rehash a table with lots of deleted slots
|
||||
if(numValues * 8 > tableSize * 3)
|
||||
{
|
||||
grow();
|
||||
// grow rehashes
|
||||
i = find(key, table, tableSize);
|
||||
}
|
||||
table[i] = key;
|
||||
numValues++;
|
||||
}
|
||||
table[i+1] = value;
|
||||
}
|
||||
|
||||
const void *GCHashtable::remove(const void *key)
|
||||
{
|
||||
const void *ret = NULL;
|
||||
int i = find(key, table, tableSize);
|
||||
if (table[i] == key) {
|
||||
table[i] = (const void*)DELETED;
|
||||
ret = table[i+1];
|
||||
table[i+1] = NULL;
|
||||
numDeleted++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const void *GCHashtable::get(const void *key)
|
||||
{
|
||||
return table[find(key, table, tableSize)+1];
|
||||
}
|
||||
|
||||
/* static */
|
||||
int GCHashtable::find(const void *key, const void **table, unsigned int tableSize)
|
||||
{
|
||||
GCAssert(key != (const void*)DELETED);
|
||||
int bitmask = (tableSize - 1) & ~0x1;
|
||||
|
||||
// this is a quadratic probe but we only hit even numbered slots since those hold keys.
|
||||
int n = 7 << 1;
|
||||
#ifdef _DEBUG
|
||||
unsigned loopCount = 0;
|
||||
#endif
|
||||
// Note: Mask off MSB to avoid negative indices. Mask off bottom
|
||||
// 2 bits because of alignment. Double it because names, values stored adjacently.
|
||||
unsigned i = ((0x7FFFFFF8 & (int)key)>>1) & bitmask;
|
||||
const void *k;
|
||||
while ((k=table[i]) != key && k != NULL)
|
||||
{
|
||||
i = (i + (n += 2)) & bitmask; // quadratic probe
|
||||
GCAssert(loopCount++ < tableSize); // don't scan forever
|
||||
}
|
||||
GCAssert(i <= ((tableSize-1)&~0x1));
|
||||
return i;
|
||||
}
|
||||
|
||||
void GCHashtable::grow()
|
||||
{
|
||||
int newTableSize = tableSize;
|
||||
|
||||
unsigned int occupiedSlots = numValues - numDeleted;
|
||||
GCAssert(numValues >= numDeleted);
|
||||
|
||||
// grow or shrink as appropriate:
|
||||
// if we're greater than %50 full grow
|
||||
// if we're less than %10 shrink
|
||||
// else stay the same
|
||||
if (4*occupiedSlots > tableSize)
|
||||
newTableSize <<= 1;
|
||||
else if(20*occupiedSlots < tableSize &&
|
||||
tableSize > kDefaultSize)
|
||||
newTableSize >>= 1;
|
||||
|
||||
const void **newTable = new const void*[newTableSize];
|
||||
memset(newTable, 0, newTableSize*sizeof(void*));
|
||||
|
||||
numValues = 0;
|
||||
numDeleted = 0;
|
||||
|
||||
for (int i=0, n=tableSize; i < n; i += 2)
|
||||
{
|
||||
const void *oldKey;
|
||||
if ((oldKey=table[i]) != NULL)
|
||||
{
|
||||
// inlined & simplified version of put()
|
||||
if(oldKey != (const void*)DELETED) {
|
||||
int j = find(oldKey, newTable, newTableSize);
|
||||
newTable[j] = oldKey;
|
||||
newTable[j+1] = table[i+1];
|
||||
numValues++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] table;
|
||||
table = newTable;
|
||||
tableSize = newTableSize;
|
||||
}
|
||||
|
||||
int GCHashtable::nextIndex(int index)
|
||||
{
|
||||
unsigned int i = index<<1;
|
||||
while(i < tableSize)
|
||||
{
|
||||
if(table[i] > DELETED)
|
||||
return (i>>1)+1;
|
||||
i += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCHashtable__
|
||||
#define __GCHashtable__
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
class GCHashtableIterator;
|
||||
/**
|
||||
* simplified version of avmplus hashtable, doesn't shrink or handle deletions for instance
|
||||
*/
|
||||
class GCHashtable
|
||||
{
|
||||
friend class GCHashtableIterator;
|
||||
public:
|
||||
const static uint32 kDefaultSize=16;
|
||||
const static void * DELETED;
|
||||
GCHashtable(unsigned int capacity=kDefaultSize);
|
||||
~GCHashtable();
|
||||
const void *get(const void *key);
|
||||
const void *get(int key) { return get((const void*)key); }
|
||||
const void *remove(const void *key);
|
||||
// updates value if present, adds and grows if necessary if not
|
||||
void put(const void *key, const void *value);
|
||||
void add(const void *key, const void *value) { put(key, value); }
|
||||
void add(int key, const void *value) { put((const void*)key, value); }
|
||||
int count() { return numValues; }
|
||||
|
||||
int nextIndex(int index);
|
||||
const void *keyAt(int index) { return table[index<<1]; }
|
||||
const void *valueAt(int index) { return table[((index)<<1)+1]; }
|
||||
|
||||
private:
|
||||
// capacity
|
||||
unsigned int tableSize;
|
||||
|
||||
// size of table array
|
||||
unsigned int numValues;
|
||||
|
||||
// number of delete items
|
||||
unsigned int numDeleted;
|
||||
|
||||
// table elements
|
||||
const void **table;
|
||||
|
||||
static int find(const void *key, const void **table, unsigned int tableSize);
|
||||
void grow();
|
||||
};
|
||||
|
||||
class GCHashtableIterator
|
||||
{
|
||||
public:
|
||||
GCHashtableIterator(GCHashtable *ht) : ht(ht), index(-2) {}
|
||||
|
||||
const void *nextKey()
|
||||
{
|
||||
do {
|
||||
index+=2;
|
||||
} while(index < (int)ht->tableSize && ht->table[index] <= GCHashtable::DELETED);
|
||||
if(index < (int)ht->tableSize)
|
||||
return ht->table[index];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const void *value()
|
||||
{
|
||||
GCAssert(ht->table[index] != NULL);
|
||||
return ht->table[index+1];
|
||||
}
|
||||
|
||||
void remove()
|
||||
{
|
||||
GCAssert(ht->table[index] != NULL);
|
||||
ht->table[index] = (const void*)GCHashtable::DELETED;
|
||||
ht->table[index+1] = NULL;
|
||||
}
|
||||
private:
|
||||
GCHashtable *ht;
|
||||
int index;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,392 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCHeap__
|
||||
#define __GCHeap__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* GCHeap is a heap manager for the Flash Player's garbage collector.
|
||||
*
|
||||
* Memory is allocated from the operating system in large chunks
|
||||
* aligned on page boundaries (4096-byte aligned). All allocation
|
||||
* requests are specified in numbers of 4096-byte pages. The first
|
||||
* 4 bytes of each page is reserved for GCHeap's use.
|
||||
*
|
||||
* Allocations may fail if there is no free block large enough
|
||||
* to satisfy the request. When this occurs, the GC class will
|
||||
* choose to either garbage collect or expand the heap, and then
|
||||
* call GCHeap again to retry the allocation.
|
||||
*
|
||||
* When blocks are freed, they are coalesced with their neighbors
|
||||
* when possible to reduce fragmentation. A "boundary tag" scheme
|
||||
* similar to Doug Lea's malloc is used to make coalescing fast.
|
||||
* To keep things simple, coalescing is always performed immediately
|
||||
* when a block is freed, and not deferred.
|
||||
*
|
||||
* Allocations are performed using multiple free lists. Blocks that
|
||||
* are <= kUniqueThreshold pages in size get their own free list.
|
||||
* Blocks above the threshold get mapped to more granular free lists,
|
||||
* and all blocks above kHugeThreshold get mapped to the last free list.
|
||||
* This approach is borrowed from Hans Boehm's C/C++ Garbage Collector.
|
||||
*
|
||||
* Free lists are doubly-linked lists sorted in size order. The
|
||||
* sorting is done to ensure best-fit allocation. Each free list
|
||||
* is itself a list node, and the lists are circular, in a technique
|
||||
* also borrowed from Doug Lea's malloc. This makes for very simple
|
||||
* logic to insert/remove nodes.
|
||||
*
|
||||
* Only Windows is currently supported, although this should be easy
|
||||
* to get working on other platforms. Memory is allocated in large
|
||||
* (64K minimum) chunks using the VirtualAlloc API. Every time the
|
||||
* heap is expanded, a new heap region is created corresponding to
|
||||
* the address space returned by VirtualAlloc. Heap regions are
|
||||
* allocated contiguously if possible to reduce fragmentation.
|
||||
*/
|
||||
class GCHeap : public GCAllocObject
|
||||
{
|
||||
public:
|
||||
// -- Constants
|
||||
|
||||
/** Size of a block */
|
||||
const static int kBlockSize = 4096;
|
||||
|
||||
/** Initial heap size, in blocks */
|
||||
static int kInitialHeapSize;
|
||||
|
||||
/** Default size of address space reserved per region */
|
||||
const static int kDefaultReserve = 4096;
|
||||
|
||||
/** Sizes up to this many blocks each have their own free list. */
|
||||
const static int kUniqueThreshold = 16;
|
||||
|
||||
/**
|
||||
* Sizes of at least this many heap blocks are mapped to a
|
||||
* single free list.
|
||||
*/
|
||||
const static int kHugeThreshold = 128;
|
||||
|
||||
/** In between sizes map this many distinct sizes to a single bin. */
|
||||
const static int kFreeListCompression = 8;
|
||||
|
||||
/** Calculated number of free lists */
|
||||
const static int kNumFreeLists = (kHugeThreshold-kUniqueThreshold)/kFreeListCompression+kUniqueThreshold;
|
||||
|
||||
/** Minimum heap increment, in blocks */
|
||||
const static int kMinHeapIncrement = 32;
|
||||
|
||||
/** if this much of the heap stays free for kDecommitThresholdMillis decommit some memory */
|
||||
const static int kDecommitThresholdPercentage = 25;
|
||||
|
||||
|
||||
static const int kDecommitThresholdMillis = 1000;
|
||||
|
||||
/** The native VM page size (in bytes) for the current architecture */
|
||||
static int kNativePageSize;
|
||||
|
||||
static bool heapVerbose;
|
||||
|
||||
/**
|
||||
* Init must be called to set up the GCHeap singleton
|
||||
*/
|
||||
static void Init(GCMallocFuncPtr malloc = NULL, GCFreeFuncPtr free = NULL);
|
||||
|
||||
/**
|
||||
* Destroy the GCHeap singleton
|
||||
*/
|
||||
static void Destroy();
|
||||
|
||||
/**
|
||||
* Get the GCHeap singleton
|
||||
*/
|
||||
static GCHeap *GetGCHeap() { GCAssert(instance != NULL); return instance; }
|
||||
|
||||
/**
|
||||
* Allocates a block from the heap.
|
||||
* @param size the number of pages (kBlockSize bytes apiece)
|
||||
* to allocate.
|
||||
* @return pointer to beginning of block, or NULL if failed.
|
||||
*/
|
||||
void *Alloc(int size, bool expand=true, bool zero=true);
|
||||
|
||||
/**
|
||||
* Frees a block.
|
||||
* @param item the block to free. This must be the same
|
||||
* pointer that was previously returned by
|
||||
* a call to Alloc.
|
||||
*/
|
||||
void Free(void *item);
|
||||
|
||||
size_t Size(const void *item);
|
||||
|
||||
/**
|
||||
* Expands the heap by size pages.
|
||||
*
|
||||
* Expands the heap by "size" blocks, such that a single contiguous
|
||||
* allocation of "size" blocks can be performed. This method is
|
||||
* also called to create the initial heap.
|
||||
*
|
||||
* On Windows, this uses the VirtualAlloc API to obtain memory.
|
||||
* VirtualAlloc can _reserve_ memory, _commit_ memory or both at
|
||||
* the same time. Reserved memory is just virtual address space.
|
||||
* It consumes the address space of the process but isn't really
|
||||
* allocated yet; there are no pages committed to it yet.
|
||||
* Memory allocation really occurs when reserved pages are
|
||||
* committed. Our strategy in GCHeap is to reserve a fairly large
|
||||
* chunk of address space, and then commit pages from it as needed.
|
||||
* By doing this, we're more likely to get contiguous regions in
|
||||
* memory for our heap.
|
||||
*
|
||||
* By default, we reserve 16MB (4096 pages) per heap region.
|
||||
* The amount to reserve by default is controlled by kDefaultReserve.
|
||||
* That shouldn't be a big deal, as the process address space is 2GB.
|
||||
* As we're usually a plug-in, however, we don't want to make it too
|
||||
* big because it's not all our memory.
|
||||
*
|
||||
* The goal of reserving so much address space is so that subsequent
|
||||
* expansions of the heap are able to obtain contiguous memory blocks.
|
||||
* If we can keep the heap contiguous, that reduces fragmentation
|
||||
* and the possibility of many small "Balkanized" heap regions.
|
||||
*
|
||||
* Algorithm: When an allocation is requested,
|
||||
* 1. If there is enough reserved but uncommitted memory in the
|
||||
* last-created region to satisfy the request, commit that memory
|
||||
* and exit with success, also check decommitted list
|
||||
* 2. Try to reserve a new region contiguous with the last-created
|
||||
* region. Go for a 16MB reservation or the requested size,
|
||||
* whichever is bigger.
|
||||
* 3. If we tried for 16MB reserved space and it didn't work, try
|
||||
* to reserve again, but for the requested size.
|
||||
* 4. If we were able to retrieve a contiguous region in Step 2 or 3,
|
||||
* commit any leftover memory from the last-created region,
|
||||
* commit the remainer from the newly created region, and exit
|
||||
* with success.
|
||||
* 5. OK, the contiguous region didn't work out, so allocate a
|
||||
* non-contiguous region. Go for 16MB or the requested size
|
||||
* again, whichever is bigger.
|
||||
* 6. If we tried for 16MB reserved space and it didn't work, try
|
||||
* to reserve again, but for the requested size.
|
||||
* 7. Commit the requested size out of the newly created region
|
||||
* and exit with success.
|
||||
*
|
||||
* If we are able to reserve memory but can't commit it, then, well
|
||||
* there isn't enough memory. We free the reserved memory and
|
||||
* exit with failure.
|
||||
*
|
||||
* @param size the number of pages to expand the heap by
|
||||
*/
|
||||
bool ExpandHeap(int size);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the used heap size, that is, the total
|
||||
* space actually used by allocated objects.
|
||||
* @return the minimum heap size in pages (kBlockSize bytes apiece)
|
||||
*/
|
||||
unsigned int GetUsedHeapSize() const { return numAlloc; }
|
||||
|
||||
/**
|
||||
* Returns the "free heap size", that is, the difference in the
|
||||
* total heap size and the used heap size
|
||||
* @return the minimum heap size in pages (kBlockSize bytes apiece)
|
||||
*/
|
||||
unsigned int GetFreeHeapSize() const { return GetTotalHeapSize()-numAlloc; }
|
||||
|
||||
/**
|
||||
* Returns the total heap size, that is, the total amount
|
||||
* of space managed by the heap, including all used and
|
||||
* free space.
|
||||
* @return the total heap size in pages (kBlockSize bytes apiece)
|
||||
*/
|
||||
unsigned int GetTotalHeapSize() const { return blocksLen - numDecommitted; }
|
||||
|
||||
/**
|
||||
* gives memory back to the OS when there hasn't been any memory activity in a while
|
||||
* and we have lots of free memory
|
||||
*/
|
||||
void Decommit();
|
||||
private:
|
||||
|
||||
// -- Implementation
|
||||
static GCHeap *instance;
|
||||
GCHeap(GCMallocFuncPtr m, GCFreeFuncPtr f);
|
||||
~GCHeap();
|
||||
|
||||
// Heap regions
|
||||
class Region : public GCAllocObject
|
||||
{
|
||||
public:
|
||||
Region *prev;
|
||||
char *baseAddr;
|
||||
char *reserveTop;
|
||||
char *commitTop;
|
||||
int blockId;
|
||||
};
|
||||
Region *lastRegion;
|
||||
|
||||
// Block struct used for free lists and memory traversal
|
||||
class HeapBlock : public GCAllocObject
|
||||
{
|
||||
public:
|
||||
char *baseAddr; // base address of block's memory
|
||||
int size; // size of this block
|
||||
int sizePrevious; // size of previous block
|
||||
HeapBlock *prev; // prev entry on free list
|
||||
HeapBlock *next; // next entry on free list
|
||||
bool committed; // is block fully committed?
|
||||
bool dirty; // needs zero'ing, only valid if committed
|
||||
#ifdef MEMORY_INFO
|
||||
int allocTrace;
|
||||
#endif
|
||||
bool inUse() { return prev == NULL; }
|
||||
};
|
||||
|
||||
bool ExpandHeapPrivate(int size);
|
||||
|
||||
// Core data structures
|
||||
HeapBlock *blocks;
|
||||
unsigned int blocksLen;
|
||||
unsigned int numDecommitted;
|
||||
HeapBlock freelists[kNumFreeLists];
|
||||
unsigned int numAlloc;
|
||||
|
||||
// Core methods
|
||||
void AddToFreeList(HeapBlock *block);
|
||||
void AddToFreeList(HeapBlock *block, HeapBlock* pointToInsert);
|
||||
HeapBlock *AllocBlock(int size, bool& zero);
|
||||
void FreeBlock(HeapBlock *block);
|
||||
void FreeAll();
|
||||
|
||||
HeapBlock *Split(HeapBlock *block, int size);
|
||||
|
||||
#ifdef DECOMMIT_MEMORY
|
||||
void Commit(HeapBlock *block);
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
friend class GC;
|
||||
#endif
|
||||
HeapBlock *AddrToBlock(const void *item) const;
|
||||
Region *AddrToRegion(const void *item) const;
|
||||
void RemoveRegion(Region *r);
|
||||
|
||||
// only used on mac
|
||||
GCMallocFuncPtr m_malloc;
|
||||
GCFreeFuncPtr m_free;
|
||||
|
||||
// debug only freelist consistency checks
|
||||
void CheckFreelist();
|
||||
bool BlocksAreContiguous(void *item1, void *item2);
|
||||
|
||||
// Remove a block from a free list (inlined for speed)
|
||||
inline void RemoveFromList(HeapBlock *block)
|
||||
{
|
||||
GCAssert(!block->inUse());
|
||||
block->prev->next = block->next;
|
||||
block->next->prev = block->prev;
|
||||
block->next = block->prev = 0;
|
||||
}
|
||||
|
||||
|
||||
// Map a number of blocks to the appropriate large block free list index
|
||||
// (inlined for speed)
|
||||
inline int GetFreeListIndex(int size)
|
||||
{
|
||||
if (size <= kUniqueThreshold) {
|
||||
return size-1;
|
||||
} else if (size >= kHugeThreshold) {
|
||||
return kNumFreeLists-1;
|
||||
} else {
|
||||
return (size-kUniqueThreshold)/kFreeListCompression+kUniqueThreshold-1;
|
||||
}
|
||||
}
|
||||
|
||||
// used for decommit smoothing
|
||||
// millis to wait before decommitting anything
|
||||
uint64 decommitTicks;
|
||||
uint64 decommitThresholdTicks;
|
||||
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCSpinLock m_spinlock;
|
||||
#endif /* GCHEAP_LOCK */
|
||||
|
||||
#ifdef MMGC_AVMPLUS
|
||||
// OS abstraction to determine native page size
|
||||
int vmPageSize();
|
||||
size_t committedCodeMemory;
|
||||
|
||||
#ifdef WIN32
|
||||
bool useGuardPages;
|
||||
#endif
|
||||
public:
|
||||
// support for jit buffers
|
||||
void* ReserveCodeMemory(void* address, size_t size);
|
||||
void* CommitCodeMemory(void* address, size_t size=0); // size=0 => 1 page
|
||||
void* DecommitCodeMemory(void* address, size_t size=0); // size=0 => 1 page
|
||||
void ReleaseCodeMemory(void* address, size_t size);
|
||||
bool SetGuardPage(void *address);
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
void SetExecuteBit(void *address, size_t size, bool executeFlag);
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
size_t GetCodeMemorySize() const { return committedCodeMemory; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_MMAP
|
||||
public:
|
||||
char *ReserveMemory(char *address, size_t size);
|
||||
bool CommitMemory(char *address, size_t size);
|
||||
bool DecommitMemory(char *address, size_t size);
|
||||
void ReleaseMemory(char *address, size_t size);
|
||||
|
||||
|
||||
bool CommitMemoryThatMaySpanRegions(char *address, size_t size);
|
||||
bool DecommitMemoryThatMaySpanRegions(char *address, size_t size);
|
||||
#else
|
||||
char *AllocateMemory(size_t size);
|
||||
void ReleaseMemory(char *address);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _DEBUG
|
||||
/* m_megamap is a debugging aid for finding bugs in this
|
||||
memory allocator. It tracks allocated/free pages in
|
||||
the crudest way possible ... a 1MB byte array with a
|
||||
0/1 byte for every page in the 32-bit address space. */
|
||||
static uint8 m_megamap[1048576];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCHeap__ */
|
||||
@@ -1,368 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
#include "GC.h"
|
||||
|
||||
#ifdef USE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MACH__)
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MAC
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#if defined(MMGC_IA32) && defined(MEMORY_INFO)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
#ifndef USE_MMAP
|
||||
void *aligned_malloc(size_t size, size_t align_size, GCMallocFuncPtr m_malloc)
|
||||
{
|
||||
char *ptr, *ptr2, *aligned_ptr;
|
||||
int align_mask = align_size - 1;
|
||||
|
||||
int alloc_size = size + align_size + sizeof(int);
|
||||
ptr=(char *)m_malloc(alloc_size);
|
||||
|
||||
if(ptr==NULL) return(NULL);
|
||||
|
||||
ptr2 = ptr + sizeof(int);
|
||||
aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
|
||||
|
||||
ptr2 = aligned_ptr - sizeof(int);
|
||||
*((int *)ptr2)=(int)(aligned_ptr - ptr);
|
||||
|
||||
return(aligned_ptr);
|
||||
}
|
||||
|
||||
void aligned_free(void *ptr, GCFreeFuncPtr m_free)
|
||||
{
|
||||
int *ptr2=(int *)ptr - 1;
|
||||
char *unaligned_ptr = (char*) ptr - *ptr2;
|
||||
m_free(unaligned_ptr);
|
||||
}
|
||||
#endif /* !USE_MMAP */
|
||||
|
||||
#ifdef MMGC_AVMPLUS
|
||||
#ifdef USE_MMAP
|
||||
int GCHeap::vmPageSize()
|
||||
{
|
||||
long v = sysconf(_SC_PAGESIZE);
|
||||
if (v == -1) v = 4096; // Mac 10.1 needs this
|
||||
return v;
|
||||
}
|
||||
|
||||
void* GCHeap::ReserveCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (munmap(address, size) != 0)
|
||||
GCAssert(false);
|
||||
}
|
||||
|
||||
bool GCHeap::SetGuardPage(void* /*address*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
/**
|
||||
* SetExecuteBit changes the page access protections on a block of pages,
|
||||
* to make JIT-ted code executable or not.
|
||||
*
|
||||
* If executableFlag is true, the memory is made executable and read-only.
|
||||
*
|
||||
* If executableFlag is false, the memory is made non-executable and
|
||||
* read-write.
|
||||
*/
|
||||
void GCHeap::SetExecuteBit(void *address,
|
||||
size_t size,
|
||||
bool executableFlag)
|
||||
{
|
||||
// mprotect requires that the addresses be aligned on page boundaries
|
||||
void *endAddress = (void*) ((char*)address + size);
|
||||
void *beginPage = (void*) ((size_t)address & ~0xFFF);
|
||||
void *endPage = (void*) (((size_t)endAddress + 0xFFF) & ~0xFFF);
|
||||
size_t sizePaged = (size_t)endPage - (size_t)beginPage;
|
||||
|
||||
int retval = mprotect(beginPage, sizePaged,
|
||||
executableFlag ? (PROT_READ|PROT_EXEC) : (PROT_READ|PROT_WRITE));
|
||||
|
||||
GCAssert(retval == 0);
|
||||
(void)retval;
|
||||
}
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
|
||||
void* GCHeap::CommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = GCHeap::kNativePageSize; // default of one page
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
void *res = mmap(address,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
|
||||
-1, 0);
|
||||
#else
|
||||
void *res = mmap(address,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
|
||||
-1, 0);
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
|
||||
if (res == MAP_FAILED)
|
||||
address = 0;
|
||||
else
|
||||
address = (void*)( (int)address + size );
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
void* GCHeap::DecommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = GCHeap::kNativePageSize; // default of one page
|
||||
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
|
||||
-1, 0);
|
||||
GCAssert(addr == address);
|
||||
(void)addr;
|
||||
return address;
|
||||
}
|
||||
#else
|
||||
int GCHeap::vmPageSize()
|
||||
{
|
||||
return 4096;
|
||||
}
|
||||
|
||||
void* GCHeap::ReserveCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return aligned_malloc(size, 4096, m_malloc);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
aligned_free(address, m_free);
|
||||
}
|
||||
|
||||
bool GCHeap::SetGuardPage(void *address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
void GCHeap::SetExecuteBit(void *address,
|
||||
size_t size,
|
||||
bool executableFlag)
|
||||
{
|
||||
// No-op on Mac CFM
|
||||
}
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
|
||||
|
||||
void* GCHeap::CommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return address;
|
||||
}
|
||||
void* GCHeap::DecommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return address;
|
||||
}
|
||||
#endif /* USE_MMAP */
|
||||
#endif /* MMGC_AVMPLUS */
|
||||
|
||||
#ifdef USE_MMAP
|
||||
char* GCHeap::ReserveMemory(char *address, size_t size)
|
||||
{
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
|
||||
// the man page for mmap documents it returns -1 to signal failure.
|
||||
if (addr == (char *)-1) return NULL;
|
||||
|
||||
if(address && address != addr) {
|
||||
// behave like windows and fail if we didn't get the right address
|
||||
ReleaseMemory(addr, size);
|
||||
return NULL;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool GCHeap::CommitMemory(char *address, size_t size)
|
||||
{
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
GCAssert(addr == address);
|
||||
return addr == address;
|
||||
}
|
||||
|
||||
bool GCHeap::DecommitMemory(char *address, size_t size)
|
||||
{
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
|
||||
-1, 0);
|
||||
GCAssert(addr == address);
|
||||
return addr == address;
|
||||
}
|
||||
|
||||
bool GCHeap::CommitMemoryThatMaySpanRegions(char *address, size_t size)
|
||||
{
|
||||
return CommitMemory(address, size);
|
||||
}
|
||||
|
||||
bool GCHeap::DecommitMemoryThatMaySpanRegions(char *address, size_t size)
|
||||
{
|
||||
return DecommitMemory(address, size);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseMemory(char *address, size_t size)
|
||||
{
|
||||
int result = munmap(address, size);
|
||||
GCAssert(result == 0);
|
||||
(void)result;
|
||||
}
|
||||
#else
|
||||
|
||||
char* GCHeap::AllocateMemory(size_t size)
|
||||
{
|
||||
return (char *) aligned_malloc(size, 4096, m_malloc);
|
||||
//return (char *) MPAllocateAligned(size, kMPAllocate4096ByteAligned, 0);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseMemory(char *address)
|
||||
{
|
||||
aligned_free(address, m_free);
|
||||
//MPFree(address);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
|
||||
#ifdef MMGC_PPC
|
||||
// no idea how to do this with codewarrior
|
||||
void GetInfoFromPC(int pc, char *buff, int /*buffSize*/)
|
||||
{
|
||||
sprintf(buff, "0x%x", pc);
|
||||
}
|
||||
|
||||
void GetStackTrace(int *trace, int len, int skip)
|
||||
{
|
||||
register int stackp;
|
||||
int pc;
|
||||
asm("mr %0,r1" : "=r" (stackp));
|
||||
while(skip--) {
|
||||
stackp = *(int*)stackp;
|
||||
}
|
||||
int i=0;
|
||||
// save space for 0 terminator
|
||||
len--;
|
||||
while(i<len && stackp) {
|
||||
pc = *((int*)stackp+2);
|
||||
trace[i++]=pc;
|
||||
stackp = *(int*)stackp;
|
||||
}
|
||||
trace[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MMGC_IA32
|
||||
|
||||
void GetInfoFromPC(int pc, char *buff, int buffSize)
|
||||
{
|
||||
Dl_info dlip;
|
||||
dladdr((void * const)pc, &dlip);
|
||||
snprintf(buff, buffSize, "0x%08x:%s", pc, dlip.dli_sname);
|
||||
}
|
||||
|
||||
void GetStackTrace(int* trace, int len, int skip)
|
||||
{
|
||||
void **ebp;
|
||||
asm("mov %%ebp, %0" : "=r" (ebp));
|
||||
while(skip-- && *ebp)
|
||||
{
|
||||
ebp = (void**)(*ebp);
|
||||
}
|
||||
|
||||
len--;
|
||||
int i=0;
|
||||
while(i<len && *ebp)
|
||||
{
|
||||
trace[i++] = *((int*)ebp+1);
|
||||
ebp = (void**)(*ebp);
|
||||
}
|
||||
trace[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef USE_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "GCDebug.h"
|
||||
#include "MMgc.h"
|
||||
#include "GC.h"
|
||||
|
||||
// avmplus standalone uses UNIX
|
||||
#ifdef _MAC
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
#ifndef USE_MMAP
|
||||
void *aligned_malloc(size_t size, size_t align_size, GCMallocFuncPtr m_malloc)
|
||||
{
|
||||
char *ptr, *ptr2, *aligned_ptr;
|
||||
int align_mask = align_size - 1;
|
||||
|
||||
int alloc_size = size + align_size + sizeof(int);
|
||||
ptr=(char *)m_malloc(alloc_size);
|
||||
|
||||
if(ptr==NULL) return(NULL);
|
||||
|
||||
ptr2 = ptr + sizeof(int);
|
||||
aligned_ptr = ptr2 + (align_size - ((size_t)ptr2 & align_mask));
|
||||
|
||||
ptr2 = aligned_ptr - sizeof(int);
|
||||
*((int *)ptr2)=(int)(aligned_ptr - ptr);
|
||||
|
||||
return(aligned_ptr);
|
||||
}
|
||||
|
||||
void aligned_free(void *ptr, GCFreeFuncPtr m_free)
|
||||
{
|
||||
int *ptr2=(int *)ptr - 1;
|
||||
char *unaligned_ptr = (char*) ptr - *ptr2;
|
||||
m_free(unaligned_ptr);
|
||||
}
|
||||
#endif /* !USE_MMAP */
|
||||
|
||||
#ifdef USE_MMAP
|
||||
int GCHeap::vmPageSize()
|
||||
{
|
||||
long v = sysconf(_SC_PAGESIZE);
|
||||
return v;
|
||||
}
|
||||
|
||||
void* GCHeap::ReserveCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return (char*) mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (munmap(address, size) != 0)
|
||||
GCAssert(false);
|
||||
}
|
||||
|
||||
bool GCHeap::SetGuardPage(void *address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
/**
|
||||
* SetExecuteBit changes the page access protections on a block of pages,
|
||||
* to make JIT-ted code executable or not.
|
||||
*
|
||||
* If executableFlag is true, the memory is made executable and read-only.
|
||||
*
|
||||
* If executableFlag is false, the memory is made non-executable and
|
||||
* read-write.
|
||||
*/
|
||||
void GCHeap::SetExecuteBit(void *address,
|
||||
size_t size,
|
||||
bool executableFlag)
|
||||
{
|
||||
// mprotect requires that the addresses be aligned on page boundaries
|
||||
void *endAddress = (void*) ((char*)address + size);
|
||||
void *beginPage = (void*) ((size_t)address & ~0xFFF);
|
||||
void *endPage = (void*) (((size_t)endAddress + 0xFFF) & ~0xFFF);
|
||||
size_t sizePaged = (size_t)endPage - (size_t)beginPage;
|
||||
|
||||
int retval = mprotect(beginPage, sizePaged,
|
||||
executableFlag ? (PROT_READ|PROT_EXEC) : (PROT_READ|PROT_WRITE));
|
||||
|
||||
GCAssert(retval == 0);
|
||||
}
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
|
||||
void* GCHeap::CommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
void* res;
|
||||
if (size == 0)
|
||||
size = GCHeap::kNativePageSize; // default of one page
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
mmap(address,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
#else
|
||||
mmap(address,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
res = address;
|
||||
|
||||
if (res == address)
|
||||
address = (void*)( (int)address + size );
|
||||
else
|
||||
address = 0;
|
||||
return address;
|
||||
}
|
||||
|
||||
void* GCHeap::DecommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = GCHeap::kNativePageSize; // default of one page
|
||||
|
||||
// release and re-reserve it
|
||||
ReleaseCodeMemory(address, size);
|
||||
address = ReserveCodeMemory(address, size);
|
||||
return address;
|
||||
}
|
||||
#else
|
||||
int GCHeap::vmPageSize()
|
||||
{
|
||||
return 4096;
|
||||
}
|
||||
|
||||
void* GCHeap::ReserveCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return aligned_malloc(size, 4096, m_malloc);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
aligned_free(address, m_free);
|
||||
}
|
||||
|
||||
bool GCHeap::SetGuardPage(void *address)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void* GCHeap::CommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return address;
|
||||
}
|
||||
void* GCHeap::DecommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return address;
|
||||
}
|
||||
#endif /* USE_MMAP */
|
||||
|
||||
#ifdef USE_MMAP
|
||||
char* GCHeap::ReserveMemory(char *address, size_t size)
|
||||
{
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
if(address && address != addr) {
|
||||
// behave like windows and fail if we didn't get the right address
|
||||
ReleaseMemory(addr, size);
|
||||
return NULL;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
bool GCHeap::CommitMemory(char *address, size_t size)
|
||||
{
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
GCAssert(addr == address);
|
||||
return addr == address;
|
||||
}
|
||||
|
||||
bool GCHeap::DecommitMemory(char *address, size_t size)
|
||||
{
|
||||
ReleaseMemory(address, size);
|
||||
// re-reserve it
|
||||
char *addr = (char*)mmap(address,
|
||||
size,
|
||||
PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
|
||||
-1, 0);
|
||||
GCAssert(addr == address);
|
||||
return addr == address;
|
||||
}
|
||||
|
||||
bool GCHeap::CommitMemoryThatMaySpanRegions(char *address, size_t size)
|
||||
{
|
||||
return CommitMemory(address, size);
|
||||
}
|
||||
|
||||
bool GCHeap::DecommitMemoryThatMaySpanRegions(char *address, size_t size)
|
||||
{
|
||||
return DecommitMemory(address, size);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseMemory(char *address, size_t size)
|
||||
{
|
||||
int result = munmap(address, size);
|
||||
GCAssert(result == 0);
|
||||
}
|
||||
#else
|
||||
char* GCHeap::AllocateMemory(size_t size)
|
||||
{
|
||||
return (char *) aligned_malloc(size, 4096, m_malloc);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseMemory(char *address)
|
||||
{
|
||||
aligned_free(address, m_free);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
|
||||
// Bandaid implementations for these functions. Windows has its own version.
|
||||
void GetInfoFromPC(int pc, char *buff, int buffSize)
|
||||
{
|
||||
sprintf(buff, "0x%x", pc);
|
||||
}
|
||||
|
||||
#ifdef MMGC_PPC
|
||||
void GetStackTrace(int *trace, int len, int skip)
|
||||
{
|
||||
register int stackp;
|
||||
int pc;
|
||||
asm("mr %0,r1" : "=r" (stackp));
|
||||
while(skip--) {
|
||||
stackp = *(int*)stackp;
|
||||
}
|
||||
int i=0;
|
||||
// save space for 0 terminator
|
||||
len--;
|
||||
while(i<len && stackp) {
|
||||
pc = *((int*)stackp+2);
|
||||
trace[i++]=pc;
|
||||
stackp = *(int*)stackp;
|
||||
}
|
||||
trace[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MMGC_IA32
|
||||
void GetStackTrace(int *trace, int len, int skip) {}
|
||||
#endif
|
||||
|
||||
#ifdef MMGC_ARM
|
||||
void GetStackTrace(int *trace, int len, int skip) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -1,547 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
#include <malloc.h>
|
||||
#include <strsafe.h>
|
||||
#include <DbgHelp.h>
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// helper snarfed and simplified from main flash player code.
|
||||
// since we only need it here and only for debug, I didn't bother
|
||||
// migrating the whole thing.
|
||||
class DynamicLoadLibraryHelper
|
||||
{
|
||||
protected:
|
||||
DynamicLoadLibraryHelper(const char* p_dllName, bool p_required = true);
|
||||
virtual ~DynamicLoadLibraryHelper();
|
||||
|
||||
FARPROC GetProc(const char* p_funcName, bool p_required = true);
|
||||
|
||||
public:
|
||||
// note that this is only if any of the *required* ones failed;
|
||||
// some "optional" ones may be missing and still have this return true.
|
||||
bool AllRequiredItemsPresent() const { return m_allRequiredItemsPresent; }
|
||||
|
||||
private:
|
||||
HMODULE m_lib;
|
||||
bool m_allRequiredItemsPresent;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#define GETPROC(n) do { m_##n = (n##ProcPtr)GetProc(#n); } while (0)
|
||||
#define GETPROC_OPTIONAL(n) do { m_##n = (n##ProcPtr)GetProc(#n, false); } while (0)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
DynamicLoadLibraryHelper::DynamicLoadLibraryHelper(const char* p_dllName, bool p_required) :
|
||||
m_lib(NULL),
|
||||
m_allRequiredItemsPresent(true) // assume the best
|
||||
{
|
||||
m_lib = ::LoadLibraryA(p_dllName);
|
||||
if (p_required && (m_lib == NULL || m_lib == INVALID_HANDLE_VALUE))
|
||||
{
|
||||
// don't assert here... it will trigger a DebugBreak(), which will crash
|
||||
// systems not running a debugger... and QE insists that they be able
|
||||
// to run Debug builds on debuggerless Win98 systems... (sigh)
|
||||
//GCAssertMsg(0, p_dllName);
|
||||
m_allRequiredItemsPresent = false;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
FARPROC DynamicLoadLibraryHelper::GetProc(const char* p_funcName, bool p_required)
|
||||
{
|
||||
FARPROC a_proc = NULL;
|
||||
if (m_lib != NULL && m_lib != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
a_proc = ::GetProcAddress(m_lib, p_funcName);
|
||||
}
|
||||
if (p_required && a_proc == NULL)
|
||||
{
|
||||
// don't assert here... it will trigger a DebugBreak(), which will crash
|
||||
// systems not running a debugger... and QE insists that they be able
|
||||
// to run Debug builds on debuggerless Win98 systems... (sigh)
|
||||
//GCAssertMsg(0, p_funcName);
|
||||
m_allRequiredItemsPresent = false;
|
||||
}
|
||||
return a_proc;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
DynamicLoadLibraryHelper::~DynamicLoadLibraryHelper()
|
||||
{
|
||||
if (m_lib != NULL && m_lib != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
::FreeLibrary(m_lib);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
class DbgHelpDllHelper : public DynamicLoadLibraryHelper
|
||||
{
|
||||
public:
|
||||
DbgHelpDllHelper();
|
||||
|
||||
public:
|
||||
|
||||
typedef BOOL (__stdcall *StackWalk64ProcPtr)(
|
||||
DWORD MachineType,
|
||||
HANDLE hProcess,
|
||||
HANDLE hThread,
|
||||
LPSTACKFRAME64 StackFrame,
|
||||
PVOID ContextRecord,
|
||||
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
|
||||
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
|
||||
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
|
||||
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
|
||||
);
|
||||
|
||||
typedef PVOID (__stdcall *SymFunctionTableAccess64ProcPtr)(
|
||||
HANDLE hProcess,
|
||||
DWORD64 AddrBase
|
||||
);
|
||||
|
||||
typedef DWORD64 (__stdcall *SymGetModuleBase64ProcPtr)(
|
||||
HANDLE hProcess,
|
||||
DWORD64 qwAddr
|
||||
);
|
||||
|
||||
typedef BOOL (__stdcall *SymGetLineFromAddr64ProcPtr)(
|
||||
HANDLE hProcess,
|
||||
DWORD64 qwAddr,
|
||||
PDWORD pdwDisplacement,
|
||||
PIMAGEHLP_LINE64 Line64
|
||||
);
|
||||
|
||||
typedef BOOL (__stdcall *SymGetSymFromAddr64ProcPtr)(
|
||||
HANDLE hProcess,
|
||||
DWORD64 qwAddr,
|
||||
PDWORD64 pdwDisplacement,
|
||||
PIMAGEHLP_SYMBOL64 Symbol
|
||||
);
|
||||
|
||||
typedef BOOL (__stdcall *SymInitializeProcPtr)(
|
||||
HANDLE hProcess,
|
||||
PSTR UserSearchPath,
|
||||
BOOL fInvadeProcess
|
||||
);
|
||||
|
||||
public:
|
||||
StackWalk64ProcPtr m_StackWalk64;
|
||||
SymFunctionTableAccess64ProcPtr m_SymFunctionTableAccess64;
|
||||
SymGetModuleBase64ProcPtr m_SymGetModuleBase64;
|
||||
SymGetLineFromAddr64ProcPtr m_SymGetLineFromAddr64;
|
||||
SymGetSymFromAddr64ProcPtr m_SymGetSymFromAddr64;
|
||||
SymInitializeProcPtr m_SymInitialize;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
DbgHelpDllHelper::DbgHelpDllHelper() :
|
||||
DynamicLoadLibraryHelper("dbghelp.dll"),
|
||||
m_StackWalk64(NULL),
|
||||
m_SymFunctionTableAccess64(NULL),
|
||||
m_SymGetModuleBase64(NULL),
|
||||
m_SymGetLineFromAddr64(NULL),
|
||||
m_SymGetSymFromAddr64(NULL),
|
||||
m_SymInitialize(NULL)
|
||||
{
|
||||
GETPROC(StackWalk64);
|
||||
GETPROC(SymFunctionTableAccess64);
|
||||
GETPROC(SymGetModuleBase64);
|
||||
GETPROC(SymGetLineFromAddr64);
|
||||
GETPROC(SymGetSymFromAddr64);
|
||||
GETPROC(SymInitialize);
|
||||
}
|
||||
|
||||
// declaring this statically will dynamically load the dll and procs
|
||||
// at startup, and never ever release them... if this ever becomes NON-debug
|
||||
// code, you might want to have a way to toss all this... but for _DEBUG
|
||||
// only, it should be fine
|
||||
static DbgHelpDllHelper g_DbgHelpDll;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
#ifdef MMGC_AVMPLUS
|
||||
int GCHeap::vmPageSize()
|
||||
{
|
||||
SYSTEM_INFO sysinfo;
|
||||
GetSystemInfo(&sysinfo);
|
||||
|
||||
return sysinfo.dwPageSize;
|
||||
}
|
||||
|
||||
void* GCHeap::ReserveCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
return VirtualAlloc(address,
|
||||
size,
|
||||
MEM_RESERVE,
|
||||
PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseCodeMemory(void* address,
|
||||
size_t /*size*/)
|
||||
{
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
void* GCHeap::CommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = GCHeap::kNativePageSize; // default of one page
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
void* addr = VirtualAlloc(address,
|
||||
size,
|
||||
MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
#else
|
||||
void* addr = VirtualAlloc(address,
|
||||
size,
|
||||
MEM_COMMIT,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
if (addr == NULL)
|
||||
address = 0;
|
||||
else {
|
||||
address = (void*)( (int)address + size );
|
||||
committedCodeMemory += size;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
#ifdef AVMPLUS_JIT_READONLY
|
||||
/**
|
||||
* SetExecuteBit changes the page access protections on a block of pages,
|
||||
* to make JIT-ted code executable or not.
|
||||
*
|
||||
* If executableFlag is true, the memory is made executable and read-only.
|
||||
*
|
||||
* If executableFlag is false, the memory is made non-executable and
|
||||
* read-write.
|
||||
*
|
||||
* [rickr] bug #182323 The codegen can bail in the middle of generating
|
||||
* code for any number of reasons. When this occurs we need to ensure
|
||||
* that any code that was previously on the page still executes, so we
|
||||
* leave the page as PAGE_EXECUTE_READWRITE rather than PAGE_READWRITE.
|
||||
* Ideally we'd use PAGE_READWRITE and then on failure revert it back to
|
||||
* read/execute but this is a little tricker and doesn't add too much
|
||||
* protection since only a single page is 'exposed' with this technique.
|
||||
*/
|
||||
void GCHeap::SetExecuteBit(void *address,
|
||||
size_t size,
|
||||
bool executableFlag)
|
||||
{
|
||||
DWORD oldProtectFlags = 0;
|
||||
BOOL retval = VirtualProtect(address,
|
||||
size,
|
||||
executableFlag ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE,
|
||||
&oldProtectFlags);
|
||||
|
||||
(void)retval;
|
||||
GCAssert(retval);
|
||||
|
||||
// We should not be clobbering PAGE_GUARD protections
|
||||
GCAssert((oldProtectFlags & PAGE_GUARD) == 0);
|
||||
}
|
||||
#endif /* AVMPLUS_JIT_READONLY */
|
||||
|
||||
bool GCHeap::SetGuardPage(void *address)
|
||||
{
|
||||
if (!useGuardPages)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void *res = VirtualAlloc(address,
|
||||
GCHeap::kNativePageSize,
|
||||
MEM_COMMIT,
|
||||
PAGE_GUARD | PAGE_READWRITE);
|
||||
return res != 0;
|
||||
}
|
||||
|
||||
void* GCHeap::DecommitCodeMemory(void* address,
|
||||
size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
size = GCHeap::kNativePageSize; // default of one page
|
||||
|
||||
if (VirtualFree(address, size, MEM_DECOMMIT) == false)
|
||||
address = 0;
|
||||
else
|
||||
committedCodeMemory -= size;
|
||||
|
||||
return address;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_MMAP
|
||||
char* GCHeap::ReserveMemory(char *address,
|
||||
size_t size)
|
||||
{
|
||||
return (char*) VirtualAlloc(address,
|
||||
size,
|
||||
MEM_RESERVE,
|
||||
PAGE_NOACCESS);
|
||||
}
|
||||
|
||||
bool GCHeap::CommitMemory(char *address,
|
||||
size_t size)
|
||||
{
|
||||
void *addr = VirtualAlloc(address,
|
||||
size,
|
||||
MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
#ifdef _DEBUG
|
||||
if(addr == NULL) {
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
VirtualQuery(address, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf, 0, NULL );
|
||||
GCAssertMsg(false, (const char*)lpMsgBuf);
|
||||
}
|
||||
#endif
|
||||
return addr != NULL;
|
||||
}
|
||||
|
||||
bool GCHeap::DecommitMemory(char *address, size_t size)
|
||||
{
|
||||
return VirtualFree(address, size, MEM_DECOMMIT) != 0;
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseMemory(char *address,
|
||||
size_t /*size*/)
|
||||
{
|
||||
VirtualFree(address, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
bool GCHeap::CommitMemoryThatMaySpanRegions(char *address, size_t size)
|
||||
{
|
||||
bool success = false;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
do {
|
||||
VirtualQuery(address, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
size_t commitSize = size > mbi.RegionSize ? mbi.RegionSize : size;
|
||||
success = CommitMemory(address, commitSize);
|
||||
address += commitSize;
|
||||
size -= commitSize;
|
||||
} while(size > 0 && success);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool GCHeap::DecommitMemoryThatMaySpanRegions(char *address, size_t size)
|
||||
{
|
||||
bool success = false;
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
do {
|
||||
VirtualQuery(address, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
size_t commitSize = size > mbi.RegionSize ? mbi.RegionSize : size;
|
||||
success = DecommitMemory(address, commitSize);
|
||||
address += commitSize;
|
||||
size -= commitSize;
|
||||
} while(size > 0 && success);
|
||||
return success;
|
||||
}
|
||||
|
||||
#else
|
||||
char* GCHeap::AllocateMemory(size_t size)
|
||||
{
|
||||
return (char*)_aligned_malloc(size, kBlockSize);
|
||||
}
|
||||
|
||||
void GCHeap::ReleaseMemory(char *address)
|
||||
{
|
||||
_aligned_free(address);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
#ifndef MEMORY_INFO
|
||||
|
||||
// empty when MEMORY_INFO not defined
|
||||
void GetInfoFromPC(int pc, char *buff, int buffSize) { }
|
||||
void GetStackTrace(int *trace, int len, int skip) {}
|
||||
|
||||
#else
|
||||
|
||||
void GetStackTrace(int *trace, int len, int skip)
|
||||
{
|
||||
HANDLE ht = GetCurrentThread();
|
||||
HANDLE hp = GetCurrentProcess();
|
||||
|
||||
CONTEXT c;
|
||||
memset( &c, '\0', sizeof c );
|
||||
c.ContextFlags = CONTEXT_FULL;
|
||||
|
||||
#if 0
|
||||
// broken with SP2
|
||||
if ( !GetThreadContext( ht, &c ) )
|
||||
return;
|
||||
#else
|
||||
__asm
|
||||
{
|
||||
call x
|
||||
x: pop eax
|
||||
mov c.Eip, eax
|
||||
mov c.Ebp, ebp
|
||||
}
|
||||
#endif
|
||||
|
||||
// skip an extra frame
|
||||
skip++;
|
||||
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof frame);
|
||||
|
||||
frame.AddrPC.Offset = c.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = c.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
|
||||
int i=0;
|
||||
// save space for 0 pc terminator
|
||||
len--;
|
||||
while(i < len &&
|
||||
g_DbgHelpDll.m_StackWalk64 != NULL &&
|
||||
g_DbgHelpDll.m_SymFunctionTableAccess64 != NULL &&
|
||||
g_DbgHelpDll.m_SymGetModuleBase64 != NULL &&
|
||||
(*g_DbgHelpDll.m_StackWalk64)(IMAGE_FILE_MACHINE_I386, hp, ht, &frame,
|
||||
NULL, NULL, g_DbgHelpDll.m_SymFunctionTableAccess64, g_DbgHelpDll.m_SymGetModuleBase64, NULL)) {
|
||||
if(skip-- > 0)
|
||||
continue;
|
||||
// FIXME: not 64 bit safe
|
||||
trace[i++] = (int) frame.AddrPC.Offset;
|
||||
}
|
||||
trace[i] = 0;
|
||||
}
|
||||
|
||||
static bool inited = false;
|
||||
static const int MaxNameLength = 256;
|
||||
void GetInfoFromPC(int pc, char *buff, int buffSize)
|
||||
{
|
||||
if(!inited) {
|
||||
if(!g_DbgHelpDll.m_SymInitialize ||
|
||||
!(*g_DbgHelpDll.m_SymInitialize)(GetCurrentProcess(), NULL, true)) {
|
||||
LPVOID lpMsgBuf;
|
||||
if(FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf, 0, NULL ))
|
||||
{
|
||||
GCDebugMsg("See lpMsgBuf", true);
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
goto nosym;
|
||||
}
|
||||
inited = true;
|
||||
}
|
||||
|
||||
// gleaned from IMAGEHLP_SYMBOL64 docs
|
||||
IMAGEHLP_SYMBOL64 *pSym = (IMAGEHLP_SYMBOL64 *) alloca(sizeof(IMAGEHLP_SYMBOL64) + MaxNameLength);
|
||||
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
pSym->MaxNameLength = MaxNameLength;
|
||||
|
||||
DWORD64 offsetFromSymbol;
|
||||
if(!g_DbgHelpDll.m_SymGetSymFromAddr64 ||
|
||||
!(*g_DbgHelpDll.m_SymGetSymFromAddr64)(GetCurrentProcess(), pc, &offsetFromSymbol, pSym)) {
|
||||
goto nosym;
|
||||
}
|
||||
|
||||
// get line
|
||||
IMAGEHLP_LINE64 line;
|
||||
memset(&line, 0, sizeof(IMAGEHLP_LINE64));
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
DWORD offsetFromLine;
|
||||
if(!g_DbgHelpDll.m_SymGetLineFromAddr64 ||
|
||||
!(*g_DbgHelpDll.m_SymGetLineFromAddr64)(GetCurrentProcess(), pc, &offsetFromLine, &line)) {
|
||||
goto nosym;
|
||||
}
|
||||
|
||||
/*
|
||||
this isn't working, I think i need to call SymLoadModule64 or something
|
||||
IMAGEHLP_MODULE64 module;
|
||||
memset(&module, 0, sizeof module);
|
||||
module.SizeOfStruct = sizeof module;
|
||||
if(!SymGetModuleInfo64(GetCurrentProcess(), pSym->Address, &module))
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
if(FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPTSTR) &lpMsgBuf, 0, NULL ))
|
||||
{
|
||||
GCDebugMsg((wchar*)lpMsgBuf, true);
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// success!
|
||||
char *fileName = line.FileName + strlen(line.FileName);
|
||||
|
||||
// skip everything up to last slash
|
||||
while(fileName > line.FileName && *fileName != '\\')
|
||||
fileName--;
|
||||
fileName++;
|
||||
StringCchPrintfA(buff, buffSize, "%s:%d", fileName, line.LineNumber);
|
||||
return;
|
||||
|
||||
nosym:
|
||||
StringCchPrintfA(buff, buffSize, "0x%x", pc);
|
||||
}
|
||||
#endif
|
||||
#endif // MEMORY_INFO
|
||||
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
GCLargeAlloc::GCLargeAlloc(GC* gc) : GCAllocBase(gc)
|
||||
{
|
||||
m_blocks = NULL;
|
||||
}
|
||||
|
||||
void* GCLargeAlloc::Alloc(size_t size, int flags)
|
||||
{
|
||||
int blocks = (size+sizeof(LargeBlock)+GCHeap::kBlockSize-1) / GCHeap::kBlockSize;
|
||||
|
||||
LargeBlock *block = (LargeBlock*) m_gc->AllocBlock(blocks, GC::kGCLargeAllocPageFirst, (flags&GC::kZero) != 0);
|
||||
void *item = NULL;
|
||||
|
||||
if (block)
|
||||
{
|
||||
block->flags = ((flags&GC::kFinalize) != 0) ? kFinalizeFlag : 0;
|
||||
block->flags |= ((flags&GC::kContainsPointers) != 0) ? kContainsPointers : 0;
|
||||
block->flags |= ((flags&GC::kRCObject) != 0) ? kRCObject : 0;
|
||||
block->gc = this->m_gc;
|
||||
block->next = m_blocks;
|
||||
block->usableSize = blocks*GCHeap::kBlockSize - sizeof(LargeBlock);
|
||||
m_blocks = block;
|
||||
|
||||
item = (void*)(block+1);
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (flags & GC::kZero)
|
||||
{
|
||||
// AllocBlock should take care of this
|
||||
for(int i=0, n=size/sizeof(int); i<n; i++) {
|
||||
if(((int*)item)[i] != 0)
|
||||
GCAssert(false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
void GCLargeAlloc::Free(void *item)
|
||||
{
|
||||
LargeBlock *b = GetBlockHeader(item);
|
||||
|
||||
if(b->flags & kHasWeakRef)
|
||||
b->gc->ClearWeakRef(GetUserPointer(item));
|
||||
|
||||
LargeBlock **prev = &m_blocks;
|
||||
while(*prev)
|
||||
{
|
||||
if(b == *prev)
|
||||
{
|
||||
*prev = b->next;
|
||||
m_gc->FreeBlock(b, b->GetNumBlocks());
|
||||
return;
|
||||
}
|
||||
prev = &(*prev)->next;
|
||||
}
|
||||
GCAssertMsg(false, "Bad free!");
|
||||
}
|
||||
|
||||
void GCLargeAlloc::ClearMarks()
|
||||
{
|
||||
LargeBlock *block = m_blocks;
|
||||
while (block) {
|
||||
block->flags &= ~(kMarkFlag|kQueuedFlag);
|
||||
block = block->next;
|
||||
}
|
||||
}
|
||||
|
||||
void GCLargeAlloc::Finalize()
|
||||
{
|
||||
LargeBlock *b = m_blocks;
|
||||
while (b) {
|
||||
if ((b->flags & kMarkFlag) == 0) {
|
||||
void *item = b+1;
|
||||
if (NeedsFinalize(b)) {
|
||||
GCFinalizedObject *obj = (GCFinalizedObject *) item;
|
||||
obj = (GCFinalizedObject *) GetUserPointer(obj);
|
||||
obj->~GCFinalizedObject();
|
||||
#if defined(_DEBUG) && defined(MMGC_DRC)
|
||||
if((b->flags & kRCObject) != 0) {
|
||||
b->gc->RCObjectZeroCheck((RCObject*)obj);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(b->flags & kHasWeakRef) {
|
||||
b->gc->ClearWeakRef(GetUserPointer(item));
|
||||
}
|
||||
}
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GCLargeAlloc::Sweep()
|
||||
{
|
||||
size_t visitedSize=0;
|
||||
LargeBlock **prev = &m_blocks;
|
||||
while (*prev) {
|
||||
LargeBlock *block = *prev;
|
||||
visitedSize += block->GetNumBlocks();
|
||||
LargeBlock *next = block->next;
|
||||
if ((block->flags & kMarkFlag) == 0) {
|
||||
// Destroy this block
|
||||
*prev = block->next;
|
||||
void *item = block+1;
|
||||
(void)item;
|
||||
#ifdef ALLOC_LOG
|
||||
m_gc->LogFree(item);
|
||||
#endif
|
||||
#ifdef MEMORY_INFO
|
||||
DebugFreeReverse(item, 0xba, 3);
|
||||
#endif
|
||||
m_gc->FreeBlock(block, block->GetNumBlocks());
|
||||
} else {
|
||||
prev = &block->next;
|
||||
}
|
||||
block = next;
|
||||
}
|
||||
return visitedSize;
|
||||
}
|
||||
|
||||
|
||||
GCLargeAlloc::~GCLargeAlloc()
|
||||
{
|
||||
GCAssert(!m_blocks);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool GCLargeAlloc::ConservativeGetMark(const void *item, bool bogusPointerReturnValue)
|
||||
{
|
||||
if(((intptr) item & 0xfff) == sizeof(LargeBlock))
|
||||
{
|
||||
return GetMark(item);
|
||||
}
|
||||
return bogusPointerReturnValue;
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCLargeAlloc__
|
||||
#define __GCLargeAlloc__
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* This is a garbage collecting allocator for large memory blocks.
|
||||
*/
|
||||
class GCLargeAlloc : public GCAllocBase
|
||||
{
|
||||
friend class GC;
|
||||
private:
|
||||
enum {
|
||||
kMarkFlag = 0x1,
|
||||
kQueuedFlag = 0x2,
|
||||
kFinalizeFlag = 0x4,
|
||||
kHasWeakRef = 0x8,
|
||||
kContainsPointers = 0x10,
|
||||
kRCObject = 0x20
|
||||
};
|
||||
|
||||
public:
|
||||
GCLargeAlloc(GC* gc);
|
||||
~GCLargeAlloc();
|
||||
|
||||
void* Alloc(size_t size, int flags);
|
||||
void Free(void *ptr);
|
||||
void Finalize();
|
||||
size_t Sweep();
|
||||
void ClearMarks();
|
||||
|
||||
static void SetHasWeakRef(const void *item, bool to)
|
||||
{
|
||||
if(to) {
|
||||
GetBlockHeader(item)->flags |= kHasWeakRef;
|
||||
} else {
|
||||
GetBlockHeader(item)->flags &= ~kHasWeakRef;
|
||||
}
|
||||
}
|
||||
|
||||
static bool HasWeakRef(const void *item)
|
||||
{
|
||||
return (GetBlockHeader(item)->flags & kHasWeakRef) != 0;
|
||||
}
|
||||
|
||||
static bool IsLargeBlock(const void *item)
|
||||
{
|
||||
// The pointer should be 4K aligned plus 16 bytes
|
||||
// Mac inserts 16 bytes for new[] so make it more general
|
||||
return (((uint32)item & 0xFFF) == sizeof(LargeBlock));
|
||||
}
|
||||
|
||||
static bool SetMark(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
bool oldMark = (block->flags & kMarkFlag) != 0;
|
||||
block->flags |= kMarkFlag;
|
||||
block->flags &= ~kQueuedFlag;
|
||||
return oldMark;
|
||||
}
|
||||
|
||||
static void SetQueued(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
block->flags |= kQueuedFlag;
|
||||
}
|
||||
|
||||
static void SetFinalize(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
block->flags |= kFinalizeFlag;
|
||||
}
|
||||
|
||||
static bool GetMark(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
return (block->flags & kMarkFlag) != 0;
|
||||
}
|
||||
|
||||
static bool IsWhite(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
if(!IsLargeBlock(item))
|
||||
return false;
|
||||
return (block->flags & (kMarkFlag|kQueuedFlag)) == 0;
|
||||
}
|
||||
|
||||
static void* FindBeginning(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
return (void*) (block+1);
|
||||
}
|
||||
|
||||
static void ClearFinalized(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
block->flags &= ~kFinalizeFlag;
|
||||
}
|
||||
|
||||
static bool ContainsPointers(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
return (block->flags & kContainsPointers) != 0;
|
||||
}
|
||||
|
||||
static bool IsFinalized(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
return (block->flags & kFinalizeFlag) != 0;
|
||||
}
|
||||
|
||||
static bool IsRCObject(const void *item)
|
||||
{
|
||||
LargeBlock *block = GetBlockHeader(item);
|
||||
return (block->flags & kRCObject) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
struct LargeBlock
|
||||
{
|
||||
GC *gc;
|
||||
uint32 usableSize;
|
||||
uint32 flags;
|
||||
LargeBlock *next;
|
||||
|
||||
int GetNumBlocks() const { return (usableSize + sizeof(LargeBlock)) / GCHeap::kBlockSize; }
|
||||
};
|
||||
|
||||
static LargeBlock* GetBlockHeader(const void *addr)
|
||||
{
|
||||
return (LargeBlock*) ((uint32)addr & ~0xFFF);
|
||||
}
|
||||
|
||||
static bool NeedsFinalize(LargeBlock *block)
|
||||
{
|
||||
return (block->flags & kFinalizeFlag) != 0;
|
||||
}
|
||||
|
||||
// The list of chunk blocks
|
||||
LargeBlock* m_blocks;
|
||||
static bool ConservativeGetMark(const void *item, bool bogusPointerReturnValue);
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCLargeAlloc__ */
|
||||
@@ -1,546 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#ifdef MEMORY_INFO
|
||||
|
||||
#ifndef __MWERKS__
|
||||
#include <typeinfo>
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
GCThreadLocal<const char*> memtag;
|
||||
GCThreadLocal<void*> memtype;
|
||||
|
||||
// Turn this to see GC stack traces.
|
||||
const bool enableTraces = false;
|
||||
|
||||
// this is how many stack frames we'll attempt to lookup, we may not get this many and
|
||||
// we may leave some out
|
||||
const int kMaxTraceDepth = 7;
|
||||
|
||||
// include total and swept memory totals in memory profiling dumps
|
||||
const bool showTotal = false;
|
||||
const bool showSwept = false;
|
||||
|
||||
// controls size of table which is fixed
|
||||
const int kNumTracesPow = 20;
|
||||
const int kNumTraces = (enableTraces ? 1 << kNumTracesPow : 1);
|
||||
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCCriticalSection m_traceTableLock;
|
||||
#endif
|
||||
|
||||
struct StackTrace
|
||||
{
|
||||
int ips[kMaxTraceDepth];
|
||||
int size;
|
||||
int totalSize;
|
||||
int sweepSize;
|
||||
int vtable;
|
||||
const char *memtag;
|
||||
int count;
|
||||
int totalCount;
|
||||
int sweepCount;
|
||||
bool lumped;
|
||||
};
|
||||
|
||||
static StackTrace traceTable[kNumTraces];
|
||||
|
||||
unsigned int hashTrace(int *trace)
|
||||
{
|
||||
unsigned int hash = *trace++;
|
||||
while(*trace++ != 0) {
|
||||
hash ^= *trace;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool tracesEqual(int *trace1, int *trace2)
|
||||
{
|
||||
while(*trace1) {
|
||||
if(*trace1 != *trace2)
|
||||
return false;
|
||||
trace1++;
|
||||
trace2++;
|
||||
}
|
||||
return *trace1 == *trace2;
|
||||
}
|
||||
|
||||
unsigned int LookupTrace(int *trace)
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCEnterCriticalSection lock(m_traceTableLock);
|
||||
#endif
|
||||
// this is true when traces are off
|
||||
if(*trace == 0)
|
||||
return 0;
|
||||
|
||||
static int numTraces = 0;
|
||||
int modmask = kNumTraces - 1;
|
||||
unsigned int hash = hashTrace(trace);
|
||||
unsigned int index = hash & modmask;
|
||||
unsigned int n = 17; // small number means cluster at start
|
||||
int c = 1;
|
||||
while(traceTable[index].ips[0] && !tracesEqual(traceTable[index].ips, trace)) {
|
||||
// probe
|
||||
index = (index + (n=n+c)) & modmask;
|
||||
}
|
||||
if(traceTable[index].ips[0] == 0) {
|
||||
memcpy(traceTable[index].ips, trace, kMaxTraceDepth * sizeof(int));
|
||||
numTraces++;
|
||||
}
|
||||
if(numTraces == kNumTraces) {
|
||||
GCAssertMsg(false, "Increase trace table size!");
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// increase this to get more
|
||||
const int kNumTypes = 10;
|
||||
const int kNumTracesPerType=5;
|
||||
|
||||
// data structure to gather allocations by type with the top 5 traces
|
||||
struct TypeGroup
|
||||
{
|
||||
const char *name;
|
||||
size_t size;
|
||||
int count;
|
||||
int traces[kNumTracesPerType ? kNumTracesPerType : 1];
|
||||
};
|
||||
|
||||
const char* GetTypeName(int index, void *obj)
|
||||
{
|
||||
// cache
|
||||
if(index > kNumTraces)
|
||||
return "unknown";
|
||||
if(traceTable[index].memtag)
|
||||
return traceTable[index].memtag;
|
||||
const char*name="unknown";
|
||||
#ifdef WIN32
|
||||
try {
|
||||
const std::type_info *ti = &typeid(*(MMgc::GCObject*)obj);
|
||||
if(ti->name())
|
||||
name = ti->name();
|
||||
// sometimes name will get set to bogus memory with no exceptions catch that
|
||||
char c = *name;
|
||||
(void)c; // silence compiler warning
|
||||
} catch(...) {
|
||||
name = "unknown";
|
||||
}
|
||||
#else
|
||||
(void)obj;
|
||||
#endif
|
||||
// cache
|
||||
traceTable[index].memtag = name;
|
||||
return name;
|
||||
}
|
||||
|
||||
#define PERCENT(all, some) ((((float)some)/(float)all)*100.0)
|
||||
|
||||
void DumpFatties()
|
||||
{
|
||||
GCHashtable typeTable(128);
|
||||
#ifdef GCHEAP_LOCK
|
||||
//GCEnterCriticalSection lock(m_traceTableLock);
|
||||
#endif
|
||||
int residentSize=0;
|
||||
int residentCount=0;
|
||||
|
||||
for(int i=0; i < kNumTraces; i++)
|
||||
{
|
||||
int size;
|
||||
|
||||
if(showSwept) {
|
||||
size = traceTable[i].sweepSize;
|
||||
} else if(showTotal) {
|
||||
size = traceTable[i].totalSize;
|
||||
} else {
|
||||
size = traceTable[i].size;
|
||||
}
|
||||
|
||||
if(size == 0)
|
||||
continue;
|
||||
residentSize += size;
|
||||
|
||||
int count = traceTable[i].lumped ? 0 : traceTable[i].count;
|
||||
residentCount += traceTable[i].count;
|
||||
|
||||
const char *name = "unknown";
|
||||
#ifndef _MAC
|
||||
#ifndef AVMPLUS_LINUX // TODO_LINUX
|
||||
#ifndef MMGC_ARM
|
||||
name = GetTypeName(i, &traceTable[i].vtable);
|
||||
#endif //AVMPLUS_LINUX
|
||||
#endif //MMGC_ARM
|
||||
#endif
|
||||
TypeGroup *tg = (TypeGroup*) typeTable.get((void*)name);
|
||||
if(tg) {
|
||||
GCAssert(tg->name == name);
|
||||
tg->size += size;
|
||||
tg->count += count;
|
||||
for(int j=0; j<kNumTracesPerType; j++) {
|
||||
if(traceTable[tg->traces[j]].size < size) {
|
||||
if(j != kNumTracesPerType-1) {
|
||||
memmove(&tg->traces[j+1], &tg->traces[j], (kNumTracesPerType-j-1)*sizeof(int));
|
||||
}
|
||||
tg->traces[j] = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tg = new TypeGroup();
|
||||
tg->size = size;
|
||||
tg->count = count;
|
||||
tg->name = name;
|
||||
tg->traces[0] = i;
|
||||
if(kNumTracesPerType) {
|
||||
int num = kNumTracesPerType - 1;
|
||||
memset(&tg->traces[1], 0, sizeof(int)*num);
|
||||
}
|
||||
typeTable.put((void*)name, tg);
|
||||
}
|
||||
}
|
||||
|
||||
int codeSize = GCHeap::GetGCHeap()->GetCodeMemorySize();
|
||||
int inUse = GCHeap::GetGCHeap()->GetUsedHeapSize() * GCHeap::kBlockSize;
|
||||
int committed = GCHeap::GetGCHeap()->GetTotalHeapSize() * GCHeap::kBlockSize + codeSize;
|
||||
int free = GCHeap::GetGCHeap()->GetFreeHeapSize() * GCHeap::kBlockSize;
|
||||
|
||||
int memInfo = residentCount*16;
|
||||
|
||||
// executive summary
|
||||
GCDebugMsg(false, "Code Size %d kb \n", codeSize>>10);
|
||||
GCDebugMsg(false, "Total in use (used pages, ignoring code) %d kb \n", inUse>>10);
|
||||
GCDebugMsg(false, "Total resident (individual allocations - code) %d kb \n", (residentSize-codeSize)>>10);
|
||||
GCDebugMsg(false, "Allocator overhead (used pages - resident, ignoring code and mem_info): %d kb \n", ((inUse-memInfo)-(residentSize-codeSize))>>10);
|
||||
GCDebugMsg(false, "Heap overhead (unused committed pages, ignoring code): %d kb \n", free>>10);
|
||||
GCDebugMsg(false, "Total committed (including code) %d kb \n\n", committed>>10);
|
||||
|
||||
TypeGroup *residentFatties[kNumTypes];
|
||||
memset(residentFatties, 0, kNumTypes * sizeof(TypeGroup *));
|
||||
GCHashtableIterator iter(&typeTable);
|
||||
const char *name;
|
||||
while((name = (const char*)iter.nextKey()) != NULL)
|
||||
{
|
||||
TypeGroup *tg = (TypeGroup*)iter.value();
|
||||
for(int j=0; j<kNumTypes; j++) {
|
||||
if(!residentFatties[j]) {
|
||||
residentFatties[j] = tg;
|
||||
break;
|
||||
}
|
||||
if(residentFatties[j]->size < tg->size) {
|
||||
if(j != kNumTypes-1) {
|
||||
memmove(&residentFatties[j+1], &residentFatties[j], (kNumTypes-j-1) * sizeof(TypeGroup *));
|
||||
}
|
||||
residentFatties[j] = tg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < kNumTypes; i++)
|
||||
{
|
||||
TypeGroup *tg = residentFatties[i];
|
||||
if(!tg)
|
||||
break;
|
||||
GCDebugMsg(false, "%s - %3.1f%% - %d kb %d items, avg %d b\n", tg->name, PERCENT(residentSize, tg->size), tg->size>>10, tg->count, tg->count ? tg->size/tg->count : 0);
|
||||
for(int j=0; j < kNumTracesPerType; j++) {
|
||||
int traceIndex = tg->traces[j];
|
||||
if(traceIndex) {
|
||||
int size = traceTable[traceIndex].size;
|
||||
int count = traceTable[traceIndex].count;
|
||||
if(showSwept) {
|
||||
size = traceTable[traceIndex].sweepSize;
|
||||
count = traceTable[traceIndex].sweepCount;
|
||||
} else if(showTotal) {
|
||||
size = traceTable[traceIndex].totalSize;
|
||||
count = traceTable[traceIndex].totalCount;
|
||||
}
|
||||
GCDebugMsg(false, "\t %3.1f%% - %d kb - %d items - ", PERCENT(tg->size, size), size>>10, count);
|
||||
PrintStackTraceByIndex(traceIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GCHashtableIterator iter2(&typeTable);
|
||||
while(iter2.nextKey() != NULL)
|
||||
delete (TypeGroup*)iter2.value();
|
||||
}
|
||||
|
||||
size_t DebugSize()
|
||||
{
|
||||
return 4 * sizeof(int);
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate the memory such that we can detect underwrites, overwrites and remember
|
||||
* the allocation stack in case of a leak. Memory is laid out like so:
|
||||
*
|
||||
* first four bytes == size / 4
|
||||
* second four bytes == stack trace index
|
||||
* size data bytes
|
||||
* last 4 bytes == 0xdeadbeef
|
||||
*
|
||||
* Its important that the stack trace index is not stored in the first 4 bytes,
|
||||
* it enables the leak detection to work see ~FixedAlloc. Underwrite detection isn't
|
||||
* perfect, an assert will be fired if the stack table index is invalid (greater than
|
||||
* the table size or to an unused table entry) or it the size gets mangled and the
|
||||
* end tag isn't at mem+size.
|
||||
*/
|
||||
void *DebugDecorate(void *item, size_t size, int skip)
|
||||
{
|
||||
if (!item) return NULL;
|
||||
|
||||
static void *lastItem = 0;
|
||||
static int lastTrace = 0;
|
||||
|
||||
#ifndef _MAC
|
||||
if(lastItem)
|
||||
{
|
||||
// this guy might be deleted so swallow access violations
|
||||
try {
|
||||
traceTable[lastTrace].vtable = *(int*)lastItem;
|
||||
} catch(...) {}
|
||||
lastItem = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int traceIndex;
|
||||
|
||||
// get index into trace table
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCEnterCriticalSection lock(m_traceTableLock);
|
||||
#endif
|
||||
traceIndex = GetStackTraceIndex(skip);
|
||||
}
|
||||
|
||||
if(GC::enableMemoryProfiling && memtype)
|
||||
{
|
||||
// if an allocation is tagged with MMGC_MEM_TYPE its a sub
|
||||
// allocation of a "master" type and this flag prevents it
|
||||
// from contributing to the count so averages make more sense
|
||||
traceTable[traceIndex].lumped = true;
|
||||
}
|
||||
|
||||
// subtract decoration space
|
||||
size -= DebugSize();
|
||||
|
||||
ChangeSize(traceIndex, size);
|
||||
|
||||
int *mem = (int*)item;
|
||||
// set up the memory
|
||||
*mem++ = size;
|
||||
*mem++ = traceIndex;
|
||||
void *ret = mem;
|
||||
mem += (size>>2);
|
||||
*mem++ = 0xdeadbeef;
|
||||
*mem = 0;
|
||||
|
||||
// save these off so we can save the vtable (which is assigned after memory is
|
||||
// allocated)
|
||||
if(GC::enableMemoryProfiling)
|
||||
{
|
||||
if(memtag || memtype) {
|
||||
if(memtag)
|
||||
traceTable[traceIndex].memtag = memtag;
|
||||
else
|
||||
traceTable[traceIndex].vtable = *(int*)(void*)memtype;
|
||||
memtag = NULL;
|
||||
memtype = NULL;
|
||||
} else {
|
||||
lastTrace = traceIndex;
|
||||
lastItem = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DebugFreeHelper(void *item, int poison, int skip)
|
||||
{
|
||||
int *ip = (int*) item;
|
||||
int size = *ip;
|
||||
int traceIndex = *(ip+1);
|
||||
int *endMarker = ip + 2 + (size>>2);
|
||||
|
||||
// clean up
|
||||
*ip = 0;
|
||||
ip += 2;
|
||||
|
||||
// this can be called twice on some memory in inc gc
|
||||
if(size == 0)
|
||||
return;
|
||||
|
||||
if (*endMarker != 0xdeadbeef)
|
||||
{
|
||||
// if you get here, you have a buffer overrun. The stack trace about to
|
||||
// be printed tells you where the block was allocated from. To find the
|
||||
// overrun, put a memory breakpoint on the location endMarker is pointing to.
|
||||
GCDebugMsg("Memory overwrite detected\n", false);
|
||||
PrintStackTraceByIndex(traceIndex);
|
||||
GCAssert(false);
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCEnterCriticalSection lock(m_traceTableLock);
|
||||
#endif
|
||||
ChangeSize(traceIndex, -1 * size);
|
||||
if(poison == 0xba) {
|
||||
traceTable[traceIndex].sweepSize += size;
|
||||
traceTable[traceIndex].sweepCount++;
|
||||
}
|
||||
traceIndex = GetStackTraceIndex(skip);
|
||||
}
|
||||
|
||||
// whack the entire thing except the first 8 bytes,
|
||||
// the free list
|
||||
if(poison == 0xca || poison == 0xba)
|
||||
size = GC::Size(ip);
|
||||
else
|
||||
size = FixedMalloc::Size(ip);
|
||||
|
||||
// size is the non-Debug size, so add 4 to get last 4 bytes, don't
|
||||
// touch write back pointer space
|
||||
memset(ip, poison, size+4);
|
||||
// write stack index to ip (currently 3rd 4 bytes of item)
|
||||
*ip = traceIndex;
|
||||
}
|
||||
|
||||
void *DebugFree(void *item, int poison, int skip)
|
||||
{
|
||||
item = (int*) item - 2;
|
||||
DebugFreeHelper(item, poison, skip);
|
||||
return item;
|
||||
}
|
||||
|
||||
void *DebugFreeReverse(void *item, int poison, int skip)
|
||||
{
|
||||
DebugFreeHelper(item, poison, skip);
|
||||
item = (int*) item + 2;
|
||||
return item;
|
||||
}
|
||||
|
||||
void ChangeSize(int traceIndex, int delta)
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCEnterCriticalSection lock(m_traceTableLock);
|
||||
#endif
|
||||
if(!enableTraces)
|
||||
return;
|
||||
traceTable[traceIndex].size += delta;
|
||||
traceTable[traceIndex].count += (delta > 0) ? 1 : -1;
|
||||
GCAssert(traceTable[traceIndex].size >= 0);
|
||||
if(delta > 0) {
|
||||
traceTable[traceIndex].totalSize += delta;
|
||||
traceTable[traceIndex].totalCount++;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int GetStackTraceIndex(int skip)
|
||||
{
|
||||
if(!enableTraces)
|
||||
return 0;
|
||||
int trace[kMaxTraceDepth]; // an array of pcs
|
||||
GetStackTrace(trace, kMaxTraceDepth, skip);
|
||||
|
||||
// get index into trace table
|
||||
return LookupTrace(trace);
|
||||
}
|
||||
|
||||
void DumpStackTraceHelper(int *trace)
|
||||
{
|
||||
if(!enableTraces)
|
||||
return;
|
||||
|
||||
char out[2048];
|
||||
char *tp = out;
|
||||
for(int i=0; trace[i] != 0; i++) {
|
||||
char buff[256];
|
||||
GetInfoFromPC(trace[i], buff, 256);
|
||||
strcpy(tp, buff);
|
||||
tp += strlen(buff);
|
||||
*tp++ = ' ';
|
||||
}
|
||||
*tp++ = '\n';
|
||||
*tp = '\0';
|
||||
|
||||
GCDebugMsg(out, false);
|
||||
}
|
||||
|
||||
void DumpStackTrace()
|
||||
{
|
||||
if(!enableTraces)
|
||||
return;
|
||||
int trace[kMaxTraceDepth];
|
||||
GetStackTrace(trace, kMaxTraceDepth, 1);
|
||||
DumpStackTraceHelper(trace);
|
||||
}
|
||||
|
||||
void PrintStackTrace(const void *item)
|
||||
{
|
||||
if (item)
|
||||
PrintStackTraceByIndex(*((int*)item - 1));
|
||||
}
|
||||
|
||||
void PrintStackTraceByIndex(unsigned int i)
|
||||
{
|
||||
#ifdef GCHEAP_LOCK
|
||||
GCEnterCriticalSection lock(m_traceTableLock);
|
||||
#endif
|
||||
if(i < kNumTraces)
|
||||
DumpStackTraceHelper(traceTable[i].ips);
|
||||
}
|
||||
|
||||
void ChangeSizeForObject(void *object, int size)
|
||||
{
|
||||
int traceIndex = *(((int*)object)-1);
|
||||
ChangeSize(traceIndex, size);
|
||||
}
|
||||
|
||||
void SetMemTag(const char *s)
|
||||
{
|
||||
if(memtag == NULL)
|
||||
memtag = s;
|
||||
}
|
||||
void SetMemType(void *s)
|
||||
{
|
||||
if(memtype == NULL)
|
||||
memtype = s;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,216 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCMemoryProfiler__
|
||||
#define __GCMemoryProfiler__
|
||||
|
||||
|
||||
#ifndef MEMORY_INFO
|
||||
|
||||
#define MMGC_MEM_TAG(_x)
|
||||
#define MMGC_MEM_TYPE(_x)
|
||||
#define GetRealPointer(_x) _x
|
||||
#define GetUserPointer(_x) _x
|
||||
#define DebugSize() 0
|
||||
#else
|
||||
|
||||
#define MMGC_MEM_TAG(_x) MMgc::SetMemTag(_x)
|
||||
#define MMGC_MEM_TYPE(_x) MMgc::SetMemType(_x)
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
#ifdef WIN32
|
||||
/**
|
||||
* GCCriticalSection is a simple Critical Section class used by GCMemoryProfiler to
|
||||
* ensure mutually exclusive access. GCSpinLock doesn't suffice since its not
|
||||
* re-entrant and we need that
|
||||
*/
|
||||
class GCCriticalSection
|
||||
{
|
||||
public:
|
||||
GCCriticalSection()
|
||||
{
|
||||
InitializeCriticalSection(&cs);
|
||||
}
|
||||
|
||||
inline void Acquire()
|
||||
{
|
||||
EnterCriticalSection(&cs);
|
||||
}
|
||||
|
||||
inline void Release()
|
||||
{
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class GCThreadLocal
|
||||
{
|
||||
public:
|
||||
GCThreadLocal()
|
||||
{
|
||||
GCAssert(sizeof(T) == sizeof(LPVOID));
|
||||
tlsId = TlsAlloc();
|
||||
}
|
||||
T operator=(T tNew)
|
||||
{
|
||||
TlsSetValue(tlsId, (LPVOID) tNew);
|
||||
return tNew;
|
||||
}
|
||||
operator T() const
|
||||
{
|
||||
return (T) TlsGetValue(tlsId);
|
||||
}
|
||||
private:
|
||||
DWORD tlsId;
|
||||
};
|
||||
#else
|
||||
|
||||
// FIXME: implement
|
||||
template<typename T>
|
||||
class GCThreadLocal
|
||||
{
|
||||
public:
|
||||
GCThreadLocal()
|
||||
{
|
||||
}
|
||||
T operator=(T tNew)
|
||||
{
|
||||
tlsId = tNew;
|
||||
return tNew;
|
||||
}
|
||||
operator T() const
|
||||
{
|
||||
return tlsId;
|
||||
}
|
||||
private:
|
||||
T tlsId;
|
||||
};
|
||||
|
||||
class GCCriticalSection
|
||||
{
|
||||
public:
|
||||
GCCriticalSection()
|
||||
{
|
||||
}
|
||||
|
||||
inline void Acquire()
|
||||
{
|
||||
}
|
||||
|
||||
inline void Release()
|
||||
{
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class GCEnterCriticalSection
|
||||
{
|
||||
public:
|
||||
GCEnterCriticalSection(GCCriticalSection& cs) : m_cs(cs)
|
||||
{
|
||||
m_cs.Acquire();
|
||||
}
|
||||
~GCEnterCriticalSection()
|
||||
{
|
||||
m_cs.Release();
|
||||
}
|
||||
|
||||
private:
|
||||
GCCriticalSection& m_cs;
|
||||
};
|
||||
|
||||
void SetMemTag(const char *memtag);
|
||||
void SetMemType(void *memtype);
|
||||
|
||||
/**
|
||||
* calculate a stack trace skipping skip frames and return index into
|
||||
* trace table of stored trace
|
||||
*/
|
||||
unsigned int GetStackTraceIndex(int skip);
|
||||
unsigned int LookupTrace(int *trace);
|
||||
void ChangeSize(int traceIndex, int delta);
|
||||
void DumpFatties();
|
||||
|
||||
/**
|
||||
* Manually set me, for special memory not new/deleted, like the code memory region
|
||||
*/
|
||||
void ChangeSizeForObject(void *object, int size);
|
||||
|
||||
/**
|
||||
* How much extra size does DebugDecorate need?
|
||||
*/
|
||||
size_t DebugSize();
|
||||
|
||||
/**
|
||||
* decorate memory with debug information, return pointer to memory to return to caller
|
||||
*/
|
||||
void *DebugDecorate(void *item, size_t size, int skip);
|
||||
|
||||
/**
|
||||
* Given a pointer to user memory do debug checks and return pointer to real memory
|
||||
*/
|
||||
void *DebugFree(void *item, int poison, int skip);
|
||||
|
||||
/**
|
||||
* Given a pointer to real memory do debug checks and return pointer to user memory
|
||||
*/
|
||||
void *DebugFreeReverse(void *item, int poison, int skip);
|
||||
|
||||
/**
|
||||
* Given a user pointer back up to real beginning
|
||||
*/
|
||||
inline void *GetRealPointer(const void *item) { return (void*)((intptr) item - 2 * sizeof(int)); }
|
||||
|
||||
/**
|
||||
* Given a user pointer back up to real beginning
|
||||
*/
|
||||
inline void *GetUserPointer(const void *item) { return (void*)((intptr) item + 2 * sizeof(int)); }
|
||||
|
||||
const char* GetTypeName(int index, void *obj);
|
||||
|
||||
void GetInfoFromPC(int pc, char *buff, int buffSize);
|
||||
void GetStackTrace(int *trace, int len, int skip);
|
||||
// print stack trace of index into trace table
|
||||
void PrintStackTraceByIndex(unsigned int index);
|
||||
void PrintStackTrace(const void *item);
|
||||
// print stack trace of caller
|
||||
void DumpStackTrace();
|
||||
}
|
||||
|
||||
#endif //MEMORY_INFO
|
||||
#endif //!__GCMemoryProfiler__
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
GCWeakRef* GCObject::GetWeakRef() const
|
||||
{
|
||||
return GC::GetWeakRef(this);
|
||||
}
|
||||
|
||||
GCWeakRef* GCFinalizedObject::GetWeakRef() const
|
||||
{
|
||||
return GC::GetWeakRef(this);
|
||||
}
|
||||
|
||||
void* GCFinalizedObject::operator new(size_t size, GC *gc, size_t extra)
|
||||
{
|
||||
return gc->Alloc(size + extra, GC::kFinalize|GC::kContainsPointers|GC::kZero, 4);
|
||||
}
|
||||
|
||||
void GCFinalizedObject::operator delete (void *gcObject)
|
||||
{
|
||||
GC::GetGC(gcObject)->Free(gcObject);
|
||||
}
|
||||
|
||||
void* GCFinalizedObjectOptIn::operator new(size_t size, GC *gc, size_t extra)
|
||||
{
|
||||
return gc->Alloc(size + extra, GC::kContainsPointers|GC::kZero, 4);
|
||||
}
|
||||
|
||||
void GCFinalizedObjectOptIn::operator delete (void *gcObject)
|
||||
{
|
||||
GC::GetGC(gcObject)->Free(gcObject);
|
||||
}
|
||||
|
||||
#if defined(MMGC_DRC) && defined(_DEBUG)
|
||||
void RCObject::DumpHistory()
|
||||
{
|
||||
GCDebugMsg(false, "Ref count modification history for object 0x%x:\n", this);
|
||||
int *traces = history.GetData();
|
||||
for(int i=0, n=history.Count(); i<n; i++)
|
||||
{
|
||||
PrintStackTraceByIndex(traces[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,390 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCObject__
|
||||
#define __GCObject__
|
||||
|
||||
|
||||
// VC++ wants these declared
|
||||
//void *operator new(size_t size);
|
||||
//void *operator new[] (size_t size);
|
||||
|
||||
inline void *operator new(size_t size, MMgc::GC *gc, int flags=MMgc::GC::kContainsPointers|MMgc::GC::kZero)
|
||||
{
|
||||
return gc->Alloc(size, flags, 4);
|
||||
}
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class GCCustomSizer
|
||||
{
|
||||
public:
|
||||
virtual ~GCCustomSizer() {} // here since gcc complains otherwise
|
||||
virtual size_t Size() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Baseclass for GC managed objects that aren't finalized
|
||||
*/
|
||||
class GCObject
|
||||
{
|
||||
public:
|
||||
static void *operator new(size_t size, GC *gc, size_t extra = 0)
|
||||
#ifdef __GNUC__
|
||||
// add this to avoid GCC warning: 'operator new' must not return NULL unless it is declared 'throw()' (or -fcheck-new is in effect)
|
||||
throw()
|
||||
#endif
|
||||
{
|
||||
// TODO throw exception and shutdown player?
|
||||
if (size + extra < size)
|
||||
{
|
||||
GCAssert(0);
|
||||
return 0;
|
||||
}
|
||||
return gc->Alloc(size + extra, GC::kContainsPointers|GC::kZero, 4);
|
||||
}
|
||||
|
||||
static void operator delete (void *gcObject)
|
||||
{
|
||||
GC::GetGC(gcObject)->Free(gcObject);
|
||||
}
|
||||
|
||||
GCWeakRef *GetWeakRef() const;
|
||||
#ifdef MEMORY_INFO
|
||||
// give everyone a vtable for rtti type info purposes
|
||||
virtual ~GCObject() {}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Baseclass for GC managed objects that are finalized
|
||||
*/
|
||||
class GCFinalizedObject
|
||||
//: public GCObject can't do this, get weird compile errors in AVM plus, I think it has to do with
|
||||
// the most base class (GCObject) not having any virtual methods)
|
||||
{
|
||||
public:
|
||||
virtual ~GCFinalizedObject() {}
|
||||
GCWeakRef *GetWeakRef() const;
|
||||
static void *operator new(size_t size, GC *gc, size_t extra = 0);
|
||||
static void operator delete (void *gcObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Baseclass for GC managed objects that are finalized
|
||||
*/
|
||||
class GCFinalizedObjectOptIn : public GCFinalizedObject
|
||||
//: public GCObject can't do this, get weird compile errors in AVM plus, I think it has to do with
|
||||
// the most base class (GCObject) not having any virtual methods)
|
||||
{
|
||||
public:
|
||||
static void *operator new(size_t size, GC *gc, size_t extra = 0);
|
||||
static void operator delete (void *gcObject);
|
||||
};
|
||||
|
||||
#ifdef MMGC_DRC
|
||||
class RCObject : public GCFinalizedObject
|
||||
{
|
||||
friend class GC;
|
||||
public:
|
||||
RCObject()
|
||||
#ifdef _DEBUG
|
||||
: history(0)
|
||||
#endif
|
||||
{
|
||||
// composite == 0 is special, it means a deleted object in Release builds
|
||||
// b/c RCObjects have a vtable we know composite isn't the first 4 byte and thus
|
||||
// won't be trampled by the freelist
|
||||
composite = 1;
|
||||
GC::GetGC(this)->AddToZCT(this);
|
||||
}
|
||||
|
||||
~RCObject()
|
||||
{
|
||||
// for explicit deletion
|
||||
if (InZCT())
|
||||
GC::GetGC(this)->RemoveFromZCT(this);
|
||||
composite = 0;
|
||||
}
|
||||
|
||||
bool IsPinned()
|
||||
{
|
||||
return (composite & STACK_PIN) != 0;
|
||||
}
|
||||
|
||||
void Pin()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// this is a deleted object but 0xca indicates the InZCT flag so we
|
||||
// might erroneously get here for a deleted RCObject
|
||||
if(composite == 0xcacacaca || composite == 0xbabababa)
|
||||
return;
|
||||
#endif
|
||||
|
||||
// In Release builds, a deleted object is indicated by
|
||||
// composite == 0. We must not set the STACK_PIN bit
|
||||
// on a deleted object, because if we do, it transforms
|
||||
// from a deleted object into a zero-ref count live object,
|
||||
// causing nasty crashes down the line.
|
||||
if (composite == 0)
|
||||
return;
|
||||
|
||||
composite |= STACK_PIN;
|
||||
}
|
||||
|
||||
void Unpin()
|
||||
{
|
||||
composite &= ~STACK_PIN;
|
||||
}
|
||||
|
||||
int InZCT() const { return composite & ZCTFLAG; }
|
||||
int RefCount() const { return (composite & RCBITS) - 1; }
|
||||
int Sticky() const { return composite & STICKYFLAG; }
|
||||
void Stick() { composite = STICKYFLAG; }
|
||||
|
||||
// called by EnqueZCT
|
||||
void ClearZCTFlag()
|
||||
{
|
||||
composite &= ~(ZCTFLAG|ZCT_INDEX);
|
||||
}
|
||||
|
||||
void IncrementRef()
|
||||
{
|
||||
if(Sticky() || composite == 0)
|
||||
return;
|
||||
|
||||
#ifdef _DEBUG
|
||||
GCAssert(GC::GetGC(this)->IsRCObject(this));
|
||||
GCAssert(this == GC::GetGC(this)->FindBeginning(this));
|
||||
// don't touch swept objects
|
||||
if(composite == 0xcacacaca || composite == 0xbabababa)
|
||||
return;
|
||||
#endif
|
||||
|
||||
composite++;
|
||||
if((composite&RCBITS) == RCBITS) {
|
||||
composite |= STICKYFLAG;
|
||||
} else if(InZCT()) {
|
||||
GCAssert(RefCount() == 1);
|
||||
GC::GetGC(this)->RemoveFromZCT(this);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
if(GC::keepDRCHistory)
|
||||
history.Push(GetStackTraceIndex(2));
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void DecrementRef()
|
||||
{
|
||||
if(Sticky() || composite == 0)
|
||||
return;
|
||||
#ifdef _DEBUG
|
||||
GCAssert(GC::GetGC(this)->IsRCObject(this));
|
||||
GCAssert(this == GC::GetGC(this)->FindBeginning(this));
|
||||
// don't touch swept objects
|
||||
if(composite == 0xcacacaca || composite == 0xbabababa)
|
||||
return;
|
||||
|
||||
if(GC::GetGC(this)->Destroying())
|
||||
return;
|
||||
|
||||
if(RefCount() == 0) {
|
||||
DumpHistory();
|
||||
GCAssert(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (RefCount() == 0)
|
||||
{
|
||||
// This is a defensive measure. If DecrementRef is
|
||||
// ever called on a zero ref-count object, composite--
|
||||
// will cause an underflow, flipping all kinds of bits
|
||||
// in bad ways and resulting in a crash later. Often,
|
||||
// such a DecrementRef bug would be caught by the
|
||||
// _DEBUG asserts above, but sometimes we have
|
||||
// release-only crashers like this. Better to fail
|
||||
// gracefully at the point of failure, rather than
|
||||
// push the failure to some later point.
|
||||
return;
|
||||
}
|
||||
|
||||
composite--;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// the delete flag works around the fact that DecrementRef
|
||||
// may be called after ~RCObject since all dtors are called
|
||||
// in one pass. For example a FunctionScriptObject may be
|
||||
// the sole reference to a ScopeChain and dec its ref in
|
||||
// ~FunctionScriptObject during a sweep, but since ScopeChain's
|
||||
// are smaller the ScopeChain was already finalized, thus the
|
||||
// push crashes b/c the history object has been destructed.
|
||||
if(GC::keepDRCHistory)
|
||||
history.Push(GetStackTraceIndex(1));
|
||||
#endif
|
||||
// composite == 1 is the same as (rc == 1 && !notSticky && !notInZCT)
|
||||
if(RefCount() == 0) {
|
||||
GC::GetGC(this)->AddToZCT(this);
|
||||
}
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
void DumpHistory();
|
||||
#endif
|
||||
|
||||
void setZCTIndex(int index)
|
||||
{
|
||||
GCAssert(index >= 0 && index < (ZCT_INDEX>>8));
|
||||
GCAssert(index < ZCT_INDEX>>8);
|
||||
composite = (composite&~ZCT_INDEX) | ((index<<8)|ZCTFLAG);
|
||||
}
|
||||
|
||||
int getZCTIndex() const
|
||||
{
|
||||
return (composite & ZCT_INDEX) >> 8;
|
||||
}
|
||||
|
||||
static void *operator new(size_t size, GC *gc, size_t extra = 0)
|
||||
{
|
||||
return gc->Alloc(size + extra, GC::kContainsPointers|GC::kZero|GC::kRCObject|GC::kFinalize, 4);
|
||||
}
|
||||
|
||||
private:
|
||||
// 1 bit for inZCT flag (0x80000000)
|
||||
// 1 bit for sticky flag (0x40000000)
|
||||
// 20 bits for ZCT index
|
||||
// 8 bits for RC count (0x000000FF)
|
||||
static const int ZCTFLAG = 0x80000000;
|
||||
static const int STICKYFLAG = 0x40000000;
|
||||
static const int STACK_PIN = 0x20000000;
|
||||
static const int RCBITS = 0x000000FF;
|
||||
static const int ZCT_INDEX = 0x0FFFFF00;
|
||||
#ifdef MMGC_DRC
|
||||
int32 composite;
|
||||
#ifdef _DEBUG
|
||||
// addref/decref stack traces
|
||||
GCStack<int,4> history;
|
||||
int padto32bytes;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
class RCFinalizedObject : public RCObject{};
|
||||
|
||||
template<class T>
|
||||
class ZeroPtr
|
||||
{
|
||||
public:
|
||||
ZeroPtr() { t = NULL; }
|
||||
ZeroPtr(T t) : t(t) { }
|
||||
~ZeroPtr()
|
||||
{
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
operator T() { return t; }
|
||||
bool operator!=(T other) { return other != t; }
|
||||
T operator->() const { return t; }
|
||||
private:
|
||||
T t;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class RCPtr
|
||||
{
|
||||
public:
|
||||
RCPtr() { t = NULL; }
|
||||
RCPtr(T t) : t(t) { if(t && (int)t != 1) t->IncrementRef(); }
|
||||
~RCPtr()
|
||||
{
|
||||
if(t && t != (T)1)
|
||||
t->DecrementRef();
|
||||
|
||||
// 02may06 grandma : I want to enable
|
||||
// class DataIOBase { DRC(PlayerToplevel *) const m_toplevel; }
|
||||
//
|
||||
// DataIOBase is a virtual base class, so we don't know if the
|
||||
// subclass is GCObject or not. We need it to be const, or
|
||||
// a GCObject would require a DWB(), and if it's const, we
|
||||
// cannot zero it out during ~DataIOBase. The simplest solution
|
||||
// seemed to be zeroing out the member here.
|
||||
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
T operator=(T tNew)
|
||||
{
|
||||
if(t && (int)t != 1)
|
||||
t->DecrementRef();
|
||||
t = tNew;
|
||||
if(t && (int)t != 1)
|
||||
t->IncrementRef();
|
||||
// this cast is safe b/c other wise compilation would fail
|
||||
return (T) t;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return (T) t;
|
||||
}
|
||||
|
||||
operator ZeroPtr<T>() const { return t; }
|
||||
|
||||
bool operator!=(T other) { return other != t; }
|
||||
|
||||
T operator->() const
|
||||
{
|
||||
return (T) t;
|
||||
}
|
||||
|
||||
void Clear() { t = NULL; }
|
||||
|
||||
private:
|
||||
T t;
|
||||
};
|
||||
|
||||
|
||||
#define DRC(_type) MMgc::RCPtr<_type>
|
||||
|
||||
#else // !MMGC_DRC
|
||||
|
||||
#define DRC(_type) _type
|
||||
|
||||
class RCObject : public GCObject {};
|
||||
class RCFinalizedObject : public GCFinalizedObject {};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif /* __GCObject__ */
|
||||
@@ -1,101 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCSpinLock__
|
||||
#define __GCSpinLock__
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* GCSpinLock is a simple spin lock class used by GCHeap to
|
||||
* ensure mutually exclusive access. The GCHeap may be accessed
|
||||
* by multiple threads, so this is necessary to ensure that
|
||||
* the threads do not step on each other.
|
||||
*/
|
||||
class GCSpinLock
|
||||
{
|
||||
public:
|
||||
GCSpinLock()
|
||||
{
|
||||
pthread_spin_init( &m1, 0 );
|
||||
}
|
||||
|
||||
~GCSpinLock()
|
||||
{
|
||||
pthread_spin_destroy( &m1 );
|
||||
}
|
||||
|
||||
inline void Acquire()
|
||||
{
|
||||
pthread_spin_lock( &m1 );
|
||||
}
|
||||
|
||||
inline void Release()
|
||||
{
|
||||
pthread_spin_unlock( &m1 );
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_spinlock_t m1;
|
||||
};
|
||||
|
||||
/**
|
||||
* GCAcquireSpinlock is a convenience class which acquires
|
||||
* the specified spinlock at construct time, then releases
|
||||
* the spinlock at desruct time. The single statement
|
||||
*
|
||||
* GCAcquireSpinlock acquire(spinlock);
|
||||
*
|
||||
* ... will acquire the spinlock at the top of the function
|
||||
* and release it at the end. This makes for less error-prone
|
||||
* code than explicit acquire/release.
|
||||
*/
|
||||
class GCAcquireSpinlock
|
||||
{
|
||||
public:
|
||||
GCAcquireSpinlock(GCSpinLock& spinlock) : m_spinlock(spinlock)
|
||||
{
|
||||
m_spinlock.Acquire();
|
||||
}
|
||||
~GCAcquireSpinlock()
|
||||
{
|
||||
m_spinlock.Release();
|
||||
}
|
||||
|
||||
private:
|
||||
GCSpinLock& m_spinlock;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCSpinLock__ */
|
||||
@@ -1,135 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __GCSpinLock__
|
||||
#define __GCSpinLock__
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#else // __GNUC__
|
||||
#include <Multiprocessing.h>
|
||||
#endif // __GNUC__
|
||||
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
extern "C"
|
||||
{
|
||||
extern void _spin_lock(uint32_t *);
|
||||
extern void _spin_unlock(uint32_t *);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* GCSpinLock is a simple spin lock class used by GCHeap to
|
||||
* ensure mutually exclusive access. The GCHeap may be accessed
|
||||
* by multiple threads, so this is necessary to ensure that
|
||||
* the threads do not step on each other.
|
||||
*/
|
||||
class GCSpinLock
|
||||
{
|
||||
public:
|
||||
GCSpinLock()
|
||||
{
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
m1 = 0;
|
||||
#else
|
||||
OSStatus critErr = ::MPCreateCriticalRegion( &mCriticalRegion );
|
||||
GCAssert( critErr == noErr );
|
||||
#endif
|
||||
}
|
||||
|
||||
~GCSpinLock()
|
||||
{
|
||||
#if !TARGET_RT_MAC_MACHO
|
||||
OSStatus critErr = ::MPDeleteCriticalRegion( mCriticalRegion );
|
||||
GCAssert( critErr == noErr );
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void Acquire()
|
||||
{
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
_spin_lock(&m1);
|
||||
#else
|
||||
OSStatus critErr = ::MPEnterCriticalRegion( mCriticalRegion, kDurationForever );
|
||||
GCAssert( critErr == noErr );
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void Release()
|
||||
{
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
_spin_unlock(&m1);
|
||||
#else
|
||||
OSStatus critErr = ::MPExitCriticalRegion( mCriticalRegion );
|
||||
GCAssert( critErr == noErr );
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
uint32_t m1;
|
||||
#else
|
||||
MPCriticalRegionID mCriticalRegion;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* GCAcquireSpinlock is a convenience class which acquires
|
||||
* the specified spinlock at construct time, then releases
|
||||
* the spinlock at desruct time. The single statement
|
||||
*
|
||||
* GCAcquireSpinlock acquire(spinlock);
|
||||
*
|
||||
* ... will acquire the spinlock at the top of the function
|
||||
* and release it at the end. This makes for less error-prone
|
||||
* code than explicit acquire/release.
|
||||
*/
|
||||
class GCAcquireSpinlock
|
||||
{
|
||||
public:
|
||||
GCAcquireSpinlock(GCSpinLock& spinlock) : m_spinlock(spinlock)
|
||||
{
|
||||
m_spinlock.Acquire();
|
||||
}
|
||||
~GCAcquireSpinlock()
|
||||
{
|
||||
m_spinlock.Release();
|
||||
}
|
||||
|
||||
private:
|
||||
GCSpinLock& m_spinlock;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCSpinLock__ */
|
||||
@@ -1,99 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCSpinLock__
|
||||
#define __GCSpinLock__
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* GCSpinLock is a simple spin lock class used by GCHeap to
|
||||
* ensure mutually exclusive access. The GCHeap may be accessed
|
||||
* by multiple threads, so this is necessary to ensure that
|
||||
* the threads do not step on each other.
|
||||
*/
|
||||
class GCSpinLock
|
||||
{
|
||||
public:
|
||||
GCSpinLock()
|
||||
{
|
||||
sl = 0;
|
||||
}
|
||||
|
||||
inline void Acquire()
|
||||
{
|
||||
GCAssert(sl==0 || sl==1 || sl==0); // Poor mans defense against thread timing issues, per Tom R.
|
||||
while (InterlockedCompareExchange(&sl, 1, 0) != 0) {
|
||||
Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Release()
|
||||
{
|
||||
InterlockedExchange(&sl, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
long sl;
|
||||
};
|
||||
|
||||
/**
|
||||
* GCAcquireSpinlock is a convenience class which acquires
|
||||
* the specified spinlock at construct time, then releases
|
||||
* the spinlock at desruct time. The single statement
|
||||
*
|
||||
* GCAcquireSpinlock acquire(spinlock);
|
||||
*
|
||||
* ... will acquire the spinlock at the top of the function
|
||||
* and release it at the end. This makes for less error-prone
|
||||
* code than explicit acquire/release.
|
||||
*/
|
||||
class GCAcquireSpinlock
|
||||
{
|
||||
public:
|
||||
GCAcquireSpinlock(GCSpinLock& spinlock) : m_spinlock(spinlock)
|
||||
{
|
||||
m_spinlock.Acquire();
|
||||
}
|
||||
~GCAcquireSpinlock()
|
||||
{
|
||||
m_spinlock.Release();
|
||||
}
|
||||
|
||||
private:
|
||||
GCSpinLock& m_spinlock;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCSpinLock__ */
|
||||
@@ -1,123 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCStack__
|
||||
#define __GCStack__
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
template<typename T, int defSize=512>
|
||||
class GCStack
|
||||
{
|
||||
enum { kDefSize = defSize };
|
||||
public:
|
||||
GCStack(int defaultSize=kDefSize) : m_iCount(0), m_iAllocSize(defaultSize), m_items(NULL)
|
||||
{
|
||||
Alloc();
|
||||
}
|
||||
|
||||
~GCStack()
|
||||
{
|
||||
if ( m_items )
|
||||
{
|
||||
delete [] m_items;
|
||||
m_items = NULL;
|
||||
}
|
||||
m_iCount = m_iAllocSize = 0;
|
||||
}
|
||||
|
||||
void Push(T item)
|
||||
{
|
||||
if ( ( m_iCount + 1 ) > m_iAllocSize )
|
||||
{
|
||||
// need to allocate a new block first
|
||||
m_iAllocSize = m_iAllocSize ? m_iAllocSize*2 : kDefSize;
|
||||
Alloc();
|
||||
}
|
||||
|
||||
m_items[m_iCount++] = item;
|
||||
}
|
||||
|
||||
T Pop()
|
||||
{
|
||||
T t = m_items[--m_iCount];
|
||||
#ifdef _DEBUG
|
||||
GCAssert(m_iCount>=0);
|
||||
memset(&m_items[m_iCount], 0, sizeof(T));
|
||||
#endif
|
||||
return t;
|
||||
}
|
||||
|
||||
T Peek()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
GCAssert(m_iCount>=0);
|
||||
#endif
|
||||
T t = m_items[m_iCount-1];
|
||||
return t;
|
||||
}
|
||||
|
||||
unsigned int Count() { return m_iCount; }
|
||||
|
||||
void Keep(unsigned int num)
|
||||
{
|
||||
GCAssert(num <= m_iCount);
|
||||
m_iCount = num;
|
||||
}
|
||||
|
||||
T* GetData() { return m_items; }
|
||||
|
||||
protected:
|
||||
// no impl
|
||||
GCStack(const GCStack& other);
|
||||
GCStack& operator=(const GCStack& other);
|
||||
|
||||
private:
|
||||
void Alloc()
|
||||
{
|
||||
// need to allocate a new block first
|
||||
if(m_iAllocSize) {
|
||||
T* items = new T[ m_iAllocSize ];
|
||||
if ( items )
|
||||
{
|
||||
::memcpy(items, m_items, m_iCount * sizeof(T));
|
||||
}
|
||||
delete [] m_items;
|
||||
m_items = items;
|
||||
}
|
||||
}
|
||||
unsigned int m_iCount, m_iAllocSize;
|
||||
T *m_items;
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __GCStack__ */
|
||||
@@ -1,147 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#include "MMgc.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// "behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized"
|
||||
#pragma warning(disable:4345) // b/c GCObject doesn't have a ctor
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
GC *gc;
|
||||
|
||||
GCWeakRef* createWeakRef(int extra=0)
|
||||
{
|
||||
return (new (gc, extra) GCObject())->GetWeakRef();
|
||||
}
|
||||
|
||||
void weakRefSweepSmall()
|
||||
{
|
||||
GCWeakRef *ref = createWeakRef();
|
||||
gc->Collect();
|
||||
gc->CleanStack(true);
|
||||
gc->Collect();
|
||||
(void)ref;
|
||||
GCAssert(ref->get() == NULL);
|
||||
}
|
||||
|
||||
void weakRefSweepLarge()
|
||||
{
|
||||
GCWeakRef *ref = createWeakRef(5000);
|
||||
gc->Collect();
|
||||
gc->CleanStack(true);
|
||||
gc->Collect();
|
||||
(void)ref;
|
||||
GCAssert(ref->get() == NULL);
|
||||
}
|
||||
|
||||
void weakRefFreeSmall()
|
||||
{
|
||||
GCWeakRef *ref = createWeakRef();
|
||||
delete ref->get();
|
||||
GCAssert(ref->get() == NULL);
|
||||
}
|
||||
|
||||
void weakRefFreeLarge()
|
||||
{
|
||||
GCWeakRef *ref = createWeakRef(5000);
|
||||
delete ref->get();
|
||||
GCAssert(ref->get() == NULL);
|
||||
}
|
||||
|
||||
class RCObjectAddRefInDtor : public RCObject
|
||||
{
|
||||
public:
|
||||
RCObjectAddRefInDtor(RCObject **stackPinners, int length) : rcs(stackPinners), length(length) {}
|
||||
~RCObjectAddRefInDtor()
|
||||
{
|
||||
// whack these, used create freelist
|
||||
for(int i=0, n=length; i<n;i++)
|
||||
{
|
||||
r1 = rcs[i];
|
||||
}
|
||||
|
||||
// add/remove myself (this was the apollo bug)
|
||||
r1 = this;
|
||||
r1 = NULL;
|
||||
rcs = NULL;
|
||||
length = 0;
|
||||
}
|
||||
DRCWB(RCObject*) r1;
|
||||
|
||||
// naked pointer so I can kick these pinners out out of the ZCT during reap
|
||||
RCObject **rcs;
|
||||
int length;
|
||||
};
|
||||
|
||||
GCWeakRef* createProblem(RCObject **stackPinners)
|
||||
{
|
||||
// now create one that causes some removes from the dtor
|
||||
return (new (gc) RCObjectAddRefInDtor(stackPinners, 3))->GetWeakRef();
|
||||
}
|
||||
|
||||
/* see bug 182420 */
|
||||
void drcApolloTest()
|
||||
{
|
||||
// prime ZCT with some pinners
|
||||
RCObject *stackPinners[3];
|
||||
|
||||
GCWeakRef *wr = createProblem(stackPinners);
|
||||
|
||||
stackPinners[0] = new (gc) RCObject();
|
||||
stackPinners[1] = new (gc) RCObject();
|
||||
stackPinners[2] = new (gc) RCObject();
|
||||
|
||||
// force ZCT
|
||||
for(int i=0, n=1000;i<n; i++)
|
||||
{
|
||||
new (gc) RCObject();
|
||||
}
|
||||
|
||||
// it may still be alive if we had a dirty stack
|
||||
if(wr->get())
|
||||
delete wr->get();
|
||||
}
|
||||
|
||||
void RunGCTests(GC *g)
|
||||
{
|
||||
gc = g;
|
||||
weakRefSweepSmall();
|
||||
weakRefSweepLarge();
|
||||
weakRefFreeSmall();
|
||||
weakRefFreeLarge();
|
||||
drcApolloTest();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __GCTests__
|
||||
#define __GCTests__
|
||||
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
void RunGCTests(GC *gc);
|
||||
}
|
||||
|
||||
#endif /* __GCTests__ */
|
||||
@@ -1,94 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#ifndef __GCTypes__
|
||||
#define __GCTypes__
|
||||
|
||||
#ifdef _MAC
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
typedef __int64 int64;
|
||||
typedef __int64 sint64;
|
||||
typedef unsigned __int64 uint64;
|
||||
#elif defined(_MAC)
|
||||
typedef int64_t int64;
|
||||
typedef int64_t sint64;
|
||||
typedef uint64_t uint64;
|
||||
#else
|
||||
typedef long long int64;
|
||||
typedef long long sint64;
|
||||
typedef unsigned long long uint64;
|
||||
#endif
|
||||
|
||||
typedef unsigned long uint32;
|
||||
typedef signed long int32;
|
||||
|
||||
typedef unsigned short uint16;
|
||||
typedef signed short int16;
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef signed char int8;
|
||||
|
||||
// math friendly pointer (64 bits in LP 64 systems)
|
||||
typedef unsigned long intptr;
|
||||
|
||||
/* wchar is our version of wchar_t, since wchar_t is different sizes
|
||||
on different platforms, but we want to use UTF-16 uniformly. */
|
||||
typedef unsigned short wchar;
|
||||
|
||||
/**
|
||||
* Conservative collector unit of work
|
||||
*/
|
||||
class GCWorkItem
|
||||
{
|
||||
public:
|
||||
GCWorkItem() : ptr(0), size(0) {}
|
||||
GCWorkItem(const void *p, uint32 s) : ptr(p), size(s) {}
|
||||
const void *ptr;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
|
||||
typedef void* (*GCMallocFuncPtr)(size_t size);
|
||||
typedef void (*GCFreeFuncPtr)(void* mem);
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* __GCTypes__ */
|
||||
@@ -1,107 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
//
|
||||
// GCWeakRef.h
|
||||
// GC weak references (aka safe handles) as template classes
|
||||
//
|
||||
|
||||
#ifndef _GC_WEAK_REF_H_
|
||||
#define _GC_WEAK_REF_H_
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
// new improved weak ref
|
||||
class GCWeakRef : public GCObject
|
||||
{
|
||||
friend class GC;
|
||||
public:
|
||||
GCObject *get() { return (GCObject*)m_obj; }
|
||||
void clear() { m_obj = 0; }
|
||||
private:
|
||||
// override new so we can be tell the GC we don't contain pointers
|
||||
static void *operator new(size_t size, GC *gc)
|
||||
{
|
||||
return gc->Alloc(size, 0, 4);
|
||||
}
|
||||
// private, only GC can access
|
||||
GCWeakRef(const void *obj) : m_obj(obj)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
obj_creation = *((int*)GetRealPointer(obj)+1);
|
||||
#endif
|
||||
}
|
||||
const void *m_obj;
|
||||
#ifdef _DEBUG
|
||||
int obj_creation;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if 0
|
||||
// something like this would be nice
|
||||
template<class T> class GCWeakRefPtr
|
||||
{
|
||||
|
||||
public:
|
||||
GCWeakRefPtr() {}
|
||||
GCWeakRefPtr(T t) { set(t);}
|
||||
~GCWeakRefPtr() { t = NULL; }
|
||||
|
||||
T operator=(const GCWeakRefPtr<T>& wb)
|
||||
{
|
||||
return set(wb.t);
|
||||
}
|
||||
|
||||
T operator=(T tNew)
|
||||
{
|
||||
return set(tNew);
|
||||
}
|
||||
|
||||
operator T() const { return (T) t->get(); }
|
||||
|
||||
bool operator!=(T other) const { return other != t; }
|
||||
|
||||
T operator->() const
|
||||
{
|
||||
return (T) t->get();
|
||||
}
|
||||
private:
|
||||
T set(const T tNew)
|
||||
{
|
||||
t = tNew->GetWeakRef();
|
||||
}
|
||||
GCWeakRef* t;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // _GC_WEAK_REF_H_
|
||||
@@ -1,32 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "MMgc.h"
|
||||
@@ -1,151 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifndef __MMgc__
|
||||
#define __MMgc__
|
||||
|
||||
|
||||
// For size_t
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include "winbuild.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MAC
|
||||
#include "macbuild.h"
|
||||
#endif
|
||||
|
||||
#ifdef AVMPLUS_LINUX
|
||||
#include "linuxbuild.h"
|
||||
#endif
|
||||
|
||||
#ifdef MMGC_ARM
|
||||
#include "armbuild.h"
|
||||
#endif
|
||||
|
||||
//define this to get an alloc log
|
||||
//#define ALLOC_LOG
|
||||
|
||||
#if defined(ALLOC_LOG) || defined(GC_STATS)
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifdef SCRIPT_DEBUGGER
|
||||
#ifndef DEBUGGER
|
||||
#define DEBUGGER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(_MAC)
|
||||
// for memset
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define __forceinline
|
||||
#endif
|
||||
|
||||
#include "GCDebug.h"
|
||||
/*
|
||||
* If _GCHeapLock is defined, a spin lock is used for thread safety
|
||||
* on all public API's (Alloc, Free, ExpandHeap)
|
||||
*
|
||||
* Warning:
|
||||
* We may use GCHeap for allocation on other threads, hence the
|
||||
* spinlock, but the MMgc garbage collector in general is not
|
||||
* thread-safe.
|
||||
*/
|
||||
|
||||
#ifdef GCHEAP_LOCK
|
||||
#ifdef WIN32
|
||||
#include "GCSpinLockWin.h"
|
||||
#endif
|
||||
#ifdef _MAC
|
||||
#include "GCSpinLockMac.h"
|
||||
#endif
|
||||
#ifdef AVMPLUS_LINUX
|
||||
#include "GCSpinLockLinux.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
class GCAllocBase;
|
||||
class GC;
|
||||
class GCTraceObject;
|
||||
class RCObject;
|
||||
class GCWeakRef;
|
||||
class GCObject;
|
||||
class GCHashtable;
|
||||
class Cleaner;
|
||||
class GCAlloc;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4291) // no matching operator delete found; memory will not be freed if initialization throws an exception
|
||||
#endif
|
||||
|
||||
#include "GCTypes.h"
|
||||
#include "GCStack.h"
|
||||
#include "GCAllocObject.h"
|
||||
#include "GCAllocBase.h"
|
||||
#include "GCHeap.h"
|
||||
#include "GCAlloc.h"
|
||||
#include "GCLargeAlloc.h"
|
||||
#include "GCMemoryProfiler.h"
|
||||
#include "FixedAlloc.h"
|
||||
#include "FixedMalloc.h"
|
||||
#include "GCHashtable.h"
|
||||
#include "GC.h"
|
||||
#include "GCObject.h"
|
||||
#include "GCWeakRef.h"
|
||||
#include "WriteBarrier.h"
|
||||
|
||||
#ifdef MMGC_AVMPLUS
|
||||
#include "avmbuild.h"
|
||||
#include "avmplus.h"
|
||||
#ifdef AVMPLUS_PROFILE
|
||||
#define PROFILE(x) avmplus::DynamicProfiler::StackMark mark(x)
|
||||
#else
|
||||
#define PROFILE(x)
|
||||
#endif
|
||||
#else
|
||||
#define PROFILE(x)
|
||||
#endif
|
||||
|
||||
#if defined(MMGC_DRC) && !defined(WRITE_BARRIERS)
|
||||
#error "Need write barriers for DRC"
|
||||
#endif
|
||||
|
||||
#endif /* __MMgc__ */
|
||||
|
||||
Binary file not shown.
@@ -1,30 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMgc", "MMgc.vcproj", "{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Release = Release
|
||||
VTune = VTune
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug.ActiveCfg = Debug|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug.Build.0 = Debug|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release.ActiveCfg = Release|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release.Build.0 = Release|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.VTune.ActiveCfg = VTune|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.VTune.Build.0 = VTune|Win32
|
||||
{FE29422B-B9A1-4C3A-954A-0B37CF0642D5}.Debug.ActiveCfg = Debug|Win32
|
||||
{FE29422B-B9A1-4C3A-954A-0B37CF0642D5}.Debug.Build.0 = Debug|Win32
|
||||
{FE29422B-B9A1-4C3A-954A-0B37CF0642D5}.Release.ActiveCfg = Release|Win32
|
||||
{FE29422B-B9A1-4C3A-954A-0B37CF0642D5}.Release.Build.0 = Release|Win32
|
||||
{FE29422B-B9A1-4C3A-954A-0B37CF0642D5}.VTune.ActiveCfg = VTune|Win32
|
||||
{FE29422B-B9A1-4C3A-954A-0B37CF0642D5}.VTune.Build.0 = VTune|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,375 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="MMgc"
|
||||
ProjectGUID="{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}"
|
||||
SccProjectName=""
|
||||
SccAuxPath=""
|
||||
SccLocalPath=""
|
||||
SccProvider=""
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="0">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;AVMPLUS_IA32"
|
||||
MinimalRebuild="TRUE"
|
||||
ExceptionHandling="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc_d.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="0">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
FavorSizeOrSpeed="0"
|
||||
OptimizeForProcessor="0"
|
||||
AdditionalIncludeDirectories=".;..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;AVMPLUS_IA32"
|
||||
StringPooling="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="FALSE"
|
||||
UsePrecompiledHeader="0"
|
||||
AssemblerOutput="4"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="FALSE"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="VTune|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="0">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
OptimizeForProcessor="2"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;AVMPLUS_IA32"
|
||||
StringPooling="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="FALSE"
|
||||
UsePrecompiledHeader="0"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="2"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="lib/MMgc_vtune.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release Debugger|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;DEBUGGER;AVMPLUS_IA32"
|
||||
StringPooling="TRUE"
|
||||
ExceptionHandling="FALSE"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="FALSE"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="TRUE"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug Debugger|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="0">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;DEBUGGER;AVMPLUS_IA32"
|
||||
MinimalRebuild="TRUE"
|
||||
ExceptionHandling="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="FALSE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc_d.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\FixedAlloc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FixedMalloc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GC.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAlloc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAllocBase.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCAllocObjectWin.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCDebugWin.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCHashtable.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCHeap.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCHeapWin.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCLargeAlloc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCMemoryProfiler.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCObject.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCTests.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath=".\FixedAlloc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FixedMalloc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GC.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAlloc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAllocBase.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCAllocObject.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCDebug.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCHashtable.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCHeap.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCLargeAlloc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCMemoryProfiler.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCObject.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCSpinLockWin.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCStack.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCTests.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCTypes.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCWeakRef.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\MMgc.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\winbuild.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\WriteBarrier.h">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\VTune\MMgc.vpj">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,28 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMgc", "MMgc_8.vcproj", "{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug Debugger|Win32 = Debug Debugger|Win32
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release Debugger|Win32 = Release Debugger|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
VTune|Win32 = VTune|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug Debugger|Win32.ActiveCfg = Debug Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug Debugger|Win32.Build.0 = Debug Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release Debugger|Win32.ActiveCfg = Release Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release Debugger|Win32.Build.0 = Release Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release|Win32.Build.0 = Release|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.VTune|Win32.ActiveCfg = VTune|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.VTune|Win32.Build.0 = VTune|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,531 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8.00"
|
||||
Name="MMgc"
|
||||
ProjectGUID="{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}"
|
||||
Keyword="Win32Proj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
IntermediateDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;AVMPLUS_IA32;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
ExceptionHandling="1"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
UsePrecompiledHeader="0"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="true"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc_d.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
IntermediateDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
FavorSizeOrSpeed="0"
|
||||
AdditionalIncludeDirectories=".;..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;AVMPLUS_IA32;_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="0"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
AssemblerOutput="4"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="true"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="0"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="VTune|Win32"
|
||||
OutputDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
IntermediateDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="3"
|
||||
FavorSizeOrSpeed="1"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;AVMPLUS_IA32;_CRT_SECURE_NO_DEPRECATE"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="0"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="true"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc_vtune.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release Debugger|Win32"
|
||||
OutputDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
IntermediateDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;DEBUGGER;AVMPLUS_IA32;_CRT_SECURE_NO_DEPRECATE"
|
||||
ExceptionHandling="0"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
RuntimeTypeInfo="false"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug Debugger|Win32"
|
||||
OutputDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
IntermediateDirectory="obj_8/$(ProjectName)/$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="0"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\core;..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;DEBUGGER;AVMPLUS_IA32;_CRT_SECURE_NO_DEPRECATE"
|
||||
MinimalRebuild="true"
|
||||
ExceptionHandling="1"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
UsePrecompiledHeader="0"
|
||||
ProgramDataBaseFileName="$(IntDir)/MMgc.pdb"
|
||||
BrowseInformation="0"
|
||||
WarningLevel="4"
|
||||
WarnAsError="true"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/MMgc_d.lib"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\FixedAlloc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FixedMalloc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GC.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAlloc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAllocBase.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCAllocObjectWin.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCDebugWin.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCHashtable.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCHeap.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCHeapWin.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCLargeAlloc.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCMemoryProfiler.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCObject.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCTests.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\FixedAlloc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FixedMalloc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GC.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAlloc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCAllocBase.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCAllocObject.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCDebug.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCHashtable.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCHeap.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="GCLargeAlloc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCMemoryProfiler.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCObject.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCSpinLockWin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCStack.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCTests.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCTypes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\GCWeakRef.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\MMgc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\winbuild.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\WriteBarrier.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\VTune\MMgc.vpj"
|
||||
>
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,108 +0,0 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
# "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
# WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
# language governing rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is [Open Source Virtual Machine.]
|
||||
#
|
||||
# The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
# by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
# Contributor(s): Adobe AS3 Team
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
# General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
# License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
# LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
# file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
# version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
# above and replace them with the notice and other provisions required by the GPL or the
|
||||
# LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
# under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
# DEBUG can be set to YES to include debugging info, or NO otherwise
|
||||
DEBUG := YES
|
||||
|
||||
# DEBUGGER can be set to choose the Content Debugger version of the gc
|
||||
DEBUGGER := YES
|
||||
|
||||
MMGC_ROOT := .
|
||||
|
||||
CC := gcc
|
||||
CXX := g++
|
||||
AR := ar
|
||||
|
||||
UNAME := $(shell uname)
|
||||
|
||||
ARCH := ${shell uname -m}
|
||||
|
||||
ifeq ($(UNAME),Linux)
|
||||
MMGC_PLATFORM_DEFS := -DSOFT_ASSERTS -D_DEBUG
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
MMGC_PLATFORM_DEFS := -DDARWIN -D_MAC -Dpowerc -DSOFT_ASSERTS -DDEBUGGER -DTARGET_RT_MAC_MACHO=1 -D_DEBUG -DDEBUG
|
||||
ifeq (${ARCH},i386)
|
||||
MMGC_PLATFORM_DEFS := ${MMGC_PLATFORM_DEFS} -DAVMPLUS_IA32
|
||||
else
|
||||
MMGC_PLATFORM_DEFS := ${MMGC_PLATFORM_DEFS} -DAVMPLUS_PPC
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME),CYGWIN_NT-5.1)
|
||||
MMGC_PLATFORM_DEFS := -DCYGWIN -DAVMPLUS_IA32
|
||||
endif
|
||||
|
||||
include makecommon
|
||||
|
||||
#****************************************************************************
|
||||
# Targets of the build
|
||||
#****************************************************************************
|
||||
|
||||
OUTPUT := libmmgc.a
|
||||
|
||||
all: ${OUTPUT}
|
||||
|
||||
#****************************************************************************
|
||||
# Output
|
||||
#****************************************************************************
|
||||
|
||||
OBJS := $(addsuffix .o,$(basename ${MMGC_SRCS}))
|
||||
|
||||
${OUTPUT}: ${OBJS}
|
||||
@echo "=== creating libmmgc.a ==="
|
||||
${AR} rcs $@ ${OBJS}
|
||||
@echo "Done"
|
||||
|
||||
#****************************************************************************
|
||||
# Dependencies
|
||||
#****************************************************************************
|
||||
|
||||
# Create a lists of object and .d files to create -
|
||||
# one for each source file in the directory
|
||||
DEPS := ${patsubst %${strip .cpp},%.d,${MMGC_SRCS}}
|
||||
|
||||
# make any non-existent make files (using the g++ preprocessor)
|
||||
${DEPS} : %.d : %.cpp
|
||||
${CXX} ${MMGC_CXXFLAGS} ${MMGC_INCS} -MM $< > $@
|
||||
|
||||
# Rules
|
||||
|
||||
clean:
|
||||
-rm -f core* ${OBJS} ${OUTPUT} ${DEPS} log outputdebug.txt
|
||||
|
||||
ifneq (${MAKECMDGOALS},clean)
|
||||
ifneq (${UNAME},Linux)
|
||||
include ${DEPS} # include the generated make files, which make the object files
|
||||
endif
|
||||
endif
|
||||
@@ -1,172 +0,0 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
# "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
# WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
# language governing rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is [Open Source Virtual Machine.]
|
||||
#
|
||||
# The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
# by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
# Contributor(s): Adobe AS3 Team
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
# General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
# License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
# LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
# file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
# version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
# above and replace them with the notice and other provisions required by the GPL or the
|
||||
# LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
# under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
# Set this to yes if doing ARM skunkworks
|
||||
ARM_SKUNKWORKS := YES
|
||||
|
||||
# Set this to yes for GNUARM
|
||||
GNUARM := YES
|
||||
|
||||
# DEBUG can be set to YES to include debugging info, or NO otherwise
|
||||
DEBUG := YES
|
||||
|
||||
CC := arm-elf-gcc
|
||||
CXX := arm-elf-g++
|
||||
AR := arm-elf-ar
|
||||
RANLIB := arm-elf-ranlib
|
||||
|
||||
UNAME := $(shell uname)
|
||||
|
||||
ifeq ($(UNAME),Linux)
|
||||
PLATFORM_DEFS := -DAVMPLUS_LINUX -DSOFT_ASSERTS -DDEBUGGER -DAVMPLUS_IA32 -D_DEBUG -DDEBUG -DCYGWIN -DAVMPLUS_IA32
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
PLATFORM_DEFS := -DDARWIN -D_MAC -Dpowerc -DSOFT_ASSERTS -DAVMPLUS_PPC -DDEBUGGER -DTARGET_RT_MAC_MACHO=1 -D_DEBUG -DDEBUG
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME),CYGWIN_NT-5.1)
|
||||
PLATFORM_DEFS := -DCYGWIN -DAVMPLUS_IA32
|
||||
endif
|
||||
|
||||
ifeq (YES, ${ARM_SKUNKWORKS})
|
||||
ifeq (YES, ${GNUARM})
|
||||
SOFT_FLOAT :=
|
||||
USE_MMAP :=
|
||||
else
|
||||
SOFT_FLOAT := -msoft-float
|
||||
USE_MMAP := -DUSE_MMAP
|
||||
endif
|
||||
else
|
||||
SOFT_FLOAT :=
|
||||
USE_MMAP := -DUSE_MMAP
|
||||
endif
|
||||
|
||||
ifeq (YES, ${ARM_SKUNKWORKS})
|
||||
PLATFORM_DEFS := -DSOFT_ASSERTS -DMMGC_ARM -DAVMPLUS_ARM -DAVMPLUS_UCLINUX -DDEBUGGER -D_DEBUG -DDEBUG
|
||||
endif
|
||||
|
||||
DEBUG_CFLAGS := -g -MMD
|
||||
RELEASE_CFLAGS := -O3 -MMD
|
||||
|
||||
DEBUG_CXXFLAGS := ${DEBUG_CFLAGS} -fno-rtti -fcheck-new ${SOFT_FLOAT} ${USE_MMAP}
|
||||
RELEASE_CXXFLAGS := ${RELEASE_CFLAGS} -fno-rtti -fcheck-new ${SOFT_FLOAT} ${USE_MMAP}
|
||||
|
||||
ifeq (YES, ${DEBUG})
|
||||
CFLAGS := ${DEBUG_CFLAGS}
|
||||
CXXFLAGS := ${DEBUG_CXXFLAGS}
|
||||
else
|
||||
CFLAGS := ${RELEASE_CFLAGS}
|
||||
CXXFLAGS := ${RELEASE_CXXFLAGS}
|
||||
endif
|
||||
|
||||
#****************************************************************************
|
||||
# Preprocessor directives
|
||||
#****************************************************************************
|
||||
|
||||
DEFS := -DUNIX ${PLATFORM_DEFS} -DENABLE_PROFILER
|
||||
|
||||
CFLAGS := ${CFLAGS} ${DEFS}
|
||||
CXXFLAGS := ${CXXFLAGS} ${DEFS}
|
||||
|
||||
#****************************************************************************
|
||||
# Include paths
|
||||
#****************************************************************************
|
||||
|
||||
INCS := -I. -I../core -I../codegen
|
||||
|
||||
#****************************************************************************
|
||||
# Targets of the build
|
||||
#****************************************************************************
|
||||
|
||||
OUTPUT := libmmgc.a
|
||||
|
||||
all: ${OUTPUT}
|
||||
|
||||
#****************************************************************************
|
||||
# Source files
|
||||
#****************************************************************************
|
||||
|
||||
SRCS := GCObject.cpp \
|
||||
GCMemoryProfiler.cpp \
|
||||
GCLargeAlloc.cpp \
|
||||
GCHeapUnix.cpp \
|
||||
GCHeap.cpp \
|
||||
GCHashtable.cpp \
|
||||
GCDebugUnix.cpp \
|
||||
GCAllocObjectUnix.cpp \
|
||||
GCAllocBase.cpp \
|
||||
GCAlloc.cpp \
|
||||
GC.cpp \
|
||||
FixedMalloc.cpp \
|
||||
FixedAlloc.cpp
|
||||
|
||||
#****************************************************************************
|
||||
# Output
|
||||
#****************************************************************************
|
||||
|
||||
OBJS := $(addsuffix .o,$(basename ${SRCS}))
|
||||
|
||||
${OUTPUT}: ${OBJS}
|
||||
${AR} rcs $@ ${OBJS}
|
||||
${RANLIB} $@
|
||||
@echo "Done"
|
||||
|
||||
#****************************************************************************
|
||||
# Dependencies
|
||||
#****************************************************************************
|
||||
|
||||
# Create a lists of object and .d files to create -
|
||||
# one for each source file in the directory
|
||||
DEPS := $(addsufix .d,$(basename ${SRCS}))
|
||||
|
||||
# make any non-existent make files (using the g++ preprocessor)
|
||||
${DEPS} : %.d : %.cpp
|
||||
${CXX} ${CXXFLAGS} ${INCS} -MM $< > $@
|
||||
|
||||
#****************************************************************************
|
||||
# Rules
|
||||
#****************************************************************************
|
||||
|
||||
# Rules for compiling source files to object files
|
||||
%.o : %.cpp
|
||||
@echo "=== compiling:" $@ ${OPT}
|
||||
@${CXX} -c ${OPT} ${CXXFLAGS} ${INCS} $< -o $@
|
||||
|
||||
clean:
|
||||
-rm -f core* ${OBJS} ${OUTPUT} ${DEPS} log outputdebug.txt
|
||||
|
||||
ifneq (${MAKECMDGOALS},clean)
|
||||
ifneq (${UNAME},Linux)
|
||||
include ${DEPS} # include the generated make files, which make the object files
|
||||
endif
|
||||
endif
|
||||
@@ -1,189 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
//
|
||||
// GCWriteBarrier
|
||||
//
|
||||
|
||||
#ifndef _WRITE_BARRIER_H_
|
||||
#define _WRITE_BARRIER_H_
|
||||
|
||||
#ifdef WRITE_BARRIERS
|
||||
|
||||
// inline write barrier
|
||||
#define WB(gc, container, addr, value) gc->writeBarrier(container, addr, (const void *) (value))
|
||||
|
||||
// fast manual RC write barrier
|
||||
#define WBRC(gc, container, addr, value) gc->writeBarrierRC(container, addr, (const void *) (value))
|
||||
|
||||
// declare write barrier
|
||||
#define DWB(type) MMgc::WriteBarrier<type>
|
||||
|
||||
// declare an optimized RCObject write barrier
|
||||
#define DRCWB(type) MMgc::WriteBarrierRC<type>
|
||||
|
||||
#else
|
||||
|
||||
#define WB(gc, container, addr, value) *addr = value
|
||||
|
||||
#define WBRC(gc, container, addr, value) *addr = value
|
||||
|
||||
// declare write barrier
|
||||
#define DWB(type) type
|
||||
|
||||
#define DVWB(type) type
|
||||
|
||||
#endif
|
||||
|
||||
namespace MMgc
|
||||
{
|
||||
/**
|
||||
* WB is a smart pointer write barrier meant to be used on any field of a GC object that
|
||||
* may point to another GC object. A write barrier may only be avoided if if the field is
|
||||
* const and no allocations occur between the construction of the object holding the field
|
||||
* and the assignment.
|
||||
*/
|
||||
template<class T> class WriteBarrier
|
||||
{
|
||||
public:
|
||||
WriteBarrier() {}
|
||||
WriteBarrier(T t)
|
||||
{
|
||||
set(t);
|
||||
}
|
||||
|
||||
~WriteBarrier()
|
||||
{
|
||||
t = 0;
|
||||
}
|
||||
|
||||
T operator=(const WriteBarrier<T>& wb)
|
||||
{
|
||||
return set(wb.t);
|
||||
}
|
||||
|
||||
T operator=(T tNew)
|
||||
{
|
||||
return set(tNew);
|
||||
}
|
||||
|
||||
// BEHOLD ... The weird power of C++ operator overloading
|
||||
operator T() const { return t; }
|
||||
|
||||
#ifdef MMGC_DRC
|
||||
operator ZeroPtr<T>() const { return t; }
|
||||
#endif
|
||||
|
||||
bool operator!=(T other) const { return other != t; }
|
||||
|
||||
T operator->() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
private:
|
||||
|
||||
// private to prevent its use and someone adding it, GCC creates
|
||||
// WriteBarrier's on the stack with it
|
||||
WriteBarrier(const WriteBarrier<T>& toCopy) { GCAssert(false); }
|
||||
|
||||
T set(const T tNew)
|
||||
{
|
||||
if(t != tNew || tNew != 0)
|
||||
GC::WriteBarrier(this, (const void*)tNew);
|
||||
else
|
||||
t = tNew;
|
||||
return tNew;
|
||||
}
|
||||
T t;
|
||||
};
|
||||
|
||||
/**
|
||||
* WriteBarrierRC is a write barrier for naked (not pointer swizzled) RC objects.
|
||||
* the only thing going in and out of the slot is NULL or a valid RCObject
|
||||
*/
|
||||
template<class T> class WriteBarrierRC
|
||||
{
|
||||
public:
|
||||
WriteBarrierRC() {}
|
||||
WriteBarrierRC(T t)
|
||||
{
|
||||
set(t);
|
||||
}
|
||||
|
||||
~WriteBarrierRC()
|
||||
{
|
||||
if(t != 0) {
|
||||
((RCObject*)t)->DecrementRef();
|
||||
t=0;
|
||||
}
|
||||
}
|
||||
|
||||
T operator=(const WriteBarrierRC<T>& wb)
|
||||
{
|
||||
return set(wb.t);
|
||||
}
|
||||
|
||||
T operator=(T tNew)
|
||||
{
|
||||
return set(tNew);
|
||||
}
|
||||
|
||||
operator T() const { return t; }
|
||||
|
||||
#ifdef MMGC_DRC
|
||||
operator ZeroPtr<T>() const { return t; }
|
||||
#endif
|
||||
|
||||
bool operator!=(T other) const { return other != t; }
|
||||
|
||||
T operator->() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
void Clear() { t = 0; }
|
||||
private:
|
||||
|
||||
// see note for WriteBarrier
|
||||
WriteBarrierRC(const WriteBarrierRC<T>& toCopy);
|
||||
|
||||
T set(const T tNew)
|
||||
{
|
||||
GC *gc = GC::GetGC(this);
|
||||
gc->writeBarrierRC(gc->FindBeginning(this), this, (const void*)tNew);
|
||||
return tNew;
|
||||
}
|
||||
T t;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // _WRITE_BARRIER_H_
|
||||
@@ -1,79 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Critical section on GCHeap allocations.
|
||||
*/
|
||||
//#define GCHEAP_LOCK
|
||||
|
||||
/**
|
||||
* Define this to get stack traces. Helps with memory leaks.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define MEMORY_INFO
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This turns on incremental collection as well as all of
|
||||
* the write barriers.
|
||||
*/
|
||||
// TODO_LINUX
|
||||
//#define WRITE_BARRIERS
|
||||
|
||||
/**
|
||||
* Define this if MMgc is being integrated with avmplus.
|
||||
* Activates dynamic profiling support, etc.
|
||||
*/
|
||||
#define MMGC_AVMPLUS
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define DECOMMIT_MEMORY
|
||||
|
||||
/**
|
||||
* USE_MMAP not used for ARM skunkworks
|
||||
*/
|
||||
//#define USE_MMAP
|
||||
|
||||
/**
|
||||
* Controls whether DRC is in use
|
||||
*/
|
||||
|
||||
//#define MMGC_DRC
|
||||
@@ -1,87 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Critical section on GCHeap allocations.
|
||||
*/
|
||||
#define GCHEAP_LOCK
|
||||
|
||||
/**
|
||||
* IA-32
|
||||
*/
|
||||
#define MMGC_IA32
|
||||
|
||||
/**
|
||||
* Define this to get stack traces. Helps with memory leaks.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define MEMORY_INFO
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This turns on incremental collection as well as all of
|
||||
* the write barriers.
|
||||
*/
|
||||
// TODO_LINUX
|
||||
#define WRITE_BARRIERS
|
||||
|
||||
/**
|
||||
* Define this if MMgc is being integrated with avmplus.
|
||||
* Activates dynamic profiling support, etc.
|
||||
*/
|
||||
#define MMGC_AVMPLUS
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define DECOMMIT_MEMORY
|
||||
|
||||
/**
|
||||
* USE_MMAP only for MACHO builds
|
||||
*/
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
#ifndef USE_MMAP
|
||||
#define USE_MMAP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Controls whether DRC is in use
|
||||
*/
|
||||
|
||||
#define MMGC_DRC
|
||||
@@ -1,95 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
#ifndef _DEBUG
|
||||
#define _DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Critical section on GCHeap allocations.
|
||||
*/
|
||||
#define GCHEAP_LOCK
|
||||
|
||||
/**
|
||||
* PowerPC (MacOS)
|
||||
*/
|
||||
#ifdef __i386__
|
||||
#define MMGC_IA32
|
||||
#else
|
||||
#define MMGC_PPC
|
||||
#endif
|
||||
|
||||
#define MMGC_MAC
|
||||
|
||||
/**
|
||||
* Define this to get stack traces. Helps with memory leaks.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
#define MEMORY_INFO
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This turns on incremental collection as well as all of
|
||||
* the write barriers.
|
||||
*/
|
||||
#define WRITE_BARRIERS
|
||||
|
||||
/**
|
||||
* Define this if MMgc is being integrated with avmplus.
|
||||
* Activates dynamic profiling support, etc.
|
||||
*/
|
||||
#define MMGC_AVMPLUS
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#define DECOMMIT_MEMORY
|
||||
|
||||
/**
|
||||
* USE_MMAP only for MACHO builds
|
||||
*/
|
||||
#if TARGET_RT_MAC_MACHO
|
||||
#ifndef USE_MMAP
|
||||
#define USE_MMAP
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MMGC_DRC
|
||||
|
||||
/**
|
||||
* This makes JIT code buffers read-only to reduce the probability of
|
||||
* heap overflow attacks.
|
||||
*/
|
||||
#define AVMPLUS_JIT_READONLY
|
||||
@@ -1,95 +0,0 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
# "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
# WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
# language governing rights and limitations under the License.
|
||||
#
|
||||
# The Original Code is [Open Source Virtual Machine.]
|
||||
#
|
||||
# The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
# by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
# Reserved.
|
||||
#
|
||||
# Contributor(s): Adobe AS3 Team
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
# General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
# License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
# LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
# file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
# version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
# above and replace them with the notice and other provisions required by the GPL or the
|
||||
# LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
# under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
MMGC_DEBUG_CFLAGS := -g -MMD
|
||||
MMGC_RELEASE_CFLAGS := -O3 -MMD
|
||||
|
||||
MMGC_DEBUG_CXXFLAGS := ${MMGC_DEBUG_CFLAGS} -fno-rtti -fcheck-new
|
||||
MMGC_RELEASE_CXXFLAGS := ${MMGC_RELEASE_CFLAGS} -fno-rtti -fcheck-new
|
||||
|
||||
ifeq (YES, ${DEBUG})
|
||||
MMGC_CFLAGS := ${MMGC_DEBUG_CFLAGS}
|
||||
MMGC_CXXFLAGS := ${MMGC_DEBUG_CXXFLAGS}
|
||||
else
|
||||
MMGC_CFLAGS := ${MMGC_RELEASE_CFLAGS}
|
||||
MMGC_CXXFLAGS := ${MMGC_RELEASE_CXXFLAGS}
|
||||
endif
|
||||
|
||||
#************************************************************************
|
||||
# DEFS
|
||||
#************************************************************************
|
||||
|
||||
MMGC_DEFS := ${MMGC_DEFS} -DAVMPLUS_LINUX -DSOFT_ASSERTS -DDEBUGGER -DAVMPLUS_IA32 -DDEBUG -DCYGWIN -DUSE_MMAP -DENABLE_PROFILER -DENABLE_COMPILER
|
||||
|
||||
#************************************************************************
|
||||
# Include Paths
|
||||
#************************************************************************
|
||||
|
||||
MMGC_INCS := -I${MMGC_ROOT} -I${MMGC_ROOT}/../core -I${MMGC_ROOT}/../codegen
|
||||
|
||||
#****************************************************************************
|
||||
# Preprocessor directives
|
||||
#****************************************************************************
|
||||
|
||||
MMGC_DEFS := ${MMGC_DEFS} -DUNIX ${MMGC_PLATFORM_DEFS} -DUSE_MMAP -DENABLE_PROFILER
|
||||
MMGC_CFLAGS := ${MMGC_CFLAGS} ${MMGC_DEFS}
|
||||
MMGC_CXXFLAGS := ${MMGC_CXXFLAGS} ${MMGC_DEFS}
|
||||
|
||||
#************************************************************************
|
||||
# MMgc common files
|
||||
#************************************************************************
|
||||
|
||||
MMGC_SRCS := ${MMGC_ROOT}/GCObject.cpp \
|
||||
${MMGC_ROOT}/GCMemoryProfiler.cpp \
|
||||
${MMGC_ROOT}/GCLargeAlloc.cpp \
|
||||
${MMGC_ROOT}/GCHeapUnix.cpp \
|
||||
${MMGC_ROOT}/GCHeap.cpp \
|
||||
${MMGC_ROOT}/GCHashtable.cpp \
|
||||
${MMGC_ROOT}/GCDebugUnix.cpp \
|
||||
${MMGC_ROOT}/GCAllocObjectUnix.cpp \
|
||||
${MMGC_ROOT}/GCAllocBase.cpp \
|
||||
${MMGC_ROOT}/GCAlloc.cpp \
|
||||
${MMGC_ROOT}/GC.cpp \
|
||||
${MMGC_ROOT}/GCTests.cpp \
|
||||
${MMGC_ROOT}/FixedMalloc.cpp \
|
||||
${MMGC_ROOT}/FixedAlloc.cpp
|
||||
|
||||
#************************************************************************
|
||||
# MMgc rules
|
||||
#************************************************************************
|
||||
|
||||
define mmgc-cmd
|
||||
@echo "=== compiling MMgc: ===" $@ ${OPT}
|
||||
@${CXX} -c ${OPT} ${MMGC_CXXFLAGS} ${MMGC_INCS} $< -o $@
|
||||
endef
|
||||
|
||||
${MMGC_ROOT}/%.o : ${MMGC_ROOT}/%.cpp
|
||||
$(mmgc-cmd)
|
||||
@@ -1,67 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "MMgc.h"
|
||||
|
||||
using namespace MMgc;
|
||||
using namespace avmplus;
|
||||
|
||||
int main(int argc, char*argv[])
|
||||
{
|
||||
GCHeap::Init();
|
||||
GC *gc = new GC(GCHeap::GetGCHeap());
|
||||
int buffer[1024];
|
||||
|
||||
List<void*> allocations(gc, 1024*16, false);
|
||||
|
||||
FILE *file = fopen("alloc.log", "rb");
|
||||
int read = 0;
|
||||
|
||||
while((read = fread(buffer, 4, 1024, file)) > 0)
|
||||
{
|
||||
for(int i=0; i < read; i++) {
|
||||
int allocSize = buffer[i];
|
||||
|
||||
// positive # is alloc, negative is index of alloc to free
|
||||
if(allocSize > 0)
|
||||
allocations.add(gc->Alloc(allocSize&~7, allocSize&6));
|
||||
else {
|
||||
int index = -allocSize;
|
||||
void *obj = allocations[index];
|
||||
allocations.set(index, 0);
|
||||
//gc->Free(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "run_alloc", "run_alloc.vcproj", "{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B} = {B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8} = {437E43D2-ED2D-406B-88DB-B5940F838AE8}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMgc", "..\MMgc.vcproj", "{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avmplus", "..\..\platform\win32\avmplus.vcproj", "{437E43D2-ED2D-406B-88DB-B5940F838AE8}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfiguration) = preSolution
|
||||
Debug = Debug
|
||||
Debug Debugger = Debug Debugger
|
||||
Release = Release
|
||||
Release Debugger = Release Debugger
|
||||
VTune = VTune
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfiguration) = postSolution
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Debug.ActiveCfg = Debug|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Debug.Build.0 = Debug|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Debug Debugger.ActiveCfg = Debug|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Debug Debugger.Build.0 = Debug|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Release.ActiveCfg = Release|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Release.Build.0 = Release|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Release Debugger.ActiveCfg = Release|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.Release Debugger.Build.0 = Release|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.VTune.ActiveCfg = VTune|Win32
|
||||
{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}.VTune.Build.0 = VTune|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug.ActiveCfg = Debug|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug.Build.0 = Debug|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug Debugger.ActiveCfg = Debug Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Debug Debugger.Build.0 = Debug Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release.ActiveCfg = Release|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release.Build.0 = Release|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release Debugger.ActiveCfg = Release Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.Release Debugger.Build.0 = Release Debugger|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.VTune.ActiveCfg = VTune|Win32
|
||||
{B004A8CC-B3A9-4600-A1A9-EF1BBCF2434B}.VTune.Build.0 = VTune|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Debug.ActiveCfg = Debug|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Debug.Build.0 = Debug|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Debug Debugger.ActiveCfg = Debug Debugger|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Debug Debugger.Build.0 = Debug Debugger|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Release.ActiveCfg = Release|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Release.Build.0 = Release|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Release Debugger.ActiveCfg = Release Debugger|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.Release Debugger.Build.0 = Release Debugger|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.VTune.ActiveCfg = VTune|Win32
|
||||
{437E43D2-ED2D-406B-88DB-B5940F838AE8}.VTune.Build.0 = VTune|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,188 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="run_alloc"
|
||||
ProjectGUID="{AE14C92F-2B7C-4B33-9B2C-425A4152A0A7}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..;..\..\core;..\..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;_DEBUG;_CONSOLE;AVMPLUS_IA32"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib DbgHelp.lib"
|
||||
OutputFile="$(OutDir)/run_alloc.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/run_alloc.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..;..\..\core;..\..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;NDEBUG;_CONSOLE;AVMPLUS_IA32"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="0"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib"
|
||||
OutputFile="$(OutDir)/run_alloc.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="VTune|Win32"
|
||||
OutputDirectory="$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
FavorSizeOrSpeed="2"
|
||||
AdditionalIncludeDirectories="..;..\..\core;..\..\codegen"
|
||||
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;WIN32;NDEBUG;_CONSOLE;AVMPLUS_IA32"
|
||||
RuntimeLibrary="4"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="winmm.lib"
|
||||
OutputFile="$(OutDir)/run_alloc.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath=".\run_alloc.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\vtune\run_alloc.vpj">
|
||||
</File>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@@ -1,113 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Critical section on GCHeap allocations.
|
||||
*/
|
||||
#define GCHEAP_LOCK
|
||||
|
||||
/**
|
||||
* IA32 (Intel architecture)
|
||||
*/
|
||||
#define MMGC_IA32
|
||||
|
||||
/**
|
||||
* Define this to get stack traces. Helps with memory leaks.
|
||||
*/
|
||||
#ifdef _DEBUG
|
||||
#define MEMORY_INFO
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This turns on incremental collection as well as all of
|
||||
* the write barriers.
|
||||
*/
|
||||
#define WRITE_BARRIERS
|
||||
|
||||
/**
|
||||
* Define this if MMgc is being integrated with avmplus.
|
||||
* Activates dynamic profiling support, etc.
|
||||
*/
|
||||
#define MMGC_AVMPLUS
|
||||
|
||||
/**
|
||||
* Use VirtualAlloc to reserve/commit memory
|
||||
*/
|
||||
#define USE_MMAP
|
||||
|
||||
/**
|
||||
* Define this to track GC pause times
|
||||
*/
|
||||
// uncommenting requires you to link with C runtime
|
||||
//#define GC_STATS
|
||||
|
||||
/**
|
||||
* Turn this on to decommit memory
|
||||
*/
|
||||
#define DECOMMIT_MEMORY
|
||||
|
||||
/**
|
||||
* Controls whether DRC is in use
|
||||
*/
|
||||
#define MMGC_DRC
|
||||
|
||||
/**
|
||||
* This makes JIT code buffers read-only to reduce the probability of
|
||||
* heap overflow attacks.
|
||||
*/
|
||||
#define AVMPLUS_JIT_READONLY
|
||||
|
||||
/**
|
||||
* compiled with the /W4 warning level
|
||||
* which is quite picky. Disable warnings we don't care about.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning(disable:4512) //assignment operator could not be generated
|
||||
#pragma warning(disable:4511) //can't generate copy ctor
|
||||
#pragma warning(disable:4127) //conditional expression is constant
|
||||
|
||||
// enable some that are off even in /W4 mode, but are still handy
|
||||
#pragma warning(error:4265) // 'class' : class has virtual functions, but destructor is not virtual
|
||||
#pragma warning(error:4905) // wide string literal cast to 'LPSTR'
|
||||
#pragma warning(error:4906) // string literal cast to 'LPWSTR'
|
||||
|
||||
// some that might be useful to turn on someday, but would require too much twiddly code tweaking right now
|
||||
// #pragma warning(error:4263) // 'function' : member function does not override any base class virtual member function
|
||||
// #pragma warning(error:4264) // 'virtual_function' : no override available for virtual member function from base 'class'; function is hidden
|
||||
// #pragma warning(error:4266) // 'function' : no override available for virtual member function from base 'type'; function is hidden
|
||||
// #pragma warning(error:4242) // 'identifier' : conversion from 'type1' to 'type2', possible loss of data
|
||||
// #pragma warning(error:4263) // member function does not override any base class virtual member function
|
||||
// #pragma warning(error:4296) // expression is always true (false) (Generally, an unsigned variable was used in a comparison operation with zero.)
|
||||
|
||||
#endif
|
||||
@@ -1,894 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
||||
#include "avmplus.h"
|
||||
|
||||
//hack
|
||||
#include <stdio.h>
|
||||
|
||||
namespace avmplus
|
||||
{
|
||||
#ifdef AVMPLUS_ARM
|
||||
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
const char* ArmAssembler::conditionCodes[] =
|
||||
{
|
||||
"eq",
|
||||
"ne",
|
||||
"cs",
|
||||
"cc",
|
||||
"mi",
|
||||
"pl",
|
||||
"vs",
|
||||
"vc",
|
||||
"hi",
|
||||
"ls",
|
||||
"ge",
|
||||
"lt",
|
||||
"gt",
|
||||
"le",
|
||||
"al",
|
||||
"nv"
|
||||
};
|
||||
|
||||
const char* ArmAssembler::regNames[] =
|
||||
{
|
||||
"r0",
|
||||
"r1",
|
||||
"r2",
|
||||
"r3",
|
||||
"r4",
|
||||
"r5",
|
||||
"r6",
|
||||
"r7",
|
||||
"r8",
|
||||
"r9",
|
||||
"r10",
|
||||
"fp",
|
||||
"ip",
|
||||
"sp",
|
||||
"lr",
|
||||
"pc"
|
||||
};
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
|
||||
ArmAssembler::ArmAssembler()
|
||||
{
|
||||
mip = 0;
|
||||
mipStart = 0;
|
||||
mInstructionCount = 0;
|
||||
verboseFlag = false;
|
||||
console = 0;
|
||||
conditionCode = AL;
|
||||
}
|
||||
|
||||
#define PRINT_LAST_INSTRUCTION()
|
||||
//#define PRINT_LAST_INSTRUCTION() console->format("%A\n", mip[-1])
|
||||
|
||||
void ArmAssembler::MOV(Register dst, Register src)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A mov %R, %R\n", mip, dst, src);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x01A00000 | (conditionCode<<28) | (dst<<12) | src;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::LSL(Register dst, Register src, Register rShift)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A lsl %R, %R, %R\n", mip, dst, src, rShift);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x01A00010 | (conditionCode<<28) | (dst<<12) | src | (rShift<<7);
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::LSR(Register dst, Register src, Register rShift)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A lsr %R, %R, %R\n", mip, dst, src, rShift);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x01A00030 | (conditionCode<<28) | (dst<<12) | src | (rShift<<7);
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::ASR(Register dst, Register src, Register rShift)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A asr %R, %R, %R\n", mip, dst, src, rShift);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x01A00050 | (conditionCode<<28) | (dst<<12) | src | (rShift<<7);
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::CMP(Register Rn, Register Rm)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A cmp %R, %R\n", mip, Rn, Rm);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x01400000 | (conditionCode<<28) | (Rn<<16) | Rm;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::ADD(Register dst, Register src1, Register src2)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A add %R, %R, %R\n", mip, dst, src1, src2);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x00800000 | (conditionCode<<28) | (dst<<12) | (src1<<16) | src2;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::AND(Register dst, Register src1, Register src2)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A and %R, %R, %R\n", mip, dst, src1, src2);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x00000000 | (conditionCode<<28) | (dst<<12) | (src1<<16) | src2;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::OR(Register dst, Register src1, Register src2)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A or %R, %R, %R\n", mip, dst, src1, src2);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x01800000 | (conditionCode<<28) | (dst<<12) | (src1<<16) | src2;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::XOR(Register dst, Register src1, Register src2)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A xor %R, %R, %R\n", mip, dst, src1, src2);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x00200000 | (conditionCode<<28) | (dst<<12) | (src1<<16) | src2;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::MUL(Register dst, Register src1, Register src2)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A mul %R, %R, %R\n", mip, dst, src1, src2);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x00000090 | (conditionCode<<28) | (dst<<16) | (src1<<8) | src2;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::SUB(Register dst, Register src1, Register src2)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A sub %R, %R, %R\n", mip, dst, src1, src2);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x00400000 | (conditionCode<<28) | (dst<<12) | (src1<<16) | src2;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::STMFD_bang(Register dst, int mask)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A stmfd %R!, %A\n", mip, dst, mask);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x09200000 | (conditionCode<<28) | (dst<<16) | mask;
|
||||
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::SUB_imm8(Register dst, Register src, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A sub %R, %R, %d\n", mip, dst, src, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x02400000 | (conditionCode<<28) | (src<<16) | (dst<<12) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::RSB_imm8(Register dst, Register src, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A rsb %R, %R, %d\n", mip, dst, src, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x02600000 | (conditionCode<<28) | (src<<16) | (dst<<12) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::BL(int offset24)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A bl %A\n", mip, offset24);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x0B000000 | (conditionCode<<28) | ((offset24-8)>>2)&0xFFFFFF;
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::B(int offset24)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A b %A\n", mip, offset24);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x0A000000 | (conditionCode<<28) | ((offset24-8)>>2)&0xFFFFFF;
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::LDR(Register dst, int offset, Register base)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A ldr %R, %d(%R)\n", mip, dst, offset, base);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
if (offset<0) {
|
||||
*mip++ = 0x05100000 | (conditionCode<<28) | (base<<16) | (dst<<12) | (-offset&0x7FF);
|
||||
} else {
|
||||
*mip++ = 0x05900000 | (conditionCode<<28) | (base<<16) | (dst<<12) | (offset&0x7FF);
|
||||
}
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::BIC_imm8(Register dst, Register src, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A bic %R, %R, %d\n", mip, dst, src, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x03C00000 | (conditionCode<<28) | (src<<16) | (dst<<12) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::MOV_imm8(Register dst, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A mov %R, %d\n", mip, dst, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x03A00000 | (conditionCode<<28) | (dst<<12) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
// Cheesy macro for doing IMM32. Needs work.
|
||||
void ArmAssembler::MOV_imm32(Register dst, int imm32)
|
||||
{
|
||||
// Branch to instruction after constant
|
||||
B(8);
|
||||
|
||||
// Write the constant
|
||||
*mip++ = imm32;
|
||||
|
||||
// Load the constant (-12 due to ARM pipeline's +8 bias)
|
||||
LDR(dst, -12, PC);
|
||||
}
|
||||
|
||||
void ArmAssembler::CMP_imm8(Register src, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A cmp %R, %d\n", mip, src, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x03500000 | (conditionCode<<28) | (src<<16) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::STR(Register src, int offset, Register base)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A str %R, %d(%R)\n", mip, src, offset, base);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
if (offset<0) {
|
||||
*mip++ = 0x05000000 | (conditionCode<<28) | (base<<16) | (src<<12) | (-offset&0x7FF);
|
||||
} else {
|
||||
*mip++ = 0x05800000 | (conditionCode<<28) | (base<<16) | (src<<12) | (offset&0x7FF);
|
||||
}
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::ADD_imm8(Register dst, Register src, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A add %R, %R, %d\n", mip, dst, src, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x02800000 | (conditionCode<<28) | (src<<16) | (dst<<12) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::AND_imm8(Register dst, Register src, int imm8)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A and %R, %R, %d\n", mip, dst, src, imm8);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x02000000 | (conditionCode<<28) | (src<<16) | (dst<<12) | (imm8&0xFF);
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::LDMFD(Register src, int mask)
|
||||
{
|
||||
incInstructionCount();
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format(" %A ldmfd %R, %A\n", mip, src, mask);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
*mip++ = 0x08900000 | (conditionCode<<28) | (src<<16) | mask;
|
||||
PRINT_LAST_INSTRUCTION();
|
||||
}
|
||||
|
||||
void ArmAssembler::SET_CONDITION_CODE(ConditionCode conditionCode)
|
||||
{
|
||||
this->conditionCode = conditionCode;
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (verboseFlag)
|
||||
console->format("%s:", conditionCodes[conditionCode]);
|
||||
#endif /* AVMPLUS_VERBOSE */
|
||||
}
|
||||
|
||||
#ifdef AVMPLUS_MIR
|
||||
bool CodegenMIR::canImmFold(OP *ins, OP *imm) const
|
||||
{
|
||||
bool can = false;
|
||||
return can;
|
||||
}
|
||||
|
||||
void CodegenMIR::emitNativeThunk(NativeMethod *info)
|
||||
{
|
||||
SET_CONDITION_CODE(AL);
|
||||
|
||||
// Hack to see what instructions we're generating
|
||||
//verbose = true;
|
||||
|
||||
const Register TEMP = R7;
|
||||
const Register AP = R6;
|
||||
const Register ARGC = R5;
|
||||
#ifdef DEBUGGER
|
||||
const Register ENV = R4;
|
||||
const Register SAVE0 = R5;
|
||||
const Register SAVE1 = R6;
|
||||
const int NonVolatileMask = R4_mask | R5_mask | R6_mask | R7_mask;
|
||||
const int NonVolatileCount = 4;
|
||||
#else
|
||||
const int NonVolatileMask = R5_mask | R6_mask | R7_mask;
|
||||
const int NonVolatileCount = 3;
|
||||
#endif
|
||||
|
||||
if (!pool)
|
||||
core->console << "no pool " << info << "\n";
|
||||
|
||||
code = getMDBuffer(pool);
|
||||
mip = (MDInstruction*)code;
|
||||
if (!code)
|
||||
{
|
||||
overflow = true;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef FEATURE_BUFFER_GUARD
|
||||
GrowthGuard guard(pool->codeBuffer);
|
||||
#else
|
||||
if (!ensureMDBufferCapacity(pool, md_native_thunk_size))
|
||||
return;
|
||||
#endif /* FEATURE_BUFFER_GUARD */
|
||||
|
||||
int in_arg_offset = 0;
|
||||
|
||||
const int kMaxGPRIndex = 3;
|
||||
|
||||
#ifdef DEBUGGER
|
||||
uint32 *sendEnterAddr = mip;
|
||||
*mip++ = ENVADDR(MethodEnv::sendEnter);
|
||||
|
||||
uint32 *sendExitAddr = mip;
|
||||
*mip++ = ENVADDR(MethodEnv::sendExit);
|
||||
#endif
|
||||
|
||||
union {
|
||||
int handler_addr;
|
||||
NativeMethod::Handler handler;
|
||||
};
|
||||
handler = info->m_handler;
|
||||
|
||||
uint32 *handlerAddr = mip;
|
||||
*mip++ = handler_addr;
|
||||
|
||||
// scan for double optional arguments; these will
|
||||
// be constants stored up front
|
||||
uint32 *const_ip = mip;
|
||||
int first_optional = 1+info->param_count-info->optional_count;
|
||||
for (int i=first_optional; i <= info->param_count; i++)
|
||||
{
|
||||
Traits* type = info->paramTraits(i);
|
||||
Atom arg = info->getDefaultValue(i-first_optional);
|
||||
|
||||
if (type == OBJECT_TYPE || type == VOID_TYPE)
|
||||
{
|
||||
*mip++ = arg;
|
||||
}
|
||||
else if (type == BOOLEAN_TYPE)
|
||||
{
|
||||
*mip++ = (arg>>3);
|
||||
}
|
||||
else if (type == NUMBER_TYPE)
|
||||
{
|
||||
double d = core->number_d(arg);
|
||||
int *dp = (int*)&d;
|
||||
*mip++ = dp[0];
|
||||
*mip++ = dp[1];
|
||||
}
|
||||
else if (type == INT_TYPE)
|
||||
{
|
||||
Atom arg = info->getDefaultValue(i-first_optional);
|
||||
int i = core->integer_i(arg);
|
||||
*mip++ = i;
|
||||
}
|
||||
else if (type == UINT_TYPE)
|
||||
{
|
||||
Atom arg = info->getDefaultValue(i-first_optional);
|
||||
uint32 u = core->integer_u(arg);
|
||||
*mip++ = u;
|
||||
}
|
||||
else
|
||||
{
|
||||
// push pointer type
|
||||
// this case includes kStringType, kObjectType, and kNamespaceType
|
||||
int p = (arg&7)==kSpecialType ? 0 : arg & ~7;
|
||||
*mip++ = p;
|
||||
}
|
||||
}
|
||||
|
||||
mipStart = mip;
|
||||
|
||||
// prologue
|
||||
MOV (IP, SP);
|
||||
|
||||
// save callee-saved registers
|
||||
STMFD_bang (SP, NonVolatileMask | FP_mask | IP_mask | LR_mask | PC_mask);
|
||||
SUB_imm8 (FP, IP, 4);
|
||||
|
||||
// the frame size will be updated later
|
||||
uint32 *patch_frame_size = mip;
|
||||
SUB_imm8 (SP, SP, 0);
|
||||
|
||||
// set up other registers
|
||||
MOV (AP, R2);
|
||||
MOV (ARGC, R1);
|
||||
#ifdef DEBUGGER
|
||||
MOV (ENV, R0);
|
||||
#endif
|
||||
|
||||
#ifdef DEBUGGER
|
||||
//MOV (R0, ENV);
|
||||
//MOV (R1, ARGC);
|
||||
//MOV (R2, AP);
|
||||
LDR (IP, (int)sendEnterAddr-(int)mip-8, PC);
|
||||
MOV (LR, PC);
|
||||
MOV (PC, IP);
|
||||
//thincall(ENVADDR(MethodEnv::sendEnter));
|
||||
#endif
|
||||
|
||||
// Push receiver object as first argument
|
||||
#ifdef NATIVE_GLOBAL_FUNCTION_HACK
|
||||
// hack - native toplevel functions get invoked with user defined receiver
|
||||
// but are expecting the global object. this hack is totally unsound
|
||||
// because it gives users the power to crash the vm. we need to either
|
||||
// directly support toplevel native functions, or not use them.
|
||||
LDR (R0, 0, AP); // this is ap[0]
|
||||
BIC_imm (R0, R0, 7);
|
||||
#else
|
||||
LDR (R0, 0, AP); // this is ap[0]
|
||||
#endif
|
||||
in_arg_offset += 4;
|
||||
int GPRIndex = 1;
|
||||
|
||||
bool need_rest = ((info->flags & AbstractFunction::NEED_REST) != 0);
|
||||
|
||||
if (info->flags & AbstractFunction::NATIVE_COOKIE)
|
||||
{
|
||||
MOV_imm8 (R1, info->m_cookie);
|
||||
GPRIndex++;
|
||||
}
|
||||
|
||||
// push args left to right
|
||||
for (int i=1; i <= info->param_count; i++)
|
||||
{
|
||||
// param 0 is receiver, real params start at 1
|
||||
Traits* type = info->paramTraits(i);
|
||||
|
||||
if (i >= first_optional) {
|
||||
// emit code to check whether argument
|
||||
// was specified
|
||||
CMP_imm8 (ARGC, i);
|
||||
|
||||
SET_CONDITION_CODE(LT);
|
||||
|
||||
// emit code to push the default value
|
||||
Atom arg = info->getDefaultValue(i-first_optional);
|
||||
|
||||
// the arguments have already been coerced to the right type
|
||||
// by the caller. We do not do type conversions here.
|
||||
|
||||
if (type == NUMBER_TYPE)
|
||||
{
|
||||
int offset = (int)const_ip - (int)mip;
|
||||
|
||||
// Do first word of double
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
LDR ((Register)(R0+GPRIndex), offset, PC);
|
||||
} else {
|
||||
LDR (TEMP, offset, PC);
|
||||
STR (TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
|
||||
// Do second word of double
|
||||
if ((GPRIndex+1) < kMaxGPRIndex) {
|
||||
LDR ((Register)(R0+GPRIndex+1), offset, PC);
|
||||
} else {
|
||||
LDR (TEMP, offset+4, PC);
|
||||
STR (TEMP, (GPRIndex+1-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
|
||||
const_ip += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = (int)const_ip - (int)mip;
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
LDR ((Register)(R0+GPRIndex), offset, PC);
|
||||
} else {
|
||||
LDR (TEMP, offset, PC);
|
||||
STR (TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
|
||||
const_ip++;
|
||||
}
|
||||
|
||||
SET_CONDITION_CODE(GE);
|
||||
}
|
||||
|
||||
// Generate the code for the non-optional case.
|
||||
// these args will already be converted to native form by the caller
|
||||
if (type == NUMBER_TYPE)
|
||||
{
|
||||
// Copy first word of double
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
LDR((Register)(R0+GPRIndex), in_arg_offset, AP);
|
||||
} else {
|
||||
LDR(TEMP, in_arg_offset, AP);
|
||||
STR(TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
GPRIndex++;
|
||||
in_arg_offset += 4;
|
||||
|
||||
// Copy second word of double
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
LDR((Register)(R0+GPRIndex), in_arg_offset, AP);
|
||||
} else {
|
||||
LDR(TEMP, in_arg_offset, AP);
|
||||
STR(TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
|
||||
GPRIndex++;
|
||||
in_arg_offset += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
// push general type
|
||||
// this case includes everything except Number/double
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
LDR((Register)(R0+GPRIndex), in_arg_offset, AP);
|
||||
} else {
|
||||
LDR(TEMP, in_arg_offset, AP);
|
||||
STR(TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
in_arg_offset += 4;
|
||||
GPRIndex++;
|
||||
}
|
||||
|
||||
SET_CONDITION_CODE(AL);
|
||||
}
|
||||
|
||||
if (need_rest) {
|
||||
// If the method signature ends with "...",
|
||||
// deliver any arguments after the explicitly
|
||||
// specified ones as (Atom *argv, int argc)
|
||||
|
||||
// rest_count = argc-param_count
|
||||
CMP_imm8 (ARGC, info->param_count);
|
||||
SET_CONDITION_CODE (LT);
|
||||
|
||||
// rest_count<0, push argc=0, argv=NULL
|
||||
|
||||
// push argc
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
MOV_imm8((Register)(R0+GPRIndex), 0);
|
||||
} else {
|
||||
MOV_imm8(TEMP, 0);
|
||||
STR(TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
|
||||
// push argv
|
||||
if ((GPRIndex+1) < kMaxGPRIndex) {
|
||||
MOV_imm8((Register)(R0+GPRIndex+1), 0);
|
||||
} else {
|
||||
MOV_imm8(TEMP, 0);
|
||||
STR(TEMP, (GPRIndex+1-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
|
||||
SET_CONDITION_CODE(GE);
|
||||
|
||||
// rest_count>=0
|
||||
// push rest_count
|
||||
// push rest_argv = argv+param_count
|
||||
|
||||
// push argv
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
ADD_imm8((Register)(R0+GPRIndex), AP, info->restOffset);
|
||||
} else {
|
||||
ADD_imm8(TEMP, AP, info->restOffset);
|
||||
STR(TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
GPRIndex++;
|
||||
|
||||
// push argc
|
||||
if (GPRIndex < kMaxGPRIndex) {
|
||||
SUB_imm8((Register)(R0+GPRIndex), ARGC, info->param_count);
|
||||
} else {
|
||||
SUB_imm8(TEMP, ARGC, info->param_count);
|
||||
STR(TEMP, (GPRIndex-kMaxGPRIndex)*4, SP);
|
||||
}
|
||||
GPRIndex++;
|
||||
|
||||
SET_CONDITION_CODE(AL);
|
||||
}
|
||||
|
||||
// all args have been pushed, now call function using thiscall calling conventions
|
||||
Traits* type = info->returnTraits();
|
||||
|
||||
LDR (IP, (int)handlerAddr-(int)mip-8, PC);
|
||||
MOV (LR, PC);
|
||||
MOV (PC, IP);
|
||||
//thincall(handler_addr);
|
||||
|
||||
#ifdef DEBUGGER
|
||||
if (type == NUMBER_TYPE)
|
||||
{
|
||||
// result is in R0, R1. Store in nonvolatile while
|
||||
// we call sendExit.
|
||||
MOV (SAVE0, R0);
|
||||
MOV (SAVE1, R1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// result is in R0. Store in nonvolatile while we
|
||||
// call sendExit.
|
||||
MOV (SAVE0, R0);
|
||||
}
|
||||
|
||||
MOV (R0, ENV);
|
||||
LDR (IP, (int)sendExitAddr-(int)mip-8, PC);
|
||||
MOV (LR, PC);
|
||||
MOV (PC, IP);
|
||||
//thincall(ENVADDR(MethodEnv::sendExit));
|
||||
|
||||
if (type == NUMBER_TYPE)
|
||||
{
|
||||
MOV (R0, SAVE0);
|
||||
MOV (R1, SAVE1);
|
||||
}
|
||||
else
|
||||
{
|
||||
MOV (R0, SAVE0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (type != NUMBER_TYPE)
|
||||
{
|
||||
// result in R3
|
||||
if (type == BOOLEAN_TYPE)
|
||||
{
|
||||
// return value already in R3
|
||||
// bool is just a byte, so mask it off
|
||||
AND_imm8 (R0, R0, 255);
|
||||
}
|
||||
else if (type == VOID_TYPE)
|
||||
{
|
||||
MOV_imm8 (R0, undefinedAtom);
|
||||
}
|
||||
}
|
||||
// else, result in FPU register F1
|
||||
|
||||
// epilogue
|
||||
SUB_imm8 (SP, FP, 12 + NonVolatileCount * 4);
|
||||
LDMFD (SP, NonVolatileMask | FP_mask | SP_mask | PC_mask);
|
||||
|
||||
// Patch up the frame size.
|
||||
// For each arg, we need 4 bytes in the called parameter
|
||||
// area. We also leave a little cushion in the called
|
||||
// parameter area, since there are a few other function
|
||||
// calls the thunk makes (intToAtom, doubleToAtom)
|
||||
if (GPRIndex > kMaxGPRIndex)
|
||||
{
|
||||
int frameSize = (GPRIndex-kMaxGPRIndex)*4;
|
||||
*patch_frame_size |= (frameSize & 0xFF);
|
||||
}
|
||||
|
||||
bindMethod(info);
|
||||
}
|
||||
|
||||
void* CodegenMIR::emitImtThunk(ImtBuilder::ImtEntry *e)
|
||||
{
|
||||
SET_CONDITION_CODE(AL);
|
||||
|
||||
mip = mipStart = (MDInstruction*)getMDBuffer(pool);
|
||||
|
||||
#ifdef FEATURE_BUFFER_GUARD
|
||||
GrowthGuard guard(pool->codeBuffer);
|
||||
#else
|
||||
if (!ensureMDBufferCapacity(pool, md_native_thunk_size))
|
||||
return NULL;
|
||||
#endif /* FEATURE_BUFFER_GUARD */
|
||||
|
||||
// the generated thunk does not call any helper methods, so we are
|
||||
// free to use eax, ecx, edx as scratch regs without touchning the
|
||||
// stack.
|
||||
|
||||
// in: R3 = iid
|
||||
// R0 = MethodEnv
|
||||
// R1 = argc
|
||||
// R2 = ap
|
||||
// 0(ap) = ScriptObject (concrete instance of class)
|
||||
|
||||
// local register allocation:
|
||||
// R4 = iid parameter
|
||||
// R5 = vtable of receiver obj
|
||||
// R6 = temp
|
||||
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (pool->verbose)
|
||||
{
|
||||
core->console << "imt thunk\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
LDR (IP, 0, R2); // obj
|
||||
LDR (IP, offsetof(ScriptObject, vtable), IP); // vtable
|
||||
|
||||
AvmAssert(e->next != NULL); // must have 2 or more entries
|
||||
|
||||
while (e->next)
|
||||
{
|
||||
ImtBuilder::ImtEntry *next = e->next;
|
||||
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (pool->verbose)
|
||||
{
|
||||
core->console << " disp_id="<< e->disp_id << " " << e->virt << "\n";
|
||||
}
|
||||
#endif
|
||||
int iid = e->virt->iid();
|
||||
|
||||
CMP_imm8 (R3, iid);
|
||||
|
||||
#if 0
|
||||
// todo
|
||||
if (isUIMM(iid))
|
||||
{
|
||||
CMP (R3, iid);
|
||||
}
|
||||
else
|
||||
{
|
||||
//LI32(R0, iid);
|
||||
//CMP (R3, R0);
|
||||
}
|
||||
#endif
|
||||
|
||||
SET_CONDITION_CODE(EQ);
|
||||
LDR (IP, offsetof(VTable,methods)+4*e->disp_id, IP); // load concrete env
|
||||
LDR (IP, offsetof(MethodEnv, impl32), IP); // invoke real method indirectly
|
||||
MOV (PC, IP);
|
||||
SET_CONDITION_CODE(AL);
|
||||
|
||||
pool->core->gc->Free(e);
|
||||
e = next;
|
||||
}
|
||||
|
||||
// last one is unconditional
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
if (pool->verbose)
|
||||
{
|
||||
core->console << " disp_id="<< e->disp_id << " " << e->virt << "\n";
|
||||
}
|
||||
#endif
|
||||
LDR (IP, offsetof(VTable,methods)+4*e->disp_id, IP); // load concrete env
|
||||
LDR (IP, offsetof(MethodEnv, impl32), IP); // invoke real method indirectly
|
||||
MOV (PC, IP);
|
||||
|
||||
MDInstruction *retval;
|
||||
|
||||
retval = mipStart;
|
||||
|
||||
// lock in the next available location in the buffer (16B aligned)
|
||||
pool->codeBuffer->setPos((byte*) ( (size_t)mip+15 & ~15 ));
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* AVMPLUS_MIR */
|
||||
|
||||
#endif /* AVMPLUS_ARM */
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __avmplus_ArmAssembler__
|
||||
#define __avmplus_ArmAssembler__
|
||||
|
||||
|
||||
namespace avmplus
|
||||
{
|
||||
class ArmAssembler
|
||||
{
|
||||
public:
|
||||
/* ARM registers */
|
||||
typedef enum
|
||||
{
|
||||
R0 = 0,
|
||||
R1 = 1,
|
||||
R2 = 2,
|
||||
R3 = 3,
|
||||
R4 = 4,
|
||||
R5 = 5,
|
||||
R6 = 6,
|
||||
R7 = 7,
|
||||
R8 = 8,
|
||||
R9 = 9,
|
||||
R10 = 10,
|
||||
FP = 11,
|
||||
IP = 12,
|
||||
SP = 13,
|
||||
LR = 14,
|
||||
PC = 15,
|
||||
|
||||
// Pseudo-register for floating point
|
||||
F0 = 0,
|
||||
|
||||
Unknown = -1
|
||||
}
|
||||
Register;
|
||||
|
||||
/* ARM registers */
|
||||
typedef enum
|
||||
{
|
||||
R0_mask = (1<<0),
|
||||
R1_mask = (1<<1),
|
||||
R2_mask = (1<<2),
|
||||
R3_mask = (1<<3),
|
||||
R4_mask = (1<<4),
|
||||
R5_mask = (1<<5),
|
||||
R6_mask = (1<<6),
|
||||
R7_mask = (1<<7),
|
||||
R8_mask = (1<<8),
|
||||
R9_mask = (1<<9),
|
||||
R10_mask = (1<<10),
|
||||
FP_mask = (1<<11),
|
||||
IP_mask = (1<<12),
|
||||
SP_mask = (1<<13),
|
||||
LR_mask = (1<<14),
|
||||
PC_mask = (1<<15)
|
||||
}
|
||||
RegisterMask;
|
||||
|
||||
/* ARM condition codes */
|
||||
typedef enum
|
||||
{
|
||||
EQ = 0x0, // Equal
|
||||
NE = 0x1, // Not Equal
|
||||
CS = 0x2, // Carry Set (or HS)
|
||||
CC = 0x3, // Carry Clear (or LO)
|
||||
MI = 0x4, // MInus
|
||||
PL = 0x5, // PLus
|
||||
VS = 0x6, // oVerflow Set
|
||||
VC = 0x7, // oVerflow Clear
|
||||
HI = 0x8, // HIgher
|
||||
LS = 0x9, // Lower or Same
|
||||
GE = 0xA, // Greater or Equal
|
||||
LT = 0xB, // Less Than
|
||||
GT = 0xC, // Greater Than
|
||||
LE = 0xD, // Less or Equal
|
||||
AL = 0xE, // ALways
|
||||
NV = 0xF // NeVer
|
||||
}
|
||||
ConditionCode;
|
||||
|
||||
/* --- Data Processing Instructions --- */
|
||||
|
||||
/* Values for operator "a" */
|
||||
typedef enum
|
||||
{
|
||||
AND_op = 0x0, // Boolean And Rd = Rn AND Op2
|
||||
EOR_op = 0x1, // Boolean Eor Rd = Rn EOR Op2
|
||||
SUB_op = 0x2, // Subtract Rd = Rn - Op2
|
||||
RSB_op = 0x3, // Reverse Subtract Rd = Op2 - Rn
|
||||
ADD_op = 0x4, // Addition Rd = Rn + Op2
|
||||
ADC_op = 0x5, // Add with Carry Rd = Rn + Op2 + C
|
||||
SBC_op = 0x6, // Subtract with Carry Rd = Rn - Op2 - (1-C)
|
||||
RSC_op = 0x7, // Reverse Subtract with Carry Rd - Op2 - Rn - (1-C)
|
||||
TST_op = 0x8, // Test bit Rn AND Op2
|
||||
TEQ_op = 0x9, // Test equality Rn EOR Op2
|
||||
CMP_op = 0xA, // Compare Rn - Op2
|
||||
CMN_op = 0xB, // Compare Negative Rn + Op2
|
||||
ORR_op = 0xC, // Boolean Or Rd = Rn OR Op2
|
||||
MOV_op = 0xD, // Move value Rd = Op2
|
||||
BIC_op = 0xE, // Bit Clear Rd = Rn AND NOT Op2
|
||||
MVN_op = 0xF // Move Not Rd = NOT Op2
|
||||
}
|
||||
Operator;
|
||||
|
||||
/* Values for operand "t" */
|
||||
typedef enum
|
||||
{
|
||||
LSL_imm = 0, // LSL #c - Logical Shift Left
|
||||
LSL_reg = 1, // LSL Rc - Logical Shift Left
|
||||
LSR_imm = 2, // LSR #c - Logical Shift Right
|
||||
LSR_reg = 3, // LSR Rc - Logical Shift Right
|
||||
ASR_imm = 4, // ASR #c - Arithmetic Shift Right
|
||||
ASR_reg = 5, // ASR Rc - Arithmetic Shift Right
|
||||
ROR_imm = 6, // Rotate Right (c != 0)
|
||||
RRX = 6, // Rotate Right one bit with extend (c == 0)
|
||||
ROR_reg = 7 // Rotate Right
|
||||
}
|
||||
ShiftOperator;
|
||||
|
||||
typedef uint32 MDInstruction;
|
||||
|
||||
/* Instruction pointer */
|
||||
MDInstruction *mip;
|
||||
MDInstruction *mipStart;
|
||||
|
||||
int mInstructionCount; // number of machine instructions
|
||||
#define incInstructionCount() mInstructionCount++
|
||||
|
||||
/* Current condition code */
|
||||
ConditionCode conditionCode;
|
||||
|
||||
ArmAssembler();
|
||||
|
||||
void SET_CONDITION_CODE(ConditionCode conditionCode);
|
||||
|
||||
void MOV(Register dst, Register src);
|
||||
void STMFD_bang(Register dst, int mask);
|
||||
void SUB_imm8(Register dst, Register src, int imm8);
|
||||
void RSB_imm8(Register dst, Register src, int imm8);
|
||||
void B(int offset24);
|
||||
void BL(int offset24);
|
||||
void LDR(Register dst, int offset, Register base);
|
||||
void BIC_imm8(Register dst, Register src, int imm8);
|
||||
void MOV_imm8(Register dst, int imm8);
|
||||
void CMP_imm8(Register src, int imm8);
|
||||
void ADD(Register dst, Register src1, Register src2);
|
||||
void SUB(Register dst, Register src1, Register src2);
|
||||
void AND(Register dst, Register src1, Register src2);
|
||||
void OR(Register dst, Register src1, Register src2);
|
||||
void XOR(Register dst, Register src1, Register src2);
|
||||
void MUL(Register dst, Register src1, Register src2);
|
||||
void CMP(Register Rn, Register Rm);
|
||||
void LSL(Register dst, Register src, Register rShift);
|
||||
void LSR(Register dst, Register src, Register rShift);
|
||||
void ASR(Register dst, Register src, Register rShift);
|
||||
void STR(Register src, int offset, Register base);
|
||||
void ADD_imm8(Register dst, Register src, int imm8);
|
||||
void AND_imm8(Register dst, Register src, int imm8);
|
||||
void LDMFD(Register src, int mask);
|
||||
|
||||
// Cheeseball way of doing imm32.
|
||||
void MOV_imm32(Register dst, int imm32);
|
||||
|
||||
// Set if verbose output desired
|
||||
#ifdef AVMPLUS_VERBOSE
|
||||
bool verboseFlag;
|
||||
#endif
|
||||
PrintWriter *console;
|
||||
|
||||
static const char* regNames[];
|
||||
#define gpregNames regNames
|
||||
static const char* conditionCodes[];
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* __avmplus_ArmAssembler__ */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
||||
* "License"); you may not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is [Open Source Virtual Machine.]
|
||||
*
|
||||
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
||||
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
|
||||
* Reserved.
|
||||
*
|
||||
* Contributor(s): Adobe AS3 Team
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
||||
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
||||
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
||||
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
||||
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
||||
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
||||
* above and replace them with the notice and other provisions required by the GPL or the
|
||||
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
||||
* under the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "avmplus.h"
|
||||
namespace avmplus
|
||||
{
|
||||
namespace NativeID {
|
||||
#include "builtin.cpp"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user