Compare commits

..

2 Commits

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


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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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);
}
}

View File

@@ -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__ */

View File

@@ -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];
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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__ */

View File

@@ -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
}

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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__ */

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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__ */

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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;
}
}

View File

@@ -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__ */

View File

@@ -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

View File

@@ -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__

View File

@@ -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
}

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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();
}
}

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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_

View File

@@ -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"

View File

@@ -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.

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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_

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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);
}

View 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

View File

@@ -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>

View File

@@ -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

View File

@@ -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 */
}

View File

@@ -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

View File

@@ -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