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
280 changed files with 5324 additions and 96529 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,214 +0,0 @@
#! gmake
# The contents of this file are subject to the Netscape 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/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Rhino code, released
# May 6, 1998.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
# Makefile for javascript in java.
#
# This makefile is intended for packaging releases, and probably isn't
# suitable for production use - it doesn't attempt to do understand
# java dependencies beyond the package level.
#
# The makefiles for the subdirectories included in this package are
# intended to be called by this makefile with the proper CLASSDIR,
# PATH_PREFIX etc. variables. Makefiles in subdirectories are
# actually executed in the toplevel directory, with the PATH_PREFIX
# variable set to the subdirectory where the makefile is located.
#
# Initial version courtesy Mike Ang.
# Next version by Mike McCabe
# Don't include SHELL define (per GNU manual recommendation) because it
# breaks WinNT (with GNU make) builds.
# SHELL = /bin/sh
# Some things we might want to tweek.
CLASSDIR = classes
PACKAGE_NAME = org.mozilla.javascript
PACKAGE_PATH = org/mozilla/javascript
# jar filenames and the directories that build them.
JS_JAR = js.jar
JS_DIR = $(PACKAGE_PATH)
JSTOOLS_JAR = jstools.jar
JSTOOLS_DIR = $(PACKAGE_PATH)/tools
JARS = $(JS_JAR) $(JSTOOLS_JAR)
# It's not polite to store toplevel files in a tarball or zip files.
# What is the name of the toplevel directory to store files in?
# XXX we should probably add versioning to this.
DIST_DIR = jsjava
# XXX test this with sj
JAVAC = javac
# We don't define JFLAGS but we do export it to child
# builds in case it's defined by the environment.
# To build optimized (with javac) say 'make JFLAGS=-O'
GZIP = gzip
ZIP = zip
UNZIP = unzip
# Shouldn't need to change anything below here.
# For Windows NT builds (under GNU make).
ifeq ($(OS_TARGET), WINNT)
CLASSPATHSEP = '\\;'
else
CLASSPATHSEP = :
endif
# Make compatibility - use these instead of gmake 'export VARIABLE'
EXPORTS = CLASSDIR=$(CLASSDIR) JAVAC=$(JAVAC) JFLAGS=$(JFLAGS) SHELL=$(SHELL) \
PACKAGE_PATH=$(PACKAGE_PATH) PACKAGE_NAME=$(PACKAGE_NAME)
helpmessage : FORCE
@echo 'Targets include:'
@echo ' all - make jars, examples'
@echo ' jars - make js.jar, jstools.jar'
@echo ' fast - quick-and-dirty "make jars", for development'
@echo ' examples - build the .class files in the examples directory'
@echo ' check - perform checks on the source.'
@echo ' clean - remove intermediate files'
@echo ' clobber - make clean, and remove .jar files'
@echo ' zip - make a distribution .zip file'
@echo ' zip-source - make a distribution .zip file, with source'
@echo ' tar - make a distribution .tar.gz file'
@echo ' tar-source - make a distribution .tar.gz, with source'
@echo
@echo 'Define OS_TARGET to "WINNT" to build on Windows NT with GNU make.'
@echo
all : jars examples
jars : $(JARS)
fast : fast_$(JS_JAR) $(JSTOOLS_JAR)
# Always call the sub-Makefile - which may decide that the jar is up to date.
$(JS_JAR) : FORCE
$(MAKE) -f $(JS_DIR)/Makefile JAR=$(@) $(EXPORTS) \
PATH_PREFIX=$(JS_DIR) \
CLASSPATH=.
fast_$(JS_JAR) :
$(MAKE) -f $(JS_DIR)/Makefile JAR=$(JS_JAR) $(EXPORTS) \
PATH_PREFIX=$(JS_DIR) \
CLASSPATH=. \
fast
$(JSTOOLS_JAR) : $(JS_JAR) FORCE
$(MAKE) -f $(JSTOOLS_DIR)/Makefile JAR=$(@) $(EXPORTS) \
PATH_PREFIX=$(JSTOOLS_DIR) \
CLASSPATH=./$(JS_JAR)$(CLASSPATHSEP).
examples : $(JS_JAR) FORCE
$(MAKE) -f examples/Makefile $(EXPORTS) \
PATH_PREFIX=examples \
CLASSPATH=./$(JS_JAR)
# We ask the subdirs to update their MANIFESTs
MANIFEST : FORCE
$(MAKE) -f $(JS_DIR)/Makefile JAR=$(JS_JAR) $(EXPORTS) \
PATH_PREFIX=$(JS_DIR) $(JS_DIR)/MANIFEST
$(MAKE) -f $(JSTOOLS_DIR)/Makefile JAR=$(JSTOOLS_JAR) $(EXPORTS) \
PATH_PREFIX=$(JSTOOLS_DIR) $(JSTOOLS_DIR)/MANIFEST
$(MAKE) -f examples/Makefile $(EXPORTS) \
PATH_PREFIX=examples examples/MANIFEST
# so ls below always has something to work on
touch MANIFEST
# examples/Makefile doesn't get included in the
# MANIFEST file, (which is used to create the non-source distribution) so
# we include it here.
cat examples/MANIFEST $(JS_DIR)/MANIFEST \
$(JSTOOLS_DIR)/MANIFEST \
| xargs ls MANIFEST README.html \
$(JARS) \
Makefile examples/Makefile \
> $(@)
# Make a MANIFEST file containing only the binaries and documentation.
# This could be abstracted further...
MANIFEST_binonly : MANIFEST
cat examples/MANIFEST \
| xargs ls $(JARS) README.html MANIFEST > MANIFEST
# A subroutine - not intended to be called from outside the makefile.
do_zip :
# Make sure we get a fresh one
- rm -r $(DIST_DIR)
- mkdir $(DIST_DIR)
- rm $(DIST_DIR).zip
cat MANIFEST | xargs $(ZIP) -0 -q $(DIST_DIR).zip
mv $(DIST_DIR).zip $(DIST_DIR)
cd $(DIST_DIR) ; \
$(UNZIP) -q $(DIST_DIR).zip ; \
rm $(DIST_DIR).zip
$(ZIP) -r -9 -q $(DIST_DIR).zip $(DIST_DIR)
- rm -r $(DIST_DIR)
zip : check jars examples MANIFEST_binonly do_zip
zip-source : check jars examples MANIFEST do_zip
# A subroutine - not intended to be called from outside the makefile.
do_tar :
- rm -r $(DIST_DIR)
- mkdir $(DIST_DIR)
- rm $(DIST_DIR).tar $(DIST_DIR).tar.gz
cat MANIFEST | xargs tar cf $(DIST_DIR).tar
mv $(DIST_DIR).tar $(DIST_DIR)
cd $(DIST_DIR) ; \
tar xf $(DIST_DIR).tar ; \
rm $(DIST_DIR).tar
tar cf $(DIST_DIR).tar $(DIST_DIR)
- rm -r $(DIST_DIR)
$(GZIP) -9 $(DIST_DIR).tar
tar: check jars examples MANIFEST_binonly do_tar
tar-source : check jars examples MANIFEST do_tar
# These commands just get passed to the respective sub-Makefiles.
clean clobber check:
$(MAKE) -f $(JS_DIR)/Makefile $(EXPORTS) JAR=$(JS_JAR) \
PATH_PREFIX=$(JS_DIR) $(@)
$(MAKE) -f $(JSTOOLS_DIR)/Makefile $(EXPORTS) JAR=$(JSTOOLS_JAR) \
PATH_PREFIX=$(JSTOOLS_DIR) $(@)
$(MAKE) -f examples/Makefile $(EXPORTS) PATH_PREFIX=examples $(@)
#emulate .PHONY
FORCE :

View File

@@ -1,46 +0,0 @@
<html>
<!--
- The contents of this file are subject to the Netscape 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/NPL/
-
- Software distributed under the License is distributed on an "AS
- IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- implied. See the License for the specific language governing
- rights and limitations under the License.
-
- The Original Code is Rhino code, released
- May 6, 1999.
-
- The Initial Developer of the Original Code is Netscape
- Communications Corporation. Portions created by Netscape are
- Copyright (C) 1998-1999 Netscape Communications Corporation. All
- Rights Reserved.
-
- Contributor(s):
- Norris Boyd
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU Public License (the "GPL"), in which case the
- provisions of the GPL are applicable instead of those above.
- If you wish to allow use of your version of this file only
- under the terms of the GPL and not to allow others to use your
- version of this file under the NPL, indicate your decision by
- deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the NPL or the GPL.
-->
<body>
<h1>
<span CLASS=LXRSHORTDESC>
Rhino: JavaScript in Java<p>
</span>
</h1>
<span CLASS=LXRLONGDESC>
Rhino is an implementation of JavaScript in Java. Documentation can be found
<a href="http://www.mozilla.org/js/rhino/rhino.html">here</a>.
</span>
</body>
</html>

View File

@@ -1,105 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
/**
* Example of controlling the JavaScript execution engine.
*
* We evaluate a script and then manipulate the result.
*
*/
public class Control {
/**
* Main entry point.
*
* Process arguments as would a normal Java program. Also
* create a new Context and associate it with the current thread.
* Then set up the execution environment and begin to
* execute scripts.
*/
public static void main(String[] args) {
Context cx = Context.enter();
// Set version to JavaScript1.2 so that we get object-literal style
// printing instead of "[object Object]"
cx.setLanguageVersion(Context.VERSION_1_2);
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed.
Scriptable scope = cx.initStandardObjects(null);
// Now we can evaluate a script. Let's create a new object
// using the object literal notation.
Object result = null;
try {
result = cx.evaluateString(scope, "obj = {a:1, b:['x','y']}",
"MySource", 1, null);
}
catch (JavaScriptException jse) {
// ignore
}
Scriptable obj = (Scriptable) scope.get("obj", scope);
// Should print "obj == result" (Since the result of an assignment
// expression is the value that was assigned)
System.out.println("obj " + (obj == result ? "==" : "!=") +
" result");
// Should print "obj.a == 1"
System.out.println("obj.a == " + obj.get("a", obj));
Scriptable b = (Scriptable) obj.get("b", obj);
// Should print "obj.b[0] == x"
System.out.println("obj.b[0] == " + b.get(0, b));
// Should print "obj.b[1] == y"
System.out.println("obj.b[1] == " + b.get(1, b));
try {
// Should print {a:1, b:["x", "y"]}
Function fn = (Function) ScriptableObject.getProperty(obj, "toString");
System.out.println(fn.call(cx, scope, obj, new Object[0]));
} catch (JavaScriptException e) {
// ignore
}
cx.exit();
}
}

View File

@@ -1,55 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
public class Counter extends ScriptableObject {
// The zero-argument constructor used by Rhino runtime to create instances
public Counter() { }
// Method jsConstructor defines the JavaScript constructor
public void jsConstructor(int a) { count = a; }
// The class name is defined by the getClassName method
public String getClassName() { return "Counter"; }
// The method jsGet_count defines the count property.
public int jsGet_count() { return count++; }
// Methods can be defined using the jsFunction_ prefix. Here we define
// resetCount for JavaScript.
public void jsFunction_resetCount() { count = 0; }
private int count;
}

View File

@@ -1,178 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
/**
* Example of controlling the JavaScript with multiple scopes and threads.
*/
public class DynamicScopes {
/**
* Main entry point.
*
* Set up the shared scope and then spawn new threads that execute
* relative to that shared scope. Try compiling functions with and
* without dynamic scope to see the effect.
*
* The expected output is
* <pre>
* sharedScope
* sharedScope
* sharedScope
* thread0
* thread1
* thread2
* </pre>
* The final three lines may be permuted in any order depending on
* thread scheduling.
*/
public static void main(String[] args)
throws JavaScriptException
{
Context cx = Context.enter();
try {
cx.setCompileFunctionsWithDynamicScope(false);
runScripts(cx);
cx.setCompileFunctionsWithDynamicScope(true);
runScripts(cx);
} finally {
cx.exit();
}
}
static void runScripts(Context cx)
throws JavaScriptException
{
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed. The call
// returns a new scope that we will share.
Scriptable scope = cx.initStandardObjects(null);
// Now we can evaluate a script and functions will be compiled to
// use dynamic scope if the Context is so initialized.
String source = "var x = 'sharedScope';" +
"function f() { return x; }";
cx.evaluateString(scope, source, "MySource", 1, null);
// Now we spawn some threads that execute a script that calls the
// function 'f'. The scope chain looks like this:
// <pre>
// ------------------
// | shared scope |
// ------------------
// ^
// |
// ------------------
// | per-thread scope |
// ------------------
// ^
// |
// ------------------
// | f's activation |
// ------------------
// </pre>
// Both the shared scope and the per-thread scope have variables 'x'
// defined in them. If 'f' is compiled with dynamic scope enabled,
// the 'x' from the per-thread scope will be used. Otherwise, the 'x'
// from the shared scope will be used. The 'x' defined in 'g' (which
// calls 'f') should not be seen by 'f'.
final int threadCount = 3;
Thread[] t = new Thread[threadCount];
for (int i=0; i < threadCount; i++) {
String script = "function g() { var x = 'local'; return f(); }" +
"java.lang.System.out.println(g());";
t[i] = new Thread(new PerThread(scope, script,
"thread" + i));
}
for (int i=0; i < threadCount; i++)
t[i].start();
// Don't return in this thread until all the spawned threads have
// completed.
for (int i=0; i < threadCount; i++) {
try {
t[i].join();
} catch (InterruptedException e) {
}
}
}
static class PerThread implements Runnable {
PerThread(Scriptable scope, String script, String x) {
this.scope = scope;
this.script = script;
this.x = x;
}
public void run() {
// We need a new Context for this thread.
Context cx = Context.enter();
try {
// We can share the scope.
Scriptable threadScope = cx.newObject(scope);
threadScope.setPrototype(scope);
// We want "threadScope" to be a new top-level
// scope, so set its parent scope to null. This
// means that any variables created by assignments
// will be properties of "threadScope".
threadScope.setParentScope(null);
// Create a JavaScript property of the thread scope named
// 'x' and save a value for it.
threadScope.put("x", threadScope, x);
cx.evaluateString(threadScope, script, "threadScript", 1, null);
}
catch (NotAFunctionException jse) {
// ignore
}
catch (PropertyException jse) {
// ignore
}
catch (JavaScriptException jse) {
// ignore
}
finally {
Context.exit();
}
}
private Scriptable scope;
private String script;
private String x;
}
}

View File

@@ -1,356 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
import java.io.*;
import java.util.Vector;
/**
* Define a simple JavaScript File object.
*
* This isn't intended to be any sort of definitive attempt at a
* standard File object for JavaScript, but instead is an example
* of a more involved definition of a host object.
*
* Example of use of the File object:
* <pre>
* js> defineClass("File")
* js> file = new File("myfile.txt");
* [object File]
* js> file.writeLine("one"); <i>only now is file actually opened</i>
* js> file.writeLine("two");
* js> file.writeLine("thr", "ee");
* js> file.close(); <i>must close file before we can reopen for reading</i>
* js> var a = file.readLines(); <i>creates and fills an array with the contents of the file</i>
* js> a;
* one,two,three
* js>
* </pre>
*
*
* File errors or end-of-file signaled by thrown Java exceptions will
* be wrapped as JavaScript exceptions when called from JavaScript,
* and may be caught within JavaScript.
*
* @author Norris Boyd
*/
public class File extends ScriptableObject {
/**
* The zero-parameter constructor.
*
* When Context.defineClass is called with this class, it will
* construct File.prototype using this constructor.
*/
public File() {
}
/**
* The Java method defining the JavaScript File constructor.
*
* If the constructor has one or more arguments, and the
* first argument is not undefined, the argument is converted
* to a string as used as the filename.<p>
*
* Otherwise System.in or System.out is assumed as appropriate
* to the use.
*/
public static Scriptable jsConstructor(Context cx, Object[] args,
Function ctorObj,
boolean inNewExpr)
{
File result = new File();
if (args.length == 0 || args[0] == Context.getUndefinedValue()) {
result.name = "";
result.file = null;
} else {
result.name = Context.toString(args[0]);
result.file = new java.io.File(result.name);
}
return result;
}
/**
* Returns the name of this JavaScript class, "File".
*/
public String getClassName() {
return "File";
}
/**
* Get the name of the file.
*
* Used to define the "name" property.
*/
public String jsGet_name() {
return name;
}
/**
* Read the remaining lines in the file and return them in an array.
*
* Implements a JavaScript function.<p>
*
* This is a good example of creating a new array and setting
* elements in that array.
*
* @exception IOException if an error occurred while accessing the file
* associated with this object
* @exception JavaScriptException if a JavaScript exception occurred
* while creating the result array
*/
public Object jsFunction_readLines()
throws IOException, JavaScriptException
{
Vector v = new Vector();
String s;
while ((s = jsFunction_readLine()) != null) {
v.addElement(s);
}
Object[] lines = new Object[v.size()];
v.copyInto(lines);
Scriptable scope = ScriptableObject.getTopLevelScope(this);
Scriptable result;
try {
Context cx = Context.getCurrentContext();
result = cx.newObject(scope, "Array", lines);
} catch (PropertyException e) {
throw Context.reportRuntimeError(e.getMessage());
} catch (NotAFunctionException e) {
throw Context.reportRuntimeError(e.getMessage());
}
return result;
}
/**
* Read a line.
*
* Implements a JavaScript function.
* @exception IOException if an error occurred while accessing the file
* associated with this object, or EOFException if the object
* reached the end of the file
*/
public String jsFunction_readLine() throws IOException {
return getReader().readLine();
}
/**
* Read a character.
*
* @exception IOException if an error occurred while accessing the file
* associated with this object, or EOFException if the object
* reached the end of the file
*/
public String jsFunction_readChar() throws IOException {
int i = getReader().read();
if (i == -1)
return null;
char[] charArray = { (char) i };
return new String(charArray);
}
/**
* Write strings.
*
* Implements a JavaScript function. <p>
*
* This function takes a variable number of arguments, converts
* each argument to a string, and writes that string to the file.
* @exception IOException if an error occurred while accessing the file
* associated with this object
*/
public static void jsFunction_write(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws IOException
{
write0(thisObj, args, false);
}
/**
* Write strings and a newline.
*
* Implements a JavaScript function.
* @exception IOException if an error occurred while accessing the file
* associated with this object
*
*/
public static void jsFunction_writeLine(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws IOException
{
write0(thisObj, args, true);
}
public int jsGet_lineNumber()
throws FileNotFoundException
{
return getReader().getLineNumber();
}
/**
* Close the file. It may be reopened.
*
* Implements a JavaScript function.
* @exception IOException if an error occurred while accessing the file
* associated with this object
*/
public void jsFunction_close() throws IOException {
if (reader != null) {
reader.close();
reader = null;
} else if (writer != null) {
writer.close();
writer = null;
}
}
/**
* Finalizer.
*
* Close the file when this object is collected.
*/
public void finalize() {
try {
jsFunction_close();
}
catch (IOException e) {
}
}
/**
* Get the Java reader.
*/
public Object jsFunction_getReader() {
if (reader == null)
return null;
// Here we use toObject() to "wrap" the BufferedReader object
// in a Scriptable object so that it can be manipulated by
// JavaScript.
Scriptable parent = ScriptableObject.getTopLevelScope(this);
return Context.toObject(reader, parent);
}
/**
* Get the Java writer.
*
* @see File#jsFunction_getReader
*
*/
public Object jsFunction_getWriter() {
if (writer == null)
return null;
Scriptable parent = ScriptableObject.getTopLevelScope(this);
return Context.toObject(writer, parent);
}
/**
* Get the reader, checking that we're not already writing this file.
*/
private LineNumberReader getReader() throws FileNotFoundException {
if (writer != null) {
throw Context.reportRuntimeError("already writing file \""
+ name
+ "\"");
}
if (reader == null)
reader = new LineNumberReader(file == null
? new InputStreamReader(System.in)
: new FileReader(file));
return reader;
}
/**
* Perform the guts of write and writeLine.
*
* Since the two functions differ only in whether they write a
* newline character, move the code into a common subroutine.
*
*/
private static void write0(Scriptable thisObj, Object[] args, boolean eol)
throws IOException
{
File thisFile = checkInstance(thisObj);
if (thisFile.reader != null) {
throw Context.reportRuntimeError("already writing file \""
+ thisFile.name
+ "\"");
}
if (thisFile.writer == null)
thisFile.writer = new BufferedWriter(
thisFile.file == null ? new OutputStreamWriter(System.out)
: new FileWriter(thisFile.file));
for (int i=0; i < args.length; i++) {
String s = Context.toString(args[i]);
thisFile.writer.write(s, 0, s.length());
}
if (eol)
thisFile.writer.newLine();
}
/**
* Perform the instanceof check and return the downcasted File object.
*
* This is necessary since methods may reside in the File.prototype
* object and scripts can dynamically alter prototype chains. For example:
* <pre>
* js> defineClass("File");
* js> o = {};
* [object Object]
* js> o.__proto__ = File.prototype;
* [object File]
* js> o.write("hi");
* js: called on incompatible object
* </pre>
* The runtime will take care of such checks when non-static Java methods
* are defined as JavaScript functions.
*/
private static File checkInstance(Scriptable obj) {
if (obj == null || !(obj instanceof File)) {
throw Context.reportRuntimeError("called on incompatible object");
}
return (File) obj;
}
/**
* Some private data for this class.
*/
private String name;
private java.io.File file; // may be null, meaning to use System.out or .in
private LineNumberReader reader;
private BufferedWriter writer;
}

View File

@@ -1,168 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
/**
* An example host object class.
*
* Here's a shell session showing the Foo object in action:
* <pre>
* js> defineClass("Foo")
* js> foo = new Foo(); <i>A constructor call, see <a href="#Foo">Foo</a> below.</i>
* [object Foo] <i>The "Foo" here comes from <a href"#getClassName">getClassName</a>.</i>
* js> foo.counter; <i>The counter property is defined by the <code>defineProperty</code></i>
* 0 <i>call below and implemented by the <a href="#getCounter">getCounter</a></i>
* js> foo.counter; <i>method below.</i>
* 1
* js> foo.counter;
* 2
* js> foo.resetCounter(); <i>Results in a call to <a href="#resetCounter">resetCounter</a>.</i>
* js> foo.counter; <i>Now the counter has been reset.</i>
* 0
* js> foo.counter;
* 1
* js> bar = new Foo(37); <i>Create a new instance.</i>
* [object Foo]
* js> bar.counter; <i>This instance's counter is distinct from</i>
* 37 <i>the other instance's counter.</i>
* js> foo.varargs(3, "hi"); <i>Calls <a href="#varargs">varargs</a>.</i>
* this = [object Foo]; args = [3, hi]
* js> foo[7] = 34; <i>Since we extended ScriptableObject, we get</i>
* 34 <i>all the behavior of a JavaScript object</i>
* js> foo.a = 23; <i>for free.</i>
* 23
* js> foo.a + foo[7];
* 57
* js>
* </pre>
*
* @see org.mozilla.javascript.Context
* @see org.mozilla.javascript.Scriptable
* @see org.mozilla.javascript.ScriptableObject
*
* @author Norris Boyd
*/
public class Foo extends ScriptableObject {
/**
* The zero-parameter constructor.
*
* When Context.defineClass is called with this class, it will
* construct Foo.prototype using this constructor.
*/
public Foo() {
}
/**
* The Java method defining the JavaScript Foo constructor.
*
* Takes an initial value for the counter property.
* Note that in the example Shell session above, we didn't
* supply a argument to the Foo constructor. This means that
* the Undefined value is used as the value of the argument,
* and when the argument is converted to an integer, Undefined
* becomes 0.
*/
public Foo(int counterStart) {
counter = counterStart;
}
/**
* Returns the name of this JavaScript class, "Foo".
*/
public String getClassName() {
return "Foo";
}
/**
* The Java method defining the JavaScript resetCounter function.
*
* Resets the counter to 0.
*/
public void jsFunction_resetCounter() {
counter = 0;
}
/**
* The Java method implementing the getter for the counter property.
* <p>
* If "setCounter" had been defined in this class, the runtime would
* call the setter when the property is assigned to.
*/
public int jsGet_counter() {
return counter++;
}
/**
* An example of a variable-arguments method.
*
* All variable arguments methods must have the same number and
* types of parameters, and must be static. <p>
* @param cx the Context of the current thread
* @param thisObj the JavaScript 'this' value.
* @param args the array of arguments for this call
* @param funObj the function object of the invoked JavaScript function
* This value is useful to compute a scope using
* Context.getTopLevelScope().
* @return computes the string values and types of 'this' and
* of each of the supplied arguments and returns them in a string.
*
* @exception ThreadAssociationException if the current
* thread is not associated with a Context
* @see org.mozilla.javascript.ScriptableObject#getTopLevelScope
*/
public static Object jsFunction_varargs(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
StringBuffer buf = new StringBuffer();
buf.append("this = ");
buf.append(Context.toString(thisObj));
buf.append("; args = [");
for (int i=0; i < args.length; i++) {
buf.append(Context.toString(args[i]));
if (i+1 != args.length)
buf.append(", ");
}
buf.append("]");
return buf.toString();
}
/**
* A piece of private data for this class.
*/
private int counter;
}

View File

@@ -1,59 +0,0 @@
#! gmake
# The contents of this file are subject to the Netscape 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/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Rhino code, released
# May 6, 1998.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
# Makefile for the examples directory.
#
# This Makefile just calls $(JAVAC) on all the .java files. This
# Makefile is intended to be called from the toplevel Makefile.
#
JSFILES = $(PATH_PREFIX)/*.js
SOURCES = $(PATH_PREFIX)/*.java
CLASSES = $(PATH_PREFIX)/*.class
$(CLASSES) : $(SOURCES)
$(JAVAC) $(JFLAGS) $(SOURCES)
clean :
- rm $(CLASSES) $(PATH_PREFIX)/MANIFEST
clobber : clean
check :
$(PATH_PREFIX)/MANIFEST : $(SOURCES) $(CLASSES) $(JSFILES)
ls $(SOURCES) $(CLASSES) $(JSFILES) \
> $(@)
# Emulate .PHONY
FORCE :

View File

@@ -1,274 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
import java.util.Vector;
/**
* Matrix: An example host object class that implements the Scriptable interface.
*
* Built-in JavaScript arrays don't handle multiple dimensions gracefully: the
* script writer must create every array in an array of arrays. The Matrix class
* takes care of that by automatically allocating arrays for every index that
* is accessed. What's more, the Matrix constructor takes a integer argument
* that specifies the dimension of the Matrix. If m is a Matrix with dimension 3,
* then m[0] will be a Matrix with dimension 1, and m[0][0] will be an Array.
*
* Here's a shell session showing the Matrix object in action:
* <pre>
* js> defineClass("Matrix")
* js> m = new Matrix(2); <i>A constructor call, see <a href="#Matrix">Matrix</a> below.</i>
* [object Matrix] <i>The "Matrix" here comes from <a href"#getClassName">getClassName</a>.</i>
* js> version(120); <i>switch to JavaScript1.2 to see arrays better</i>
* 0
* js> m[0][0] = 3;
* 3
* js> m[0]; <i>an array was created automatically!</i>
* [3]
* js> m[1]; <i>array is created even if we don't set a value</i>
* []
* js> m.dim; <i>we can access the "dim" property</i>
* 2
* js> m.dim = 3;
* 3
* js> m.dim; <i>but not modify it</i>
* 2
* </pre>
*
* @see org.mozilla.javascript.Context
* @see org.mozilla.javascript.Scriptable
*
* @author Norris Boyd
*/
public class Matrix implements Scriptable {
/**
* The zero-parameter constructor.
*
* When Context.defineClass is called with this class, it will
* construct Matrix.prototype using this constructor.
*/
public Matrix() {
}
/**
* The Java constructor, also used to define the JavaScript constructor.
*/
public Matrix(int dimension) {
if (dimension <= 0) {
throw Context.reportRuntimeError(
"Dimension of Matrix must be greater than zero");
}
dim = dimension;
v = new Vector();
}
/**
* Returns the name of this JavaScript class, "Matrix".
*/
public String getClassName() {
return "Matrix";
}
/**
* Defines the "dim" property by returning true if name is
* equal to "dim".
* <p>
* Defines no other properties, i.e., returns false for
* all other names.
*
* @param name the name of the property
* @param start the object where lookup began
*/
public boolean has(String name, Scriptable start) {
return name.equals("dim");
}
/**
* Defines all numeric properties by returning true.
*
* @param index the index of the property
* @param start the object where lookup began
*/
public boolean has(int index, Scriptable start) {
return true;
}
/**
* Get the named property.
* <p>
* Handles the "dim" property and returns NOT_FOUND for all
* other names.
* @param name the property name
* @param start the object where the lookup began
*/
public Object get(String name, Scriptable start) {
if (name.equals("dim"))
return new Integer(dim);
return NOT_FOUND;
}
/**
* Get the indexed property.
* <p>
* Look up the element in the associated vector and return
* it if it exists. If it doesn't exist, create it.<p>
* @param index the index of the integral property
* @param start the object where the lookup began
*/
public Object get(int index, Scriptable start) {
if (index >= v.size())
v.setSize(index+1);
Object result = v.elementAt(index);
if (result != null)
return result;
if (dim > 2) {
Matrix m = new Matrix(dim-1);
m.setParentScope(getParentScope());
m.setPrototype(getPrototype());
result = m;
} else {
Context cx = Context.getCurrentContext();
Scriptable scope = ScriptableObject.getTopLevelScope(start);
result = cx.newArray(scope, 0);
}
v.setElementAt(result, index);
return result;
}
/**
* Set a named property.
*
* We do nothing here, so all properties are effectively read-only.
*/
public void put(String name, Scriptable start, Object value) {
}
/**
* Set an indexed property.
*
* We do nothing here, so all properties are effectively read-only.
*/
public void put(int index, Scriptable start, Object value) {
}
/**
* Remove a named property.
*
* This method shouldn't even be called since we define all properties
* as PERMANENT.
*/
public void delete(String id) {
}
/**
* Remove an indexed property.
*
* This method shouldn't even be called since we define all properties
* as PERMANENT.
*/
public void delete(int index) {
}
/**
* Get prototype.
*/
public Scriptable getPrototype() {
return prototype;
}
/**
* Set prototype.
*/
public void setPrototype(Scriptable prototype) {
this.prototype = prototype;
}
/**
* Get parent.
*/
public Scriptable getParentScope() {
return parent;
}
/**
* Set parent.
*/
public void setParentScope(Scriptable parent) {
this.parent = parent;
}
/**
* Get properties.
*
* We return an empty array since we define all properties to be DONTENUM.
*/
public Object[] getIds() {
return new Object[0];
}
/**
* Default value.
*
* Use the convenience method from Context that takes care of calling
* toString, etc.
*/
public Object getDefaultValue(Class typeHint) {
return "[object Matrix]";
}
/**
* instanceof operator.
*
* We mimick the normal JavaScript instanceof semantics, returning
* true if <code>this</code> appears in <code>value</code>'s prototype
* chain.
*/
public boolean hasInstance(Scriptable value) {
Scriptable proto = value.getPrototype();
while (proto != null) {
if (proto.equals(this)) return true;
}
return false;
}
/**
* Some private data for this class.
*/
private int dim;
private Vector v;
private Scriptable prototype, parent;
}

View File

@@ -1,7 +0,0 @@
<html>
<body>
This is the NervousText applet in javascript:
<applet code=NervousText.class width=200 height=50 >
</applet>
</body>
</html>

View File

@@ -1,75 +0,0 @@
// The Java "NervousText" example ported to JavaScript.
// Compile using java org.mozilla.tools.jsc.Main -extends java.applet.Applet -implements java.lang.Runnable NervousText.js
/*
Adapted from Java code by
Daniel Wyszynski
Center for Applied Large-Scale Computing (CALC)
04-12-95
Test of text animation.
kwalrath: Changed string; added thread suspension. 5-9-95
*/
var Font = java.awt.Font;
var Thread = java.lang.Thread;
var separated;
var s = null;
var killme = null;
var i;
var x_coord = 0, y_coord = 0;
var num;
var speed=35;
var counter =0;
var threadSuspended = false; //added by kwalrath
function init() {
resize(150,50);
setFont(new Font("TimesRoman",Font.BOLD,36));
s = getParameter("text");
if (s == null) {
s = "Rhino";
}
separated = s.split('');
}
function start() {
if(killme == null)
{
killme = new java.lang.Thread(java.lang.Runnable(this));
killme.start();
}
}
function stop() {
killme = null;
}
function run() {
while (killme != null) {
try {Thread.sleep(100);} catch (e){}
repaint();
}
killme = null;
}
function paint(g) {
for(i=0;i<separated.length;i++)
{
x_coord = Math.random()*10+15*i;
y_coord = Math.random()*10+36;
g.drawChars(separated, i,1,x_coord,y_coord);
}
}
/* Added by kwalrath. */
function mouseDown(evt, x, y) {
if (threadSuspended) {
killme.resume();
}
else {
killme.suspend();
}
threadSuspended = !threadSuspended;
return true;
}

View File

@@ -1,73 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
/**
* RunScript: simplest example of controlling execution of Rhino.
*
* Collects its arguments from the command line, executes the
* script, and prints the result.
*
* @author Norris Boyd
*/
public class RunScript {
public static void main(String args[])
throws JavaScriptException
{
// Creates and enters a Context. The Context stores information
// about the execution environment of a script.
Context cx = Context.enter();
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed. Returns
// a scope object that we use in later calls.
Scriptable scope = cx.initStandardObjects(null);
// Collect the arguments into a single string.
String s = "";
for (int i=0; i < args.length; i++)
s += args[i];
// Now evaluate the string we've colected.
Object result = cx.evaluateString(scope, s, "<cmd>", 1, null);
// Convert the result to a string and print it.
System.err.println(cx.toString(result));
// Exit from the context.
Context.exit();
}
}

View File

@@ -1,63 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
/**
* RunScript2: Like RunScript, but reflects the System.out into JavaScript.
*
* @author Norris Boyd
*/
public class RunScript2 {
public static void main(String args[])
throws JavaScriptException
{
Context cx = Context.enter();
Scriptable scope = cx.initStandardObjects(null);
// Add a global variable "out" that is a JavaScript reflection
// of System.out
Scriptable jsArgs = Context.toObject(System.out, scope);
scope.put("out", scope, jsArgs);
String s = "";
for (int i=0; i < args.length; i++)
s += args[i];
Object result = cx.evaluateString(scope, s, "<cmd>", 1, null);
System.err.println(cx.toString(result));
Context.exit();
}
}

View File

@@ -1,63 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
/**
* RunScript3: Execute scripts in an environment that includes the
* example Counter class.
*
* @author Norris Boyd
*/
public class RunScript3 {
public static void main(String args[])
throws Exception
{
Context cx = Context.enter();
Scriptable scope = cx.initStandardObjects(null);
// Use the Counter class to define a Counter constructor
// and prototype in JavaScript.
ScriptableObject.defineClass(scope, Counter.class);
String s = "";
for (int i=0; i < args.length; i++)
s += args[i];
Object result = cx.evaluateString(scope, s, "<cmd>", 1, null);
System.err.println(cx.toString(result));
Context.exit();
}
}

View File

@@ -1,352 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1998.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
import org.mozilla.javascript.*;
import java.io.*;
/**
* The shell program.
*
* Can execute scripts interactively or in batch mode at the command line.
* An example of controlling the JavaScript engine.
*
* @author Norris Boyd
*/
public class Shell extends ScriptableObject {
/**
* Main entry point.
*
* Process arguments as would a normal Java program. Also
* create a new Context and associate it with the current thread.
* Then set up the execution environment and begin to
* execute scripts.
*/
public static void main(String args[]) {
// Associate a new Context with this thread
Context cx = Context.enter();
// A bit of shorthand: since Shell extends ScriptableObject,
// we can make it the global object.
global = new Shell();
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed.
cx.initStandardObjects(global);
// Define some global functions particular to the shell. Note
// that these functions are not part of ECMA.
String[] names = { "print", "quit", "version", "load", "help" };
try {
global.defineFunctionProperties(names, Shell.class,
ScriptableObject.DONTENUM);
} catch (PropertyException e) {
throw new Error(e.getMessage());
}
args = processOptions(cx, args);
// Set up "arguments" in the global scope to contain the command
// line arguments after the name of the script to execute
Object[] array = args;
if (args.length > 0) {
int length = args.length - 1;
array = new Object[length];
System.arraycopy(args, 1, array, 0, length);
}
Scriptable argsObj = cx.newArray(global, array);
global.defineProperty("arguments", argsObj,
ScriptableObject.DONTENUM);
processSource(cx, args.length == 0 ? null : args[0]);
cx.exit();
}
/**
* Parse arguments.
*/
public static String[] processOptions(Context cx, String args[]) {
for (int i=0; i < args.length; i++) {
String arg = args[i];
if (!arg.startsWith("-")) {
String[] result = new String[args.length - i];
for (int j=i; j < args.length; j++)
result[j-i] = args[j];
return result;
}
if (arg.equals("-version")) {
if (++i == args.length)
usage(arg);
double d = cx.toNumber(args[i]);
if (d != d)
usage(arg);
cx.setLanguageVersion((int) d);
continue;
}
usage(arg);
}
return new String[0];
}
/**
* Return name of this class, the global object.
*
* This method must be implemented in all concrete classes
* extending ScriptableObject.
*
* @see org.mozilla.javascript.Scriptable#getClassName
*/
public String getClassName() {
return "global";
}
/**
* Print a usage message.
*/
public static void usage(String s) {
p("Didn't understand \"" + s + "\".");
p("Valid arguments are:");
p("-version 100|110|120|130");
System.exit(1);
}
/**
* Print a help message.
*
* This method is defined as a JavaScript function.
*/
public static void help(String s) {
p("");
p("Command Description");
p("======= ===========");
p("help() Display usage and help messages. ");
p("defineClass(className) Define an extension using the Java class");
p(" named with the string argument. ");
p(" Uses ScriptableObject.defineClass(). ");
p("load(['foo.js', ...]) Load JavaScript source files named by ");
p(" string arguments. ");
p("loadClass(className) Load a class named by a string argument.");
p(" The class must be a script compiled to a");
p(" class file. ");
p("print([expr ...]) Evaluate and print expressions. ");
p("quit() Quit the shell. ");
p("version([number]) Get or set the JavaScript version number.");
p("");
}
/**
* Print the string values of its arguments.
*
* This method is defined as a JavaScript function.
* Note that its arguments are of the "varargs" form, which
* allows it to handle an arbitrary number of arguments
* supplied to the JavaScript function.
*
*/
public static void print(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
for (int i=0; i < args.length; i++) {
if (i > 0)
System.out.print(" ");
// Convert the arbitrary JavaScript value into a string form.
String s = Context.toString(args[i]);
System.out.print(s);
}
System.out.println();
}
/**
* Quit the shell.
*
* This only affects the interactive mode.
*
* This method is defined as a JavaScript function.
*/
public static void quit() {
quitting = true;
}
/**
* Get and set the language version.
*
* This method is defined as a JavaScript function.
*/
public static double version(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
double result = (double) cx.getLanguageVersion();
if (args.length > 0) {
double d = cx.toNumber(args[0]);
cx.setLanguageVersion((int) d);
}
return result;
}
/**
* Load and execute a set of JavaScript source files.
*
* This method is defined as a JavaScript function.
*
*/
public static void load(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
for (int i=0; i < args.length; i++) {
processSource(cx, cx.toString(args[i]));
}
}
/**
* Evaluate JavaScript source.
*
* @param cx the current context
* @param filename the name of the file to compile, or null
* for interactive mode.
*/
public static void processSource(Context cx, String filename) {
if (filename == null) {
BufferedReader in = new BufferedReader
(new InputStreamReader(System.in));
String sourceName = "<stdin>";
int lineno = 1;
boolean hitEOF = false;
do {
int startline = lineno;
System.err.print("js> ");
System.err.flush();
try {
String source = "";
// Collect lines of source to compile.
while(true) {
String newline;
newline = in.readLine();
if (newline == null) {
hitEOF = true;
break;
}
source = source + newline + "\n";
lineno++;
// Continue collecting as long as more lines
// are needed to complete the current
// statement. stringIsCompilableUnit is also
// true if the source statement will result in
// any error other than one that might be
// resolved by appending more source.
if (cx.stringIsCompilableUnit(source))
break;
}
Object result = cx.evaluateString(global, source,
sourceName, startline,
null);
if (result != cx.getUndefinedValue()) {
System.err.println(cx.toString(result));
}
}
catch (WrappedException we) {
// Some form of exception was caught by JavaScript and
// propagated up.
System.err.println(we.getWrappedException().toString());
we.printStackTrace();
}
catch (EvaluatorException ee) {
// Some form of JavaScript error.
System.err.println("js: " + ee.getMessage());
}
catch (JavaScriptException jse) {
// Some form of JavaScript error.
System.err.println("js: " + jse.getMessage());
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
if (quitting) {
// The user executed the quit() function.
break;
}
} while (!hitEOF);
System.err.println();
} else {
FileReader in = null;
try {
in = new FileReader(filename);
}
catch (FileNotFoundException ex) {
Context.reportError("Couldn't open file \"" + filename + "\".");
return;
}
try {
// Here we evalute the entire contents of the file as
// a script. Text is printed only if the print() function
// is called.
cx.evaluateReader(global, in, filename, 1, null);
}
catch (WrappedException we) {
System.err.println(we.getWrappedException().toString());
we.printStackTrace();
}
catch (EvaluatorException ee) {
System.err.println("js: " + ee.getMessage());
}
catch (JavaScriptException jse) {
System.err.println("js: " + jse.getMessage());
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
finally {
try {
in.close();
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
}
System.gc();
}
private static void p(String s) {
System.out.println(s);
}
static Shell global;
static boolean quitting;
}

View File

@@ -1,134 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/**
* checkParam.js
*
* The files given as arguments on the command line are assumed to be
* Java source code files. This program checks to see that the @param
* tags in the documentation comments match with the parameters for
* the associated Java methods.
* <p>
* Any errors found are reported.
*
*/
defineClass("File")
// Return true if "str" ends with "suffix".
function stringEndsWith(str, suffix) {
return str.substring(str.length - suffix.length) == suffix;
}
/**
* Perform processing once the end of a documentation comment is seen.
*
* Look for a parameter list following the end of the comment and
* collect the parameters and compare to the @param entries.
* Report any discrepancies.
* @param f the current file
* @param a an array of parameters from @param comments
* @param line the string containing the comment end (in case the
* parameters are on the same line)
*/
function processCommentEnd(f, a, line) {
while (line != null && !line.match(/\(/))
line = f.readLine();
while (line != null && !line.match(/\)/))
line += f.readLine();
if (line === null)
return;
var m = line.match(/\(([^\)]+)\)/);
var args = m ? m[1].split(",") : [];
if (a.length != args.length) {
print('"' + f.name +
'"; line ' + f.lineNumber +
' mismatch: had a different number' +
' of @param entries and parameters.');
} else {
for (var i=0; i < a.length; i++) {
if (!stringEndsWith(args[i], a[i])) {
print('"' + f.name +
'"; line ' + f.lineNumber +
' mismatch: had "' + a[i] +
'" and "' + args[i] + '".');
break;
}
}
}
}
/**
* Process the given file, looking for mismatched @param lists and
* parameter lists.
* @param f the file to process
*/
function processFile(f) {
var line;
var m;
var i = 0;
var a = [];
outer:
while ((line = f.readLine()) != null) {
if (line.match(/@param/)) {
while (m = line.match(/@param[ ]+([^ ]+)/)) {
a[i++] = m[1];
line = f.readLine();
if (line == null)
break outer;
}
}
if (i != 0 && line.match(/\*\//)) {
processCommentEnd(f, a, line);
i = 0;
a = [];
}
}
if (i != 0) {
print('"' + f.name +
'"; line ' + f.lineNumber +
' missing parameters at end of file.');
}
}
// main script: process each file in arguments list
for (var i=0; i < arguments.length; i++) {
var filename = String(arguments[i]);
print("Checking " + filename + "...");
var f = new File(filename);
processFile(f);
}
print("done.");

View File

@@ -1,70 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Patrick Beard
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/*
enum.js
Implementing the interface java.util.Enumeration using the new syntax.
Note that this syntax is experimental only, and hasn't been approved
by ECMA.
The same functionality can be had without the new syntax using the
uglier syntax:
var elements = new JavaAdapter(java.util.Enumeration, {
index: 0, elements: array,
hasMoreElements: function ...
nextElement: function ...
});
by Patrick C. Beard.
*/
// an array to enumerate.
var array = [0, 1, 2];
// create an array enumeration.
var elements = new java.util.Enumeration() {
index: 0, elements: array,
hasMoreElements: function() {
return (this.index < this.elements.length);
},
nextElement: function() {
return this.elements[this.index++];
}
};
// now print out the array by enumerating through the Enumeration
while (elements.hasMoreElements())
print(elements.nextElement());

View File

@@ -1,508 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Roland Pennings
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/**
* Process a JavaScript source file and process special comments
* to produce an HTML file of documentation, similar to javadoc.
* @author Norris Boyd
* @see rhinotip.jar
* @lastmodified xx
* @version 1.2 Roland Pennings: Allow multiple files for a function.
* @version 1.3 Roland Pennings: Removes ../.. from the input directory name
*/
defineClass("File")
var functionDocArray = [];
var inputDirName = "";
var indexFileArray = [];
var indexFile = "";
var indexFileName = "index_files";
var indexFunctionArray = [];
var indexFunction = "";
var indexFunctionName = "index_functions";
var FileList = [];
var DirList = [];
var outputdir = null;
var debug = 0;
/**
* Process JavaScript source file <code>f</code>, writing jsdoc to
* file <code>out</code>.
* @param f input file
* @param fname name of the input file (without the path)
* @param inputdir directory of the input file
* @param out output file
*/
function processFile(f, fname, inputdir, out) {
var s;
var firstLine = true;
indexFileArray[fname] = "";
// write the header of the output file
out.writeLine('<HTML><HEADER><TITLE>' + fname + '</TITLE><BODY>');
if (inputdir != null) {
outstr = '<a name=\"_top_\"></a><pre><a href=\"' + indexFile + '\">Index Files</a> ';
outstr += '<a href=\"' + indexFunction + '\">Index Functions</a></pre><hr>';
out.writeLine(outstr);
}
// process the input file
var comment = "";
while ((s = f.readLine()) != null) {
var m = s.match(/\/\*\*(.*)/);
if (m != null) {
// Found a comment start.
s = "*" + m[1];
do {
m = s.match(/(.*)\*\//);
if (m != null) {
// Found end of comment.
comment += m[1];
break;
}
// Strip leading whitespace and "*".
comment += s.replace(/^\s*\*/, "");
s = f.readLine();
} while (s != null);
if (debug)
print("Found comment " + comment);
if (firstLine) {
// We have a comment for the whole file.
out.writeLine('<H1>File ' + fname + '</H1>');
out.writeLine(processComment(comment,firstLine,fname));
out.writeLine('<HR>');
firstLine = false;
comment = "";
continue;
}
}
// match the beginning of the function
// NB we also match functions without a comment!
// if we have two comments one after another only the last one will be taken
m = s.match(/^\s*function\s+((\w+)|(\w+)(\s+))\(([^)]*)\)/);
if (m != null)
{
// Found a function start
var htmlText = processFunction(m[1], m[2], comment);
// Save the text in a global variable, so we
// can write out a table of contents first.
functionDocArray[functionDocArray.length] =
{name:m[1], text:htmlText};
// Store the function also in the indexFunctionArray
// so we can have a seperate file with the function table of contents
if (indexFunctionArray[m[1]]) {
// print("ERROR: function: " + m[1] + " is defined more than once!");
// Allow multiple files for a function
with (indexFunctionArray[m[1]]) {
filename = filename + "|" + fname;
// print("filename = " + filename);
}
} else {
indexFunctionArray[m[1]] =
{filename:fname};
}
//reset comment
comment = "";
}
firstLine = false;
}
// Write table of contents.
for (var i=0; i < functionDocArray.length; i++) {
with (functionDocArray[i]) {
out.writeLine('function <A HREF=#' + name +
'>' + name + '</A><BR>');
}
}
out.writeLine('<HR>');
// Now write the saved function documentation.
for (i=0; i < functionDocArray.length; i++) {
with (functionDocArray[i]) {
out.writeLine('<A NAME=' + name + '>');
out.writeLine(text);
}
}
out.writeLine('</BODY></HTML>');
// Now clean up the doc array
functionDocArray = [];
}
/**
* Process function and associated comment.
* @param name the name of the function
* @param args the args of the function as a single string
* @param comment the text of the comment
* @return a string for the HTML text of the documentation
*/
function processFunction(name, args, comment) {
if (debug)
print("Processing " + name + " " + args + " " + comment);
return "<H2>Function " + name + "</H2>" +
"<PRE>" +
"function " + name + "(" + args + ")" +
"</PRE>" +
processComment(comment,0,name) +
"<P><BR><BR>";
}
/**
* Process comment.
* @param comment the text of the comment
* @param firstLine shows if comment is at the beginning of the file
* @param fname name of the file (without path)
* @return a string for the HTML text of the documentation
*/
function processComment(comment,firstLine,fname) {
var tags = {};
// Use the "lambda" form of regular expression replace,
// where the replacement object is a function rather
// than a string. The function is called with the
// matched text and any parenthetical matches as
// arguments, and the result of the function used as the
// replacement text.
// Here we use the function to build up the "tags" object,
// which has a property for each "@" tag that is the name
// of the tag, and whose value is an array of the
// text following that tag.
comment = comment.replace(/@(\w+)\s+([^@]*)/g,
function (s, name, text) {
var a = tags[name] || [];
a.push(text);
tags[name] = a;
return "";
});
// if we have a comment at the beginning of a file
// store the comment for the index file
if (firstLine) {
indexFileArray[fname] = comment;
}
var out = comment + '<P>';
if (tags["param"]) {
// Create a table of parameters and their descriptions.
var array = tags["param"];
var params = "";
for (var i=0; i < array.length; i++) {
var m = array[i].match(/(\w+)\s+(.*)/);
params += '<TR><TD><I>'+m[1]+'</I></TD>' +
'<TD>'+m[2]+'</TD></TR>';
}
out += '<TABLE WIDTH="90%" BORDER=1>';
out += '<TR BGCOLOR=0xdddddddd>';
out += '<TD><B>Parameter</B></TD>';
out += '<TD><B>Description</B></TD></TR>';
out += params;
out += '</TABLE><P>';
}
if (tags["return"]) {
out += "<DT><B>Returns:</B><DD>";
out += tags["return"][0] + "</DL><P>";
}
if (tags["author"]) {
// List the authors together, separated by commas.
out += '<DT><B>Author:</B><DD>';
var array = tags["author"];
for (var i=0; i < array.length; i++) {
out += array[i];
if (i+1 < array.length)
out += ", ";
}
out += '</DL><P>';
}
if (tags["version"]) {
// Show the version.
out += '<DT><B>Version:</B><DD>';
var array = tags["version"];
for (var i=0; i < array.length; i++) {
out += array[i];
if (i+1 < array.length)
out += "<BR><DD>";
}
out += '</DL><P>';
}
if (tags["see"]) {
// List the see modules together, separated by <BR>.
out += '<DT><B>Dependencies:</B><DD>';
var array = tags["see"];
for (var i=0; i < array.length; i++) {
out += array[i];
if (i+1 < array.length)
out += "<BR><DD>";
}
out += '</DL><P>';
}
if (tags["lastmodified"]) {
// Shows a last modified description with client-side js.
out += '<DT><B>Last modified:</B><DD>';
out += '<script><!--\n';
out += 'document.writeln(document.lastModified);\n';
out += '// ---></script>\n';
out += '</DL><P>';
}
// additional tags can be added here (i.e., "if (tags["see"])...")
return out;
}
/**
* Create an html output file
* @param outputdir directory to put the file
* @param htmlfile name of the file
*/
function CreateOutputFile(outputdir,htmlfile)
{
if (outputdir==null)
{
var outname = htmlfile;
}
else
{
var separator = Packages.java.io.File.separator;
var outname = outputdir + separator + htmlfile.substring(htmlfile.lastIndexOf(separator),htmlfile.length);
}
print("output file: " + outname);
return new File(outname);
}
/**
* Process a javascript file. Puts the generated HTML file in the outdir
* @param filename name of the javascript file
* @inputdir input directory of the file (default null)
*/
function processJSFile(filename,inputdir)
{
if (debug) print("filename = " + filename + " inputdir = " + inputdir);
if (!filename.match(/\.js$/)) {
print("Expected filename to end in '.js'; had instead " +
filename + ". I don't treat the file.");
} else {
if (inputdir==null)
{
var inname = filename;
}
else
{
var separator = Packages.java.io.File.separator;
var inname = inputdir + separator + filename;
}
print("Processing file " + inname);
var f = new File(inname);
// create the output file
var htmlfile = filename.replace(/\.js$/, ".html");
var out = CreateOutputFile(outputdir,htmlfile);
processFile(f, filename, inputdir, out);
out.close();
}
}
/**
* Generate index files containing links to the processed javascript files
* and the generated functions
*/
function GenerateIndex(dirname)
{
// construct the files index file
var out = CreateOutputFile(outputdir,indexFile);
// write the beginning of the file
out.writeLine('<HTML><HEADER><TITLE>File Index - directory: ' + dirname + '</TITLE><BODY>');
out.writeLine('<H1>File Index - directory: ' + dirname + '</H1>\n');
out.writeLine('<TABLE WIDTH="90%" BORDER=1>');
out.writeLine('<TR BGCOLOR=0xdddddddd>');
out.writeLine('<TD><B>File</B></TD>');
out.writeLine('<TD><B>Description</B></TD></TR>');
var separator = Packages.java.io.File.separator;
// sort the index file array
var SortedFileArray = [];
for (var fname in indexFileArray)
SortedFileArray.push(fname);
SortedFileArray.sort();
for (var i=0; i < SortedFileArray.length; i++) {
var fname = SortedFileArray[i];
var htmlfile = fname.replace(/\.js$/, ".html");
out.writeLine('<TR><TD><A HREF=\"' + htmlfile + '\">' + fname + '</A></TD></TD><TD>');
if (indexFileArray[fname])
out.writeLine(indexFileArray[fname]);
else
out.writeLine('No comments');
out.writeLine('</TD></TR>\n');
}
out.writeLine('</TABLE></BODY></HTML>');
out.close();
// construct the functions index file
var out = CreateOutputFile(outputdir,indexFunction);
// write the beginning of the file
out.writeLine('<HTML><HEADER><TITLE>Function Index - directory: ' + dirname + '</TITLE><BODY>');
out.writeLine('<H1>Function Index - directory: ' + dirname + '</H1>\n');
out.writeLine('<TABLE WIDTH="90%" BORDER=1>');
out.writeLine('<TR BGCOLOR=0xdddddddd>');
out.writeLine('<TD><B>Function</B></TD>');
out.writeLine('<TD><B>Files</B></TD></TR>');
// sort the function array
var SortedFunctionArray = [];
for (var functionname in indexFunctionArray)
SortedFunctionArray.push(functionname);
SortedFunctionArray.sort();
for (var j=0; j < SortedFunctionArray.length; j++) {
var funcname = SortedFunctionArray[j];
with (indexFunctionArray[funcname]) {
var outstr = '<TR><TD>' + funcname + '</TD><TD>';
var filelst = filename.split("|");
for (var i in filelst) {
var htmlfile = filelst[i].replace(/\.js$/, ".html");
outstr += '<A HREF=\"' + htmlfile + '#' + funcname + '\">' + filelst[i] + '</A>&nbsp;';
}
outstr += '</TD></TR>';
out.writeLine(outstr);
}
}
out.writeLine('</TABLE></BODY></HTML>');
out.close();
}
/**
* prints the options for JSDoc
*/
function PrintOptions()
{
print("You can use the following options:\n");
print("-d: specify an output directory for the generated html files\n");
print("-i: processes all files in an input directory (you can specify several directories)\n");
quit();
}
// Main Script
// first read the arguments
if (! arguments)
PrintOptions();
for (var i=0; i < arguments.length; i++) {
if (debug) print("argument: + \'" + arguments[i] + "\'");
if (arguments[i].match(/^\-/)) {
if (String(arguments[i])=="-d"){
// output directory for the generated html files
outputdir = String(arguments[i+1]);
if (debug) print("outputdir: + \'" + outputdir + "\'");
i++;
}
else if (String(arguments[i])=="-i"){
// process all files in an input directory
DirList.push(String(arguments[i+1]));
if (debug) print("inputdir: + \'" + arguments[i+1] + "\'");
i++;
}
else {
print("Unknown option: " + arguments[i] + "\n");
PrintOptions();
}
}
else
{
// we have a single file
if (debug) print("file: + \'" + arguments[i] + "\'");
FileList.push(String(arguments[i]));
}
}
// first handle the single files
for (var i in FileList)
processJSFile(FileList[i],null);
// then handle the input directories
for (var j in DirList) {
var inputdir = String(DirList[j]);
print("Process input directory: " + inputdir);
// clean up index arrays
var indexFileArray = [];
var indexFunctionArray = [];
// for the directory name get rid of ../../ or ..\..\
inputDirName = inputdir.replace(/\.\.\/|\.\.\\/g,"");
indexFile = indexFileName + "_" + inputDirName + ".html";
indexFunction = indexFunctionName + "_" + inputDirName + ".html";
print("indexFile = " + indexFile);
print("indexFunction = " + indexFunction);
// read the files in the directory
var DirFile = new java.io.File(inputdir);
var lst = DirFile.list();
var separator = Packages.java.io.File.separator;
for (var i=0; i < lst.length; i++)
{
processJSFile(String(lst[i]),inputdir);
}
// generate the index files for the input directory
GenerateIndex(inputDirName);
}

View File

@@ -1,54 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/**
* liveConnect.js: a simple demonstration of JavaScript-to-Java connectivity
*/
// Create a new StringBuffer. Note that the class name must be fully qualified
// by its package. Packages other than "java" must start with "Packages", i.e.,
// "Packages.javax.servlet...".
var sb = new java.lang.StringBuffer();
// Now add some stuff to the buffer.
sb.append("hi, mom");
sb.append(3); // this will add "3.0" to the buffer since all JS numbers
// are doubles by default
sb.append(true);
// Now print it out. (The toString() method of sb is automatically called
// to convert the buffer to a string.)
// Should print "hi, mom3.0true".
print(sb);

View File

@@ -1,53 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// unique.js: read the contents of a file and print out the unique lines
defineClass("File")
// "arguments[0]" refers to the first argument at the command line to the
// script, if present. If not present, "arguments[0]" will be undefined,
// which will cause f to read from System.in.
var f = new File(arguments[0]);
var o = {}
var line;
while ((line = f.readLine()) != null) {
// Use JavaScript objects' inherent nature as an associative
// array to provide uniqueness
o[line] = true;
}
for (i in o) {
print(i);
}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -1,2 +0,0 @@
Manifest-Version: 1.0
Main-Class: org.mozilla.javascript.tools.shell.Main

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,130 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
/**
* This class implements the "arguments" object.
*
* See ECMA 10.1.8
*
* @see org.mozilla.javascript.NativeCall
* @author Norris Boyd
*/
class Arguments extends ScriptableObject {
public Arguments(NativeCall activation) {
this.activation = activation;
Scriptable parent = activation.getParentScope();
setParentScope(parent);
setPrototype(ScriptableObject.getObjectPrototype(parent));
args = activation.getOriginalArguments();
int length = args.length;
Object callee = activation.funObj;
defineProperty("length", new Integer(length),
ScriptableObject.DONTENUM);
defineProperty("callee", callee, ScriptableObject.DONTENUM);
hasCaller = (activation.funObj.version <= Context.VERSION_1_3 &&
activation.funObj.version != Context.VERSION_DEFAULT);
}
public String getClassName() {
return "Arguments";
}
public boolean has(String name, Scriptable start) {
return (hasCaller && name.equals("caller")) || super.has(name, start);
}
public boolean has(int index, Scriptable start) {
Object[] args = activation.getOriginalArguments();
return (0 <= index && index < args.length) || super.has(index, start);
}
public Object get(String name, Scriptable start) {
if (hasCaller && name.equals("caller")) {
NativeCall caller = activation.caller;
if (caller == null || caller.originalArgs == null)
return null;
return caller.get("arguments", caller);
}
return super.get(name, start);
}
public Object get(int index, Scriptable start) {
if (0 <= index && index < args.length) {
NativeFunction f = activation.funObj;
if (index < f.argCount)
return activation.get(f.names[index+1], activation);
return args[index];
}
return super.get(index, start);
}
public void put(String name, Scriptable start, Object value) {
if (name.equals("caller")) {
// Set "hasCaller" to false so that we won't look up a
// computed value.
hasCaller = false;
}
super.put(name, start, value);
}
public void put(int index, Scriptable start, Object value) {
if (0 <= index && index < args.length) {
NativeFunction f = activation.funObj;
if (index < f.argCount)
activation.put(f.names[index+1], activation, value);
else
args[index] = value;
return;
}
super.put(index, start, value);
}
public void delete(String name) {
if (name.equals("caller"))
hasCaller = false;
super.delete(name);
}
private NativeCall activation;
private Object[] args;
private boolean hasCaller;
}

View File

@@ -1,75 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Waldemar Horwat
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
final class BinaryDigitReader {
int lgBase; // Logarithm of base of number
int digit; // Current digit value in radix given by base
int digitPos; // Bit position of last bit extracted from digit
String digits; // String containing the digits
int start; // Index of the first remaining digit
int end; // Index past the last remaining digit
BinaryDigitReader(int base, String digits, int start, int end) {
lgBase = 0;
while (base != 1) {
lgBase++;
base >>= 1;
}
digitPos = 0;
this.digits = digits;
this.start = start;
this.end = end;
}
/* Return the next binary digit from the number or -1 if done */
int getNextBinaryDigit()
{
if (digitPos == 0) {
if (start == end)
return -1;
char c = digits.charAt(start++);
if ('0' <= c && c <= '9')
digit = c - '0';
else if ('a' <= c && c <= 'z')
digit = c - 'a' + 10;
else digit = c - 'A' + 10;
digitPos = lgBase;
}
return digit >> --digitPos & 1;
}
}

View File

@@ -1,48 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
/**
* Thrown if errors are detected while attempting to define a host object
* from a Java class.
*/
public class ClassDefinitionException extends Exception {
public ClassDefinitionException(String detail) {
super(detail);
}
}

View File

@@ -1,61 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Roger Lawrence
* Andi Vajda
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
public interface ClassNameHelper {
public String getTargetClassFileName();
public void setTargetClassFileName(String classFileName);
public String getTargetPackage();
public void setTargetPackage(String targetPackage);
public String getTargetClassFileName(String className);
public String getGeneratingDirectory();
public void setTargetExtends(Class extendsClass);
public void setTargetImplements(Class[] implementsClasses);
public ClassOutput getClassOutput();
public void setClassOutput(ClassOutput classOutput);
}

View File

@@ -1,56 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Andi Vajda
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
// API class
import java.io.*;
/**
* This interface is implemented by classes interested in the bytecode
* generated by the rhino compiler for script objects.
*
* @see Context
* @author Andi Vajda
*/
public interface ClassOutput {
/**
* @param className the name of the class for which bytecode is ready.
* @return a stream into which to write bytecode.
* @since 1.5 Release 2
*/
public OutputStream getOutputStream(String className)
throws IOException;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,63 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
/**
* This is the default error reporter for JavaScript.
*
* @author Norris Boyd
*/
class DefaultErrorReporter implements ErrorReporter {
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
// do nothing
}
public void error(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
throw new EvaluatorException(message);
}
public EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource,
int lineOffset)
{
return new EvaluatorException(message);
}
}

View File

@@ -1,152 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
/**
* The class of exceptions raised by the engine as described in
* ECMA edition 3. See section 15.11.6 in particular.
*/
public class EcmaError extends RuntimeException {
/**
* Create an exception with the specified detail message.
*
* Errors internal to the JavaScript engine will simply throw a
* RuntimeException.
*
* @param nativeError the NativeError object constructed for this error
* @param sourceName the name of the source reponsible for the error
* @param lineNumber the line number of the source
* @param columnNumber the columnNumber of the source (may be zero if
* unknown)
* @param lineSource the source of the line containing the error (may be
* null if unknown)
*/
public EcmaError(NativeError nativeError, String sourceName,
int lineNumber, int columnNumber, String lineSource)
{
super("EcmaError");
errorObject = nativeError;
this.sourceName = sourceName;
this.lineNumber = lineNumber;
this.columnNumber = columnNumber;
this.lineSource = lineSource;
}
/**
* Return a string representation of the error, which currently consists
* of the name of the error together with the message.
*/
public String toString() {
if (sourceName != null && lineNumber > 0)
return errorObject.toString() + " (" + sourceName +
"; line " + lineNumber + ")";
else
return errorObject.toString();
}
/**
* Gets the name of the error.
*
* ECMA edition 3 defines the following
* errors: EvalError, RangeError, ReferenceError,
* SyntaxError, TypeError, and URIError. Additional error names
* may be added in the future.
*
* See ECMA edition 3, 15.11.7.9.
*
* @return the name of the error.
*/
public String getName() {
return errorObject.getName();
}
/**
* Gets the message corresponding to the error.
*
* See ECMA edition 3, 15.11.7.10.
*
* @return an implemenation-defined string describing the error.
*/
public String getMessage() {
return errorObject.getMessage();
}
/**
* Get the name of the source containing the error, or null
* if that information is not available.
*/
public String getSourceName() {
return sourceName;
}
/**
* Returns the line number of the statement causing the error,
* or zero if not available.
*/
public int getLineNumber() {
return lineNumber;
}
/**
* Get the error object corresponding to this exception.
*/
public Scriptable getErrorObject() {
return errorObject;
}
/**
* The column number of the location of the error, or zero if unknown.
*/
public int getColumnNumber() {
return columnNumber;
}
/**
* The source of the line causing the error, or zero if unknown.
*/
public String getLineSource() {
return lineSource;
}
private NativeError errorObject;
private String sourceName;
private int lineNumber;
private int columnNumber;
private String lineSource;
}

View File

@@ -1,103 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
/**
* This is interface defines a protocol for the reporting of
* errors during JavaScript translation or execution.
*
* @author Norris Boyd
*/
public interface ErrorReporter {
/**
* Report a warning.
*
* The implementing class may choose to ignore the warning
* if it desires.
*
* @param message a String describing the warning
* @param sourceName a String describing the JavaScript source
* where the warning occured; typically a filename or URL
* @param line the line number associated with the warning
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
*/
void warning(String message, String sourceName, int line,
String lineSource, int lineOffset);
/**
* Report an error.
*
* The implementing class is free to throw an exception if
* it desires.
*
* If execution has not yet begun, the JavaScript engine is
* free to find additional errors rather than terminating
* the translation. It will not execute a script that had
* errors, however.
*
* @param message a String describing the error
* @param sourceName a String describing the JavaScript source
* where the error occured; typically a filename or URL
* @param line the line number associated with the error
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
*/
void error(String message, String sourceName, int line,
String lineSource, int lineOffset);
/**
* Creates an EvaluatorException that may be thrown.
*
* runtimeErrors, unlike errors, will always terminate the
* current script.
*
* @param message a String describing the error
* @param sourceName a String describing the JavaScript source
* where the error occured; typically a filename or URL
* @param line the line number associated with the error
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
* @return an EvaluatorException that will be thrown.
*/
EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource,
int lineOffset);
}

View File

@@ -1,56 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
/**
* The class of exceptions thrown by the JavaScript engine.
*/
public class EvaluatorException extends RuntimeException {
/**
* Create an exception with the specified detail message.
*
* Errors internal to the JavaScript engine will simply throw a
* RuntimeException.
*
* @param detail a message with detail about the exception
*/
public EvaluatorException(String detail) {
super(detail);
}
}

View File

@@ -1,342 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* Manipulate a Scriptable object as if its prototype chain were flattened.
* <p>
* This class has been deprecated in favor of the static methods
* <code>getProperty</code>, <code>putProperty</code>, and
* <code>deleteProperty</code>. Those methods provide the
* same functionality without the confusing and inefficient need to construct
* a new object instance.
*
* @see org.mozilla.javascript.ScriptableObject
*
* @author Norris Boyd
*/
public class FlattenedObject {
/**
* Construct a new FlattenedObject.
*
* @param object the object to be viewed with flattened properties
* @deprecated
*/
public FlattenedObject(Scriptable object) {
this.obj = object;
}
/**
* Get the associated Scriptable object.
* @deprecated
*/
public Scriptable getObject() {
return obj;
}
/**
* Determine if a property exists in an object.
*
* This is a more convenient (and less efficient) form than
* <code>Scriptable.has()</code>.
* It returns true if and only if the property
* exists in this object or any of the objects in its prototype
* chain.
*
* @param id the property index, which may be either a String or a
* Number
* @return true if and only if the property exists in the prototype
* chain
* @see org.mozilla.javascript.Scriptable#has
* @deprecated As of 1.5R2, replaced by ScriptableObject.getProperty
*/
public boolean hasProperty(Object id) {
String stringId = ScriptRuntime.toString(id);
String s = ScriptRuntime.getStringId(stringId);
if (s == null)
return getBase(obj, ScriptRuntime.getIntId(stringId)) != null;
return getBase(obj, s) != null;
}
/**
* Get a property of an object.
* <p>
* This is a more convenient (and less efficient) form than
* <code>Scriptable.get()</code>. It corresponds exactly to the
* expression <code>obj[id]</code> in JavaScript. This method
* will traverse the prototype chain of an object to find the
* property.<p>
*
* If the property does not exist in the object or its prototype
* chain, the undefined value will be returned.
*
* @param id the property index; can be a String or a Number; the
* String may contain characters representing a number
* @return the value of the property or the undefined value
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.Context#getUndefinedValue
* @deprecated As of 1.5R2, replaced by ScriptableObject.getProperty
*/
public Object getProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
int index = s == null ? ScriptRuntime.getIntId(id) : 0;
Scriptable m = obj;
Object result;
for(;;) {
result = s == null ? m.get(index, obj) : m.get(s, obj);
if (result != Scriptable.NOT_FOUND)
break;
m = m.getPrototype();
if (m == null)
return Undefined.instance;
}
if (result instanceof Scriptable)
return new FlattenedObject((Scriptable) result);
return result;
}
/**
* Set a property of an object.
*
* This is a more convenient (and less efficient) form than that
* provided in Scriptable. It corresponds exactly to the
* expression <code>obj[id] = val</code> in JavaScript.<p>
*
* @param id the property index, which may be either a String or
* a Number
* @param value the value of the property
* @see org.mozilla.javascript.Scriptable#put
* @deprecated As of 1.5R2, replaced by ScriptableObject.putProperty
*/
public void putProperty(Object id, Object value) {
String s = ScriptRuntime.getStringId(id);
if (value instanceof FlattenedObject)
value = ((FlattenedObject) value).getObject();
Scriptable x;
if (s == null) {
int index = ScriptRuntime.getIntId(id);
x = getBase(obj, index);
if (x == null)
x = obj;
x.put(index, obj, value);
return;
}
x = getBase(obj, s);
if (x == null)
x = obj;
x.put(s, obj, value);
}
/**
* Remove a property.
*
* This method provides the functionality of the <code>delete</code>
* operator in JavaScript.
*
* @param id the property index, which may be either a String or
* a Number
* @return true if the property didn't exist, or existed and was removed
* @see org.mozilla.javascript.Scriptable#delete
* @deprecated as of 1.5R2, replaced by ScriptableObject.deleteProperty
*/
public boolean deleteProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
if (s == null) {
int index = ScriptRuntime.getIntId(id);
Scriptable base = getBase(obj, index);
if (base == null)
return true;
base.delete(index);
return !base.has(index, base);
}
Scriptable base = getBase(obj, s);
if (base == null)
return true;
base.delete(s);
return !base.has(s, base);
}
/**
* Return an array that contains the ids of the properties.
*
* <p>This method will walk the prototype chain and collect the
* ids of all objects in the prototype chain.<p>
*
* If an id appears in more than one object in the prototype chain,
* it will only be in the array once. (So all the entries in the
* array will be unique respective to equals().)
*
* @see org.mozilla.javascript.Scriptable#getIds
* @deprecated
*/
public Object[] getIds() {
Hashtable h = new Hashtable(11);
Scriptable m = obj;
while (m != null) {
Object[] e = m.getIds();
for (int i=0; i < e.length; i++) {
h.put(e[i], Boolean.TRUE);
}
m = m.getPrototype();
}
Enumeration keys = h.keys();
Object elem;
Object[] result = new Object[h.size()];
int index = 0;
while (keys.hasMoreElements()) {
elem = keys.nextElement();
result[index++] = elem;
}
return result;
}
/**
* Consider this object to be a function, and call it.
*
* @param cx the current Context for this thread
* @param thisObj the JavaScript 'this' for the call
* @param args the arguments for the call
* @return the result of the JavaScript function call
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the function
* @see org.mozilla.javascript.Function#call
* @deprecated
*/
public Object call(Context cx, Scriptable thisObj, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.call(cx, obj, thisObj, args, (Function) obj);
}
/**
* Consider this object to be a function, and invoke it as a
* constructor call.
*
* @param cx the current Context for this thread
* @param args the arguments for the constructor call
* @return the allocated object
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the constructor
* @see org.mozilla.javascript.Function#construct
* @deprecated
*/
public Scriptable construct(Context cx, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.newObject(cx, obj, args, null);
}
/**
* Get the property indicated by the id, and invoke it with the
* specified arguments.
* <p>
* For example, for a FlattenedObject <code>obj</code>,
* and a Java array <code>a</code> consisting of a single string
* <code>"hi"</code>, the call <pre>
* obj.callMethod("m", a)</pre>
* is equivalent to the JavaScript code <code>obj.m("hi")</code>.<p>
*
* If the property is not found or is not a function, an
* exception will be thrown.
*
* @param id the Number or String to use to find the function property
* to call
* @param args the arguments for the constructor call
* @return the result of the call
* @exception PropertyException if the designated property
* was not found
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the method
* @see org.mozilla.javascript.Function#call
* @deprecated
*/
public Object callMethod(Object id, Object[] args)
throws PropertyException,
NotAFunctionException,
JavaScriptException
{
if (!hasProperty(id)) {
throw new PropertyException(
Context.getMessage("msg.prop.not.found", null));
}
Object o = getProperty(id);
if (o instanceof FlattenedObject)
return ((FlattenedObject) o).call(Context.getContext(), obj, args);
throw new NotAFunctionException();
}
/****** End of API *******/
private static Scriptable getBase(Scriptable obj, String s) {
Scriptable m = obj;
while (m != null) {
if (m.has(s, obj))
return m;
m = m.getPrototype();
}
return null;
}
private static Scriptable getBase(Scriptable obj, int index) {
Scriptable m = obj;
while (m != null) {
if (m.has(index, obj))
return m;
m = m.getPrototype();
}
return null;
}
private Scriptable obj;
}

View File

@@ -1,86 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
/**
* This is interface that all functions in JavaScript must implement.
* The interface provides for calling functions and constructors.
*
* @see org.mozilla.javascript.Scriptable
* @author Norris Boyd
*/
public interface Function extends Scriptable {
/**
* Call the function.
*
* Note that the array of arguments is not guaranteed to have
* length greater than 0.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This is
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param thisObj the JavaScript <code>this</code> object
* @param args the array of arguments
* @return the result of the call
* @exception JavaScriptException if an uncaught exception
* occurred while executing the function
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException;
/**
* Call the function as a constructor.
*
* This method is invoked by the runtime in order to satisfy a use
* of the JavaScript <code>new</code> operator. This method is
* expected to create a new object and return it.
*
* @param cx the current Context for this thread
* @param scope an enclosing scope of the caller except
* when the function is called from a closure.
* @param args the array of arguments
* @return the allocated object
* @exception JavaScriptException if an uncaught exception
* occurred while executing the constructor
*/
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException;
}

View File

@@ -1,94 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.util.*;
public class FunctionNode extends Node {
public FunctionNode(String name, Node left, Node right) {
super(TokenStream.FUNCTION, left, right, name);
itsVariableTable = new VariableTable();
}
public String getFunctionName() {
return getString();
}
public VariableTable getVariableTable() {
return itsVariableTable;
}
public boolean requiresActivation() {
return itsNeedsActivation;
}
public boolean setRequiresActivation(boolean b) {
return itsNeedsActivation = b;
}
/**
* There are three types of functions that can be defined. The first
* is a function statement. This is a function appearing as a top-level
* statement (i.e., not nested inside some other statement) in either a
* script or a function.
*
* The second is a function expression, which is a function appearing in
* an expression except for the third type, which is...
*
* The third type is a function expression where the expression is the
* top-level expression in an expression statement.
*
* The three types of functions have different treatment and must be
* distinquished.
*/
public static final byte FUNCTION_STATEMENT = 1;
public static final byte FUNCTION_EXPRESSION = 2;
public static final byte FUNCTION_EXPRESSION_STATEMENT = 3;
public byte getFunctionType() {
return itsFunctionType;
}
public void setFunctionType(byte functionType) {
itsFunctionType = functionType;
}
protected VariableTable itsVariableTable;
protected boolean itsNeedsActivation;
protected byte itsFunctionType;
}

View File

@@ -1,636 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Ted Neward
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Vector;
import java.lang.reflect.*;
public class FunctionObject extends NativeFunction {
/**
* Create a JavaScript function object from a Java method.
*
* <p>The <code>member</code> argument must be either a java.lang.reflect.Method
* or a java.lang.reflect.Constructor and must match one of two forms.<p>
*
* The first form is a member with zero or more parameters
* of the following types: Object, String, boolean, Scriptable,
* byte, short, int, float, or double. The Long type is not supported
* because the double representation of a long (which is the
* EMCA-mandated storage type for Numbers) may lose precision.
* If the member is a Method, the return value must be void or one
* of the types allowed for parameters.<p>
*
* The runtime will perform appropriate conversions based
* upon the type of the parameter. A parameter type of
* Object specifies that no conversions are to be done. A parameter
* of type String will use Context.toString to convert arguments.
* Similarly, parameters of type double, boolean, and Scriptable
* will cause Context.toNumber, Context.toBoolean, and
* Context.toObject, respectively, to be called.<p>
*
* If the method is not static, the Java 'this' value will
* correspond to the JavaScript 'this' value. Any attempt
* to call the function with a 'this' value that is not
* of the right Java type will result in an error.<p>
*
* The second form is the variable arguments (or "varargs")
* form. If the FunctionObject will be used as a constructor,
* the member must have the following parameters
* <pre>
* (Context cx, Object[] args, Function ctorObj,
* boolean inNewExpr)</pre>
* and if it is a Method, be static and return an Object result.<p>
*
* Otherwise, if the FunctionObject will <i>not</i> be used to define a
* constructor, the member must be a static Method with parameters
* (Context cx, Scriptable thisObj, Object[] args,
* Function funObj) </pre>
* <pre>
* and an Object result.<p>
*
* When the function varargs form is called as part of a function call,
* the <code>args</code> parameter contains the
* arguments, with <code>thisObj</code>
* set to the JavaScript 'this' value. <code>funObj</code>
* is the function object for the invoked function.<p>
*
* When the constructor varargs form is called or invoked while evaluating
* a <code>new</code> expression, <code>args</code> contains the
* arguments, <code>ctorObj</code> refers to this FunctionObject, and
* <code>inNewExpr</code> is true if and only if a <code>new</code>
* expression caused the call. This supports defining a function that
* has different behavior when called as a constructor than when
* invoked as a normal function call. (For example, the Boolean
* constructor, when called as a function,
* will convert to boolean rather than creating a new object.)<p>
*
* @param name the name of the function
* @param methodOrConstructor a java.lang.reflect.Method or a java.lang.reflect.Constructor
* that defines the object
* @param scope enclosing scope of function
* @see org.mozilla.javascript.Scriptable
*/
public FunctionObject(String name, Member methodOrConstructor,
Scriptable scope)
{
String methodName;
if (methodOrConstructor instanceof Constructor) {
ctor = (Constructor) methodOrConstructor;
isStatic = true; // well, doesn't take a 'this'
types = ctor.getParameterTypes();
methodName = ctor.getName();
} else {
method = (Method) methodOrConstructor;
isStatic = Modifier.isStatic(method.getModifiers());
types = method.getParameterTypes();
methodName = method.getName();
}
String myNames[] = { name };
super.names = myNames;
int length;
if (types.length == 4 && (types[1].isArray() || types[2].isArray())) {
// Either variable args or an error.
if (types[1].isArray()) {
if (!isStatic ||
types[0] != Context.class ||
types[1].getComponentType() != ScriptRuntime.ObjectClass ||
types[2] != ScriptRuntime.FunctionClass ||
types[3] != Boolean.TYPE)
{
String[] args = { methodName };
String message = Context.getMessage("msg.varargs.ctor",
args);
throw Context.reportRuntimeError(message);
}
parmsLength = VARARGS_CTOR;
} else {
if (!isStatic ||
types[0] != Context.class ||
types[1] != ScriptRuntime.ScriptableClass ||
types[2].getComponentType() != ScriptRuntime.ObjectClass ||
types[3] != ScriptRuntime.FunctionClass)
{
String[] args = { methodName };
String message = Context.getMessage("msg.varargs.fun",
args);
throw Context.reportRuntimeError(message);
}
parmsLength = VARARGS_METHOD;
}
// XXX check return type
length = 1;
} else {
parmsLength = (short) types.length;
boolean hasConversions = false;
for (int i=0; i < parmsLength; i++) {
Class type = types[i];
if (type == ScriptRuntime.ObjectClass) {
// may not need conversions
} else if (type == ScriptRuntime.StringClass ||
type == ScriptRuntime.BooleanClass ||
ScriptRuntime.NumberClass.isAssignableFrom(type) ||
Scriptable.class.isAssignableFrom(type))
{
hasConversions = true;
} else if (type == Boolean.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.BooleanClass;
} else if (type == Byte.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.ByteClass;
} else if (type == Short.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.ShortClass;
} else if (type == Integer.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.IntegerClass;
} else if (type == Float.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.FloatClass;
} else if (type == Double.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.DoubleClass;
}
// Note that long is not supported; see comments above
else {
Object[] errArgs = { methodName };
throw Context.reportRuntimeError(
Context.getMessage("msg.bad.parms", errArgs));
}
}
if (!hasConversions)
types = null;
length = parmsLength;
}
// Initialize length property
lengthPropertyValue = (short) length;
hasVoidReturn = method != null && method.getReturnType() == Void.TYPE;
this.argCount = (short) length;
setParentScope(scope);
setPrototype(getFunctionPrototype(scope));
Context cx = Context.getCurrentContext();
useDynamicScope = cx != null &&
cx.hasCompileFunctionsWithDynamicScope();
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* We could also have defined the property using ScriptableObject's
* defineProperty method, but that would have consumed a slot in every
* FunctionObject. Most FunctionObjects typically don't have any
* properties anyway, so having the "length" property would cause us
* to allocate an array of slots. <p>
*
* In particular, this method will return true for
* <code>name.equals("length")</code>
* and will delegate to the superclass for all other
* values of <code>name</code>.
*/
public boolean has(String name, Scriptable start) {
return name.equals("length") || super.has(name, start);
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* In particular, this method will return the value defined by
* the method used to construct the object (number of parameters
* of the method, or 1 if the method is a "varargs" form), unless
* setLength has been called with a new value.
*
* @see org.mozilla.javascript.FunctionObject#setLength
*/
public Object get(String name, Scriptable start) {
if (name.equals("length"))
return new Integer(lengthPropertyValue);
return super.get(name, start);
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* In particular, this method will ignore all attempts to set the
* "length" property and forward all other requests to ScriptableObject.
*
* @see org.mozilla.javascript.FunctionObject#setLength
*/
public void put(String name, Scriptable start, Object value) {
if (!name.equals("length"))
super.put(name, start, value);
}
/**
* Set the value of the "length" property.
*
* <p>Changing the value of the "length" property of a FunctionObject only
* affects the value retrieved from get() and does not affect the way
* the method itself is called. <p>
*
* The "length" property will be defined by default as the number
* of parameters of the method used to construct the FunctionObject,
* unless the method is a "varargs" form, in which case the "length"
* property will be defined to 1.
*
* @param length the new length
*/
public void setLength(short length) {
lengthPropertyValue = length;
}
// TODO: Make not public
/**
* Finds methods of a given name in a given class.
*
* <p>Searches <code>clazz</code> for methods with name
* <code>name</code>. Maintains a cache so that multiple
* lookups on the same class are cheap.
*
* @param clazz the class to search
* @param name the name of the methods to find
* @return an array of the found methods, or null if no methods
* by that name were found.
* @see java.lang.Class#getMethods
*/
public static Method[] findMethods(Class clazz, String name) {
return findMethods(getMethodList(clazz), name);
}
static Method[] findMethods(Method[] methods, String name) {
// Usually we're just looking for a single method, so optimize
// for that case.
Vector v = null;
Method first = null;
for (int i=0; i < methods.length; i++) {
if (methods[i] == null)
continue;
if (methods[i].getName().equals(name)) {
if (first == null) {
first = methods[i];
} else {
if (v == null) {
v = new Vector(5);
v.addElement(first);
}
v.addElement(methods[i]);
}
}
}
if (v == null) {
if (first == null)
return null;
Method[] single = { first };
return single;
}
Method[] result = new Method[v.size()];
v.copyInto(result);
return result;
}
static Method[] getMethodList(Class clazz) {
Method[] cached = methodsCache; // get once to avoid synchronization
if (cached != null && cached[0].getDeclaringClass() == clazz)
return cached;
Method[] methods = null;
try {
// getDeclaredMethods may be rejected by the security manager
// but getMethods is more expensive
if (!sawSecurityException)
methods = clazz.getDeclaredMethods();
} catch (SecurityException e) {
// If we get an exception once, give up on getDeclaredMethods
sawSecurityException = true;
}
if (methods == null) {
methods = clazz.getMethods();
}
int count = 0;
for (int i=0; i < methods.length; i++) {
if (sawSecurityException
? methods[i].getDeclaringClass() != clazz
: !Modifier.isPublic(methods[i].getModifiers()))
{
methods[i] = null;
} else {
count++;
}
}
Method[] result = new Method[count];
int j=0;
for (int i=0; i < methods.length; i++) {
if (methods[i] != null)
result[j++] = methods[i];
}
if (result.length > 0 && Context.isCachingEnabled)
methodsCache = result;
return result;
}
/**
* Define this function as a JavaScript constructor.
* <p>
* Sets up the "prototype" and "constructor" properties. Also
* calls setParent and setPrototype with appropriate values.
* Then adds the function object as a property of the given scope, using
* <code>prototype.getClassName()</code>
* as the name of the property.
*
* @param scope the scope in which to define the constructor (typically
* the global object)
* @param prototype the prototype object
* @see org.mozilla.javascript.Scriptable#setParentScope
* @see org.mozilla.javascript.Scriptable#setPrototype
* @see org.mozilla.javascript.Scriptable#getClassName
*/
public void addAsConstructor(Scriptable scope, Scriptable prototype) {
setParentScope(scope);
setPrototype(getFunctionPrototype(scope));
prototype.setParentScope(this);
final int attr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT |
ScriptableObject.READONLY;
defineProperty("prototype", prototype, attr);
String name = prototype.getClassName();
if (!name.equals("With")) {
// A "With" object would delegate these calls to the prototype:
// not the right thing to do here!
if (prototype instanceof ScriptableObject) {
((ScriptableObject) prototype).defineProperty("constructor",
this, attr);
} else {
prototype.put("constructor", prototype, this);
}
}
if (scope instanceof ScriptableObject) {
((ScriptableObject) scope).defineProperty(name, this,
ScriptableObject.DONTENUM);
} else {
scope.put(name, scope, this);
}
setParentScope(scope);
}
static public Object convertArg(Scriptable scope,
Object arg, Class desired)
{
if (desired == ScriptRuntime.BooleanClass
|| desired == Boolean.TYPE)
return ScriptRuntime.toBoolean(arg) ? Boolean.TRUE
: Boolean.FALSE;
else if (desired == ScriptRuntime.StringClass)
return ScriptRuntime.toString(arg);
else if (desired == ScriptRuntime.IntegerClass
|| desired == Integer.TYPE)
return new Integer(ScriptRuntime.toInt32(arg));
else if (desired == ScriptRuntime.DoubleClass
|| desired == Double.TYPE)
return new Double(ScriptRuntime.toNumber(arg));
else if (desired == ScriptRuntime.ScriptableClass)
return ScriptRuntime.toObject(scope, arg);
else if (desired == ScriptRuntime.ObjectClass)
return arg;
// Note that the long type is not supported; see the javadoc for
// the constructor for this class
else {
Object[] errArgs = { desired.getName() };
throw Context.reportRuntimeError(
Context.getMessage("msg.cant.convert", errArgs));
}
}
/**
* Performs conversions on argument types if needed and
* invokes the underlying Java method or constructor.
* <p>
* Implements Function.call.
*
* @see org.mozilla.javascript.Function#call
* @exception JavaScriptException if the underlying Java method or
* constructor threw an exception
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (parmsLength < 0)
return callVarargs(cx, thisObj, args, false);
if (!isStatic) {
// OPT: cache "clazz"?
Class clazz = method != null ? method.getDeclaringClass()
: ctor.getDeclaringClass();
while (!clazz.isInstance(thisObj)) {
thisObj = thisObj.getPrototype();
if (thisObj == null || !useDynamicScope) {
// Couldn't find an object to call this on.
Object[] errArgs = { names[0] };
String msg = Context.getMessage("msg.incompat.call", errArgs);
throw NativeGlobal.constructError(cx, "TypeError", msg, scope);
}
}
}
Object[] invokeArgs;
int i;
if (parmsLength == args.length) {
invokeArgs = args;
// avoid copy loop if no conversions needed
i = (types == null) ? parmsLength : 0;
} else {
invokeArgs = new Object[parmsLength];
i = 0;
}
for (; i < parmsLength; i++) {
Object arg = (i < args.length)
? args[i]
: Undefined.instance;
if (types != null) {
arg = convertArg(this, arg, types[i]);
}
invokeArgs[i] = arg;
}
try {
Object result = (method != null)
? method.invoke(thisObj, invokeArgs)
: ctor.newInstance(invokeArgs);
return hasVoidReturn ? Undefined.instance : result;
}
catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(scope, e);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
}
/**
* Performs conversions on argument types if needed and
* invokes the underlying Java method or constructor
* to create a new Scriptable object.
* <p>
* Implements Function.construct.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param args arguments to the constructor
* @see org.mozilla.javascript.Function#construct
* @exception JavaScriptException if the underlying Java method or constructor
* threw an exception
*/
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
if (method == null || parmsLength == VARARGS_CTOR) {
Scriptable result;
if (method != null) {
// Ugly: allow variable-arg constructors that need access to the
// scope to get it from the Context. Cleanest solution would be
// to modify the varargs form, but that would require users with
// the old form to change their code.
cx.ctorScope = scope;
result = (Scriptable) callVarargs(cx, null, args, true);
cx.ctorScope = null;
} else {
result = (Scriptable) call(cx, scope, null, args);
}
if (result.getPrototype() == null)
result.setPrototype(getClassPrototype());
if (result.getParentScope() == null) {
Scriptable parent = getParentScope();
if (result != parent)
result.setParentScope(parent);
}
return result;
} else if (method != null && !isStatic) {
Scriptable result;
try {
result = (Scriptable) method.getDeclaringClass().newInstance();
} catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
} catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
result.setPrototype(getClassPrototype());
result.setParentScope(getParentScope());
Object val = call(cx, scope, result, args);
if (val != null && val != Undefined.instance &&
val instanceof Scriptable)
{
return (Scriptable) val;
}
return result;
}
return super.construct(cx, scope, args);
}
private Object callVarargs(Context cx, Scriptable thisObj, Object[] args,
boolean inNewExpr)
throws JavaScriptException
{
try {
if (parmsLength == VARARGS_METHOD) {
Object[] invokeArgs = { cx, thisObj, args, this };
Object result = method.invoke(null, invokeArgs);
return hasVoidReturn ? Undefined.instance : result;
} else {
Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE;
Object[] invokeArgs = { cx, args, this, b };
return (method == null)
? ctor.newInstance(invokeArgs)
: method.invoke(null, invokeArgs);
}
}
catch (InvocationTargetException e) {
Throwable target = e.getTargetException();
if (target instanceof EvaluatorException)
throw (EvaluatorException) target;
if (target instanceof EcmaError)
throw (EcmaError) target;
Scriptable scope = thisObj == null ? this : thisObj;
throw JavaScriptException.wrapException(scope, target);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
}
boolean isVarArgsMethod() {
return parmsLength == VARARGS_METHOD;
}
boolean isVarArgsConstructor() {
return parmsLength == VARARGS_CTOR;
}
private static final short VARARGS_METHOD = -1;
private static final short VARARGS_CTOR = -2;
private static boolean sawSecurityException;
static Method[] methodsCache;
Method method;
Constructor ctor;
private Class[] types;
private short parmsLength;
private short lengthPropertyValue;
private boolean hasVoidReturn;
private boolean isStatic;
private boolean useDynamicScope;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,144 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
import java.util.Vector;
/**
* Class ImporterTopLevel
*
* This class defines a ScriptableObject that can be instantiated
* as a top-level ("global") object to provide functionality similar
* to Java's "import" statement.
* <p>
* This class can be used to create a top-level scope using the following code:
* <pre>
* Scriptable scope = cx.initStandardObjects(new ImporterTopLevel());
* </pre>
* Then JavaScript code will have access to the following methods:
* <ul>
* <li>importClass - will "import" a class by making its unqualified name
* available as a property of the top-level scope
* <li>importPackage - will "import" all the classes of the package by
* searching for unqualified names as classes qualified
* by the given package.
* </ul>
* The following code from the shell illustrates this use:
* <pre>
* js> importClass(java.io.File)
* js> f = new File('help.txt')
* help.txt
* js> importPackage(java.util)
* js> v = new Vector()
* []
*
* @author Norris Boyd
*/
public class ImporterTopLevel extends ScriptableObject {
public ImporterTopLevel() {
String[] names = { "importClass", "importPackage" };
try {
this.defineFunctionProperties(names, ImporterTopLevel.class,
ScriptableObject.DONTENUM);
} catch (PropertyException e) {
throw new Error(); // should never happen
}
}
public String getClassName() {
return "global";
}
public Object get(String name, Scriptable start) {
Object result = super.get(name, start);
if (result == NOT_FOUND && importedPackages != null) {
for (int i=0; i < importedPackages.size(); i++) {
Object o = importedPackages.elementAt(i);
NativeJavaPackage p = (NativeJavaPackage) o;
Object v = p.getPkgProperty(name, start, false);
if (v != null && !(v instanceof NativeJavaPackage)) {
if (result == NOT_FOUND) {
result = v;
} else {
String[] args = { result.toString(), v.toString() };
throw Context.reportRuntimeError(
Context.getMessage("msg.ambig.import",
args));
}
}
}
}
return result;
}
public void importClass(Object cl) {
if (!(cl instanceof NativeJavaClass)) {
String[] args = { Context.toString(cl) };
throw Context.reportRuntimeError(
Context.getMessage("msg.not.class", args));
}
String s = ((NativeJavaClass) cl).getClassObject().getName();
String n = s.substring(s.lastIndexOf('.')+1);
Object val = this.get(n, this);
if (val != NOT_FOUND && val != cl) {
String[] args = { n };
throw Context.reportRuntimeError(
Context.getMessage("msg.prop.defined", args));
}
this.defineProperty(n, cl, DONTENUM);
}
public void importPackage(Object pkg) {
if (importedPackages == null)
importedPackages = new Vector();
if (!(pkg instanceof NativeJavaPackage)) {
String[] args = { Context.toString(pkg) };
throw Context.reportRuntimeError(
Context.getMessage("msg.not.pkg", args));
}
for (int i=0; i < importedPackages.size(); i++) {
if (pkg == importedPackages.elementAt(i))
return; // allready in list
}
importedPackages.addElement(pkg);
}
private Vector importedPackages;
}

View File

@@ -1,113 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.util.*;
import org.mozilla.javascript.debug.DebuggableScript;
class InterpretedFunction extends NativeFunction implements DebuggableScript {
InterpretedFunction(InterpreterData theData, Context cx)
{
itsData = theData;
init(cx);
}
void init(Context cx)
{
// probably too much copying going on from theData to the InterpretedFunction object
// should pass them as parameters - unless we need them in the data block anyway?
names = new String[itsData.itsVariableTable.size() + 1];
names[0] = itsData.itsName;
for (int i = 0; i < itsData.itsVariableTable.size(); i++)
names[i + 1] = itsData.itsVariableTable.getName(i);
argCount = (short)itsData.itsVariableTable.getParameterCount();
source = itsData.itsSource;
nestedFunctions = itsData.itsNestedFunctions;
if (cx != null)
version = (short)cx.getLanguageVersion();
}
InterpretedFunction(InterpretedFunction theOther,
Scriptable theScope, Context cx)
{
itsData = theOther.itsData;
itsClosure = theScope;
init(cx);
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
itsData.itsCX = cx;
if (itsClosure != null)
scope = itsClosure;
else if (!itsData.itsUseDynamicScope)
scope = getParentScope();
if (itsData.itsNeedsActivation)
scope = ScriptRuntime.initVarObj(cx, scope, this, thisObj, args);
itsData.itsScope = scope;
itsData.itsThisObj = thisObj;
itsData.itsInArgs = args;
return Interpreter.interpret(itsData, this);
}
public Scriptable getScriptable() {
return this;
}
public String getSourceName() {
return itsData.itsSourceFile;
}
public Enumeration getLineNumbers() {
return itsData.itsLineNumberTable.keys();
}
public boolean placeBreakpoint(int line) { // XXX throw exn?
return itsData.placeBreakpoint(line);
}
public boolean removeBreakpoint(int line) {
return itsData.removeBreakpoint(line);
}
InterpreterData itsData;
Scriptable itsClosure;
}

View File

@@ -1,96 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import org.mozilla.javascript.debug.*;
import java.util.*;
public class InterpretedScript extends NativeScript implements DebuggableScript {
InterpretedScript(InterpreterData theData, Context cx)
{
itsData = theData;
names = new String[itsData.itsVariableTable.size() + 1];
names[0] = "";
for (int i = 0; i < itsData.itsVariableTable.size(); i++)
names[i + 1] = itsData.itsVariableTable.getName(i);
nestedFunctions = itsData.itsNestedFunctions;
version = (short)cx.getLanguageVersion();
}
public Object exec(Context cx, Scriptable scope)
throws JavaScriptException
{
return call(cx, scope, scope, null);
}
public Object call(Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
throws JavaScriptException
{
scope = ScriptRuntime.initScript(cx, scope, this, thisObj,
itsData.itsFromEvalCode);
itsData.itsCX = cx;
itsData.itsScope = scope;
itsData.itsThisObj = thisObj;
itsData.itsInArgs = args;
return Interpreter.interpret(itsData, this);
}
public Scriptable getScriptable() {
return this;
}
public String getSourceName() {
return itsData.itsSourceFile;
}
public Enumeration getLineNumbers() {
return itsData.itsLineNumberTable.keys();
}
public boolean placeBreakpoint(int line) { // XXX throw exn?
return itsData.placeBreakpoint(line);
}
public boolean removeBreakpoint(int line) {
return itsData.removeBreakpoint(line);
}
InterpreterData itsData;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,138 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.util.Vector;
class InterpreterData {
static final int INITIAL_MAX_ICODE_LENGTH = 1024;
static final int INITIAL_STRINGTABLE_SIZE = 64;
static final int INITIAL_NUMBERTABLE_SIZE = 64;
InterpreterData(int lastICodeTop, int lastStringTableIndex,
int lastNumberTableIndex, Object securityDomain,
boolean useDynamicScope)
{
itsICodeTop = lastICodeTop == 0
? INITIAL_MAX_ICODE_LENGTH
: lastICodeTop * 2;
itsICode = new byte[itsICodeTop];
itsStringTable = new String[lastStringTableIndex == 0
? INITIAL_STRINGTABLE_SIZE
: lastStringTableIndex * 2];
itsNumberTable = new Number[lastNumberTableIndex == 0
? INITIAL_NUMBERTABLE_SIZE
: lastNumberTableIndex * 2];
itsUseDynamicScope = useDynamicScope;
if (securityDomain == null && Context.isSecurityDomainRequired())
throw new SecurityException("Required security context missing");
this.securityDomain = securityDomain;
}
public boolean placeBreakpoint(int line) { // XXX throw exn?
int offset = getOffset(line);
if (offset != -1 && (itsICode[offset] == TokenStream.LINE ||
itsICode[offset] == TokenStream.BREAKPOINT))
{
itsICode[offset] = (byte) TokenStream.BREAKPOINT;
return true;
}
return false;
}
public boolean removeBreakpoint(int line) {
int offset = getOffset(line);
if (offset != -1 && itsICode[offset] == TokenStream.BREAKPOINT)
{
itsICode[offset] = (byte) TokenStream.LINE;
return true;
}
return false;
}
private int getOffset(int line) {
Object offset = itsLineNumberTable.get(new Integer(line));
if (offset != null && offset instanceof Integer) {
int i = ((Integer)offset).intValue();
if (i >= 0 && i < itsICode.length)
{
return i;
}
}
return -1;
}
VariableTable itsVariableTable;
String itsName;
String itsSource;
String itsSourceFile;
boolean itsNeedsActivation;
boolean itsFromEvalCode;
boolean itsUseDynamicScope;
byte itsFunctionType;
String[] itsStringTable;
int itsStringTableIndex;
Number[] itsNumberTable;
int itsNumberTableIndex;
InterpretedFunction[] itsNestedFunctions;
Object[] itsRegExpLiterals;
byte[] itsICode;
int itsICodeTop;
int itsMaxLocals;
int itsMaxArgs;
int itsMaxStack;
int itsMaxTryDepth;
java.util.Hashtable itsLineNumberTable;
Object securityDomain;
Context itsCX;
Scriptable itsScope;
Scriptable itsThisObj;
Object[] itsInArgs;
}

View File

@@ -1,77 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.util.Vector;
import org.mozilla.javascript.debug.*;
class InterpreterFrame implements Frame {
InterpreterFrame(Scriptable scope, InterpreterData data, Scriptable obj) {
this.scope = scope;
this.data = data;
this.lineNumber = -1;
this.obj = obj;
}
public Scriptable getVariableObject() {
return scope;
}
public String getSourceName() {
return data.itsSourceFile;
}
public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
}
public int getLineNumber() {
return lineNumber;
}
public DebuggableScript getScript() {
if (obj instanceof DebuggableScript)
return (DebuggableScript) obj;
return null;
}
private Scriptable scope;
private InterpreterData data;
private Scriptable obj;
private int lineNumber;
}

View File

@@ -1,849 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Patrick Beard
* Norris Boyd
* Mike McCabe
* Matthias Radestock
* Andi Vajda
* Andrew Wason
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import org.mozilla.classfile.*;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
public class JavaAdapter extends ScriptableObject {
public boolean equals(Object obj) {
return super.equals(obj);
}
public String getClassName() {
return "JavaAdapter";
}
public static Object convertResult(Object result, String classname)
throws ClassNotFoundException
{
Class c = ScriptRuntime.loadClassName(classname);
if (result == Undefined.instance &&
(c != ScriptRuntime.ObjectClass &&
c != ScriptRuntime.StringClass))
{
// Avoid an error for an undefined value; return null instead.
return null;
}
return NativeJavaObject.coerceType(c, result);
}
public static Object js_JavaAdapter(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
throws InstantiationException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException,
ClassNotFoundException
{
Class superClass = Object.class;
Class[] intfs = new Class[args.length-1];
int interfaceCount = 0;
for (int i=0; i < args.length-1; i++) {
if (!(args[i] instanceof NativeJavaClass)) {
// TODO: report error
throw new RuntimeException("expected java class object");
}
Class c = ((NativeJavaClass) args[i]).getClassObject();
if (!c.isInterface()) {
superClass = c;
break;
}
intfs[interfaceCount++] = c;
}
Class[] interfaces = new Class[interfaceCount];
System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
Scriptable obj = (Scriptable) args[args.length - 1];
ClassSignature sig = new ClassSignature(superClass, interfaces, obj);
Class adapterClass = (Class) generatedClasses.get(sig);
if (adapterClass == null) {
String adapterName = "adapter" + serial++;
adapterClass = createAdapterClass(cx, obj, adapterName,
superClass, interfaces,
null, null);
generatedClasses.put(sig, adapterClass);
}
Class[] ctorParms = { Scriptable.class };
Object[] ctorArgs = { obj };
Object v = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
return cx.toObject(v, ScriptableObject.getTopLevelScope(ctorObj));
}
public static Class createAdapterClass(Context cx, Scriptable jsObj,
String adapterName, Class superClass,
Class[] interfaces,
String scriptClassName,
ClassNameHelper nameHelper)
throws ClassNotFoundException
{
ClassFileWriter cfw = new ClassFileWriter(adapterName,
superClass.getName(),
"<adapter>");
cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;",
(short) (ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
int interfacesCount = interfaces == null ? 0 : interfaces.length;
for (int i=0; i < interfacesCount; i++) {
if (interfaces[i] != null)
cfw.addInterface(interfaces[i].getName());
}
String superName = superClass.getName().replace('.', '/');
generateCtor(cfw, adapterName, superName);
if (scriptClassName != null)
generateEmptyCtor(cfw, adapterName, superName, scriptClassName);
Hashtable generatedOverrides = new Hashtable();
Hashtable generatedMethods = new Hashtable();
// generate methods to satisfy all specified interfaces.
for (int i = 0; i < interfacesCount; i++) {
Method[] methods = interfaces[i].getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
int mods = method.getModifiers();
if (Modifier.isStatic(mods) || Modifier.isFinal(mods))
continue;
// make sure to generate only one instance of a particular
// method/signature.
String methodName = method.getName();
String methodKey = methodName + getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
generateMethod(cfw, adapterName, methodName,
method.getParameterTypes(),
method.getReturnType());
generatedOverrides.put(methodKey, Boolean.TRUE);
generatedMethods.put(methodName, Boolean.TRUE);
}
}
}
// Now, go through the superclasses methods, checking for abstract
// methods or additional methods to override.
// generate any additional overrides that the object might contain.
Method[] methods = superClass.getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
int mods = method.getModifiers();
if (Modifier.isStatic(mods) || Modifier.isFinal(mods))
continue;
// if a method is marked abstract, must implement it or the
// resulting class won't be instantiable. otherwise, if the object
// has a property of the same name, then an override is intended.
boolean isAbstractMethod = Modifier.isAbstract(mods);
if (isAbstractMethod ||
(jsObj != null && jsObj.has(method.getName(), jsObj)))
{
// make sure to generate only one instance of a particular
// method/signature.
String methodName = method.getName();
String methodSignature = getMethodSignature(method);
String methodKey = methodName + methodSignature;
if (! generatedOverrides.containsKey(methodKey)) {
generateMethod(cfw, adapterName, methodName,
method.getParameterTypes(),
method.getReturnType());
generatedOverrides.put(methodKey, Boolean.TRUE);
generatedMethods.put(methodName, Boolean.TRUE);
}
// if a method was overridden, generate a "super$method"
// which lets the delegate call the superclass' version.
if (!isAbstractMethod) {
generateSuper(cfw, adapterName, superName,
methodName, methodSignature,
method.getParameterTypes(),
method.getReturnType());
}
}
}
// Generate Java methods, fields for remaining properties that
// are not overrides.
Object[] ids = jsObj.getIds();
for (int j=0; j < ids.length; j++) {
if (!(ids[j] instanceof String))
continue;
String id = (String) ids[j];
if (generatedMethods.containsKey(id))
continue;
Object f = jsObj.get(id, jsObj);
int length;
if (f instanceof Scriptable) {
Scriptable p = (Scriptable) f;
if (!(p instanceof Function))
continue;
length = (int) Context.toNumber(
ScriptableObject.getProperty(p, "length"));
} else if (f instanceof FunctionNode) {
length = ((FunctionNode) f).getVariableTable().getParameterCount();
} else {
continue;
}
Class[] parms = new Class[length];
for (int k=0; k < length; k++)
parms[k] = Object.class;
generateMethod(cfw, adapterName, id, parms, Object.class);
}
ByteArrayOutputStream out = new ByteArrayOutputStream(512);
try {
cfw.write(out);
}
catch (IOException ioe) {
throw new RuntimeException("unexpected IOException");
}
byte[] bytes = out.toByteArray();
if (nameHelper != null)
{
if (nameHelper.getGeneratingDirectory() != null) {
try {
int lastDot = adapterName.lastIndexOf('.');
if (lastDot != -1)
adapterName = adapterName.substring(lastDot+1);
String filename = nameHelper.getTargetClassFileName(adapterName);
FileOutputStream file = new FileOutputStream(filename);
file.write(bytes);
file.close();
}
catch (IOException iox) {
throw WrappedException.wrapException(iox);
}
return null;
} else {
try {
ClassOutput classOutput = nameHelper.getClassOutput();
if (classOutput != null) {
OutputStream cOut =
classOutput.getOutputStream(adapterName);
cOut.write(bytes);
cOut.close();
}
} catch (IOException iox) {
throw WrappedException.wrapException(iox);
}
}
}
SecuritySupport ss = cx.getSecuritySupport();
if (ss != null) {
Object securityDomain = cx.getSecurityDomainForStackDepth(-1);
return ss.defineClass(adapterName, bytes, securityDomain);
} else {
if (classLoader == null)
classLoader = new MyClassLoader();
classLoader.defineClass(adapterName, bytes);
return classLoader.loadClass(adapterName, true);
}
}
/**
* Utility method, which dynamically binds a Context to the current thread,
* if none already exists.
*/
public static Object callMethod(Scriptable object, String methodId,
Object[] args)
{
if (object.has(methodId, object)) {
try {
Context cx = Context.enter();
Object fun = object.get(methodId, object);
return ScriptRuntime.call(cx, fun, object, args, object);
} catch (JavaScriptException ex) {
// TODO: could occur
} finally {
Context.exit();
}
}
return Context.getUndefinedValue();
}
public static Scriptable toObject(Object value, Scriptable scope,
Class staticType)
{
Context.enter();
try {
return Context.toObject(value, scope, staticType);
} finally {
Context.exit();
}
}
private static void generateCtor(ClassFileWriter cfw, String adapterName,
String superName)
{
cfw.startMethod("<init>",
"(Lorg/mozilla/javascript/Scriptable;)V",
ClassFileWriter.ACC_PUBLIC);
// Invoke base class constructor
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESPECIAL, superName, "<init>", "()", "V");
// Save parameter in instance variable "self"
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // first arg
cfw.add(ByteCode.PUTFIELD, adapterName, "self",
"Lorg/mozilla/javascript/Scriptable;");
// Set the prototype of the js object to be a LiveConnect
// wrapper of the generated class's object
cfw.add(ByteCode.ALOAD_1); // first arg
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"setAdapterProto",
"(Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/Object;)",
"V");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)20, null); // TODO: magic number "20"
}
private static void generateEmptyCtor(ClassFileWriter cfw, String adapterName,
String superName, String scriptClassName)
{
cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC);
// Invoke base class constructor
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESPECIAL, superName, "<init>", "()", "V");
// Load script class
cfw.add(ByteCode.NEW, scriptClassName);
cfw.add(ByteCode.DUP);
cfw.add(ByteCode.INVOKESPECIAL, scriptClassName, "<init>", "()", "V");
// Run script and save resulting scope
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"runScript",
"(Lorg/mozilla/javascript/Script;)",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.ASTORE_1);
// Save the Scriptable in instance variable "self"
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.ALOAD_1); // the Scriptable
cfw.add(ByteCode.PUTFIELD, adapterName, "self",
"Lorg/mozilla/javascript/Scriptable;");
// Set the prototype of the js object to be a LiveConnect
// wrapper of the generated class's object
cfw.add(ByteCode.ALOAD_1); // the Scriptable
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"setAdapterProto",
"(Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/Object;)",
"V");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)20, null); // TODO: magic number "20"
}
/**
* Generates code to create a java.lang.Boolean, java.lang.Character or a
* java.lang.Double to wrap the specified primitive parameter. Leaves the
* wrapper object on the top of the stack.
*/
private static int generateWrapParam(ClassFileWriter cfw, int paramOffset,
Class paramType)
{
if (paramType.equals(Boolean.TYPE)) {
// wrap boolean values with java.lang.Boolean.
cfw.add(ByteCode.NEW, "java/lang/Boolean");
cfw.add(ByteCode.DUP);
cfw.add(ByteCode.ILOAD, paramOffset++);
cfw.add(ByteCode.INVOKESPECIAL, "java/lang/Boolean",
"<init>", "(Z)", "V");
} else
if (paramType.equals(Character.TYPE)) {
// Create a string of length 1 using the character parameter.
cfw.add(ByteCode.NEW, "java/lang/String");
cfw.add(ByteCode.DUP);
cfw.add(ByteCode.ICONST_1);
cfw.add(ByteCode.NEWARRAY, ByteCode.T_CHAR);
cfw.add(ByteCode.DUP);
cfw.add(ByteCode.ICONST_0);
cfw.add(ByteCode.ILOAD, paramOffset++);
cfw.add(ByteCode.CASTORE);
cfw.add(ByteCode.INVOKESPECIAL, "java/lang/String",
"<init>", "([C)", "V");
} else {
// convert all numeric values to java.lang.Double.
cfw.add(ByteCode.NEW, "java/lang/Double");
cfw.add(ByteCode.DUP);
String typeName = paramType.getName();
switch (typeName.charAt(0)) {
case 'b':
case 's':
case 'i':
// load an int value, convert to double.
cfw.add(ByteCode.ILOAD, paramOffset++);
cfw.add(ByteCode.I2D);
break;
case 'l':
// load a long, convert to double.
cfw.add(ByteCode.LLOAD, paramOffset);
cfw.add(ByteCode.L2D);
paramOffset += 2;
break;
case 'f':
// load a float, convert to double.
cfw.add(ByteCode.FLOAD, paramOffset++);
cfw.add(ByteCode.F2D);
break;
case 'd':
cfw.add(ByteCode.DLOAD, paramOffset);
paramOffset += 2;
break;
}
cfw.add(ByteCode.INVOKESPECIAL, "java/lang/Double",
"<init>", "(D)", "V");
}
return paramOffset;
}
/**
* Generates code to convert a wrapped value type to a primitive type.
* Handles unwrapping java.lang.Boolean, and java.lang.Number types.
* May need to map between char and java.lang.String as well.
* Generates the appropriate RETURN bytecode.
*/
private static void generateReturnResult(ClassFileWriter cfw,
Class retType)
{
// wrap boolean values with java.lang.Boolean, convert all other
// primitive values to java.lang.Double.
if (retType.equals(Boolean.TYPE)) {
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/Context",
"toBoolean", "(Ljava/lang/Object;)",
"Z");
cfw.add(ByteCode.IRETURN);
} else if (retType.equals(Character.TYPE)) {
// characters are represented as strings in JavaScript.
// return the first character.
// first convert the value to a string if possible.
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/Context",
"toString", "(Ljava/lang/Object;)",
"Ljava/lang/String;");
cfw.add(ByteCode.ICONST_0);
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/String", "charAt",
"(I)", "C");
cfw.add(ByteCode.IRETURN);
} else if (retType.isPrimitive()) {
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/Context",
"toNumber", "(Ljava/lang/Object;)",
"D");
String typeName = retType.getName();
switch (typeName.charAt(0)) {
case 'b':
case 's':
case 'i':
cfw.add(ByteCode.D2I);
cfw.add(ByteCode.IRETURN);
break;
case 'l':
cfw.add(ByteCode.D2L);
cfw.add(ByteCode.LRETURN);
break;
case 'f':
cfw.add(ByteCode.D2F);
cfw.add(ByteCode.FRETURN);
break;
case 'd':
cfw.add(ByteCode.DRETURN);
break;
default:
throw new RuntimeException("Unexpected return type " +
retType.toString());
}
} else {
String retTypeStr = retType.getName();
cfw.addLoadConstant(retTypeStr);
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/JavaAdapter",
"convertResult",
"(Ljava/lang/Object;" +
"Ljava/lang/String;)",
"Ljava/lang/Object;");
// Now cast to return type
cfw.add(ByteCode.CHECKCAST, retTypeStr.replace('.', '/'));
cfw.add(ByteCode.ARETURN);
}
}
private static void generateMethod(ClassFileWriter cfw, String genName,
String methodName, Class[] parms,
Class returnType)
{
StringBuffer sb = new StringBuffer();
sb.append('(');
short arrayLocal = 1; // includes this.
for (int i = 0; i < parms.length; i++) {
Class type = parms[i];
appendTypeString(sb, type);
if (type.equals(Long.TYPE) || type.equals(Double.TYPE))
arrayLocal += 2;
else
arrayLocal += 1;
}
sb.append(')');
appendTypeString(sb, returnType);
String methodSignature = sb.toString();
// System.out.println("generating " + m.getName() + methodSignature);
// System.out.flush();
cfw.startMethod(methodName, methodSignature,
ClassFileWriter.ACC_PUBLIC);
cfw.add(ByteCode.BIPUSH, (byte) parms.length); // > 255 parms?
cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
cfw.add(ByteCode.ASTORE, arrayLocal);
// allocate a local variable to store the scope used to wrap native objects.
short scopeLocal = (short) (arrayLocal + 1);
boolean loadedScope = false;
int paramOffset = 1;
for (int i = 0; i < parms.length; i++) {
cfw.add(ByteCode.ALOAD, arrayLocal);
cfw.add(ByteCode.BIPUSH, i);
if (parms[i].isPrimitive()) {
paramOffset = generateWrapParam(cfw, paramOffset, parms[i]);
} else {
// An arbitary Java object; call Context.toObject to wrap in
// a Scriptable object
cfw.add(ByteCode.ALOAD, paramOffset++);
if (! loadedScope) {
// load this.self into a local the first time it's needed.
// it will provide the scope needed by Context.toObject().
cfw.add(ByteCode.ALOAD_0);
cfw.add(ByteCode.GETFIELD, genName, "self",
"Lorg/mozilla/javascript/Scriptable;");
cfw.add(ByteCode.ASTORE, scopeLocal);
loadedScope = true;
}
cfw.add(ByteCode.ALOAD, scopeLocal);
// Get argument Class
cfw.addLoadConstant(parms[i].getName());
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/ScriptRuntime",
"loadClassName",
"(Ljava/lang/String;)",
"Ljava/lang/Class;");
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/JavaAdapter",
"toObject",
"(Ljava/lang/Object;" +
"Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/Class;)",
"Lorg/mozilla/javascript/Scriptable;");
}
cfw.add(ByteCode.AASTORE);
}
cfw.add(ByteCode.ALOAD_0); // this
cfw.add(ByteCode.GETFIELD, genName, "self",
"Lorg/mozilla/javascript/Scriptable;");
cfw.addLoadConstant(methodName);
cfw.add(ByteCode.ALOAD, arrayLocal);
// go through utility method, which creates a Context to run the
// method in.
cfw.add(ByteCode.INVOKESTATIC,
"org/mozilla/javascript/JavaAdapter",
"callMethod",
"(Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/String;[Ljava/lang/Object;)",
"Ljava/lang/Object;");
Class retType = returnType;
if (retType.equals(Void.TYPE)) {
cfw.add(ByteCode.POP);
cfw.add(ByteCode.RETURN);
} else {
generateReturnResult(cfw, retType);
}
cfw.stopMethod((short)(scopeLocal + 1), null);
}
/**
* Generates code to push typed parameters onto the operand stack
* prior to a direct Java method call.
*/
private static int generatePushParam(ClassFileWriter cfw, int paramOffset,
Class paramType)
{
String typeName = paramType.getName();
switch (typeName.charAt(0)) {
case 'z':
case 'b':
case 'c':
case 's':
case 'i':
// load an int value, convert to double.
cfw.add(ByteCode.ILOAD, paramOffset++);
break;
case 'l':
// load a long, convert to double.
cfw.add(ByteCode.LLOAD, paramOffset);
paramOffset += 2;
break;
case 'f':
// load a float, convert to double.
cfw.add(ByteCode.FLOAD, paramOffset++);
break;
case 'd':
cfw.add(ByteCode.DLOAD, paramOffset);
paramOffset += 2;
break;
}
return paramOffset;
}
/**
* Generates code to return a Java type, after calling a Java method
* that returns the same type.
* Generates the appropriate RETURN bytecode.
*/
private static void generatePopResult(ClassFileWriter cfw,
Class retType)
{
if (retType.isPrimitive()) {
String typeName = retType.getName();
switch (typeName.charAt(0)) {
case 'b':
case 'c':
case 's':
case 'i':
case 'z':
cfw.add(ByteCode.IRETURN);
break;
case 'l':
cfw.add(ByteCode.LRETURN);
break;
case 'f':
cfw.add(ByteCode.FRETURN);
break;
case 'd':
cfw.add(ByteCode.DRETURN);
break;
}
} else {
cfw.add(ByteCode.ARETURN);
}
}
/**
* Generates a method called "super$methodName()" which can be called
* from JavaScript that is equivalent to calling "super.methodName()"
* from Java. Eventually, this may be supported directly in JavaScript.
*/
private static void generateSuper(ClassFileWriter cfw,
String genName, String superName,
String methodName, String methodSignature,
Class[] parms, Class returnType)
{
cfw.startMethod("super$" + methodName, methodSignature,
ClassFileWriter.ACC_PUBLIC);
// push "this"
cfw.add(ByteCode.ALOAD, 0);
// push the rest of the parameters.
int paramOffset = 1;
for (int i = 0; i < parms.length; i++) {
if (parms[i].isPrimitive()) {
paramOffset = generatePushParam(cfw, paramOffset, parms[i]);
} else {
cfw.add(ByteCode.ALOAD, paramOffset++);
}
}
// split the method signature at the right parentheses.
int rightParen = methodSignature.indexOf(')');
// call the superclass implementation of the method.
cfw.add(ByteCode.INVOKESPECIAL,
superName,
methodName,
methodSignature.substring(0, rightParen + 1),
methodSignature.substring(rightParen + 1));
// now, handle the return type appropriately.
Class retType = returnType;
if (!retType.equals(Void.TYPE)) {
generatePopResult(cfw, retType);
} else {
cfw.add(ByteCode.RETURN);
}
cfw.stopMethod((short)(paramOffset + 1), null);
}
/**
* Returns a fully qualified method name concatenated with its signature.
*/
private static String getMethodSignature(Method method) {
Class[] parms = method.getParameterTypes();
StringBuffer sb = new StringBuffer();
sb.append('(');
for (int i = 0; i < parms.length; i++) {
Class type = parms[i];
appendTypeString(sb, type);
}
sb.append(')');
appendTypeString(sb, method.getReturnType());
return sb.toString();
}
private static StringBuffer appendTypeString(StringBuffer sb, Class type)
{
while (type.isArray()) {
sb.append('[');
type = type.getComponentType();
}
if (type.isPrimitive()) {
if (type.equals(Boolean.TYPE)) {
sb.append('Z');
} else
if (type.equals(Long.TYPE)) {
sb.append('J');
} else {
String typeName = type.getName();
sb.append(Character.toUpperCase(typeName.charAt(0)));
}
} else {
sb.append('L');
sb.append(type.getName().replace('.', '/'));
sb.append(';');
}
return sb;
}
static final class MyClassLoader extends ClassLoader {
public Class defineClass(String name, byte data[]) {
return super.defineClass(name, data, 0, data.length);
}
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class clazz = findLoadedClass(name);
if (clazz == null) {
ClassLoader loader = getClass().getClassLoader();
try {
if (loader != null)
return loader.loadClass(name);
clazz = findSystemClass(name);
} catch (ClassNotFoundException e) {
return ScriptRuntime.loadClassName(name);
}
}
if (resolve)
resolveClass(clazz);
return clazz;
}
}
/**
* Provides a key with which to distinguish previously generated
* adapter classes stored in a hash table.
*/
static class ClassSignature {
Class mSuperClass;
Class[] mInterfaces;
Object[] mProperties;
ClassSignature(Class superClass, Class[] interfaces, Scriptable jsObj) {
mSuperClass = superClass;
mInterfaces = interfaces;
mProperties = jsObj.getIds();
}
public boolean equals(Object obj) {
if (obj instanceof ClassSignature) {
ClassSignature sig = (ClassSignature) obj;
if (mSuperClass == sig.mSuperClass) {
Class[] interfaces = sig.mInterfaces;
if (mInterfaces != interfaces) {
if (mInterfaces == null || interfaces == null)
return false;
if (mInterfaces.length != interfaces.length)
return false;
for (int i = 0; i < interfaces.length; i++)
if (mInterfaces[i] != interfaces[i])
return false;
}
Object[] properties = sig.mProperties;
if (mProperties.length != properties.length)
return false;
for (int i = 0; i < properties.length; i++)
if (!mProperties[i].equals(properties[i]))
return false;
return true;
}
}
return false;
}
public int hashCode() {
return mSuperClass.hashCode();
}
}
private static int serial;
private static MyClassLoader classLoader;
private static Hashtable generatedClasses = new Hashtable(7);
}

View File

@@ -1,595 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Frank Mitchell
* Mike Shaver
* Kurt Westerfeld
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Enumeration;
/**
*
* @author Mike Shaver
* @author Norris Boyd
* @see NativeJavaObject
* @see NativeJavaClass
*/
class JavaMembers {
JavaMembers(Scriptable scope, Class cl) {
this.members = new Hashtable(23);
this.staticMembers = new Hashtable(7);
this.cl = cl;
reflect(scope, cl);
}
boolean has(String name, boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
Object obj = ht.get(name);
if (obj != null) {
return true;
} else {
Member member = this.findExplicitFunction(name, isStatic);
return member != null;
}
}
Object get(Scriptable scope, String name, Object javaObject,
boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (!isStatic && member == null) {
// Try to get static member from instance (LC3)
member = staticMembers.get(name);
}
if (member == null) {
member = this.getExplicitFunction(scope, name,
javaObject, isStatic);
if (member == null)
return Scriptable.NOT_FOUND;
}
if (member instanceof Scriptable)
return member; // why is this here?
Object rval;
Class type;
try {
if (member instanceof BeanProperty) {
BeanProperty bp = (BeanProperty) member;
rval = bp.getter.invoke(javaObject, ScriptRuntime.emptyArgs);
type = bp.getter.getReturnType();
} else {
Field field = (Field) member;
rval = field.get(isStatic ? null : javaObject);
type = field.getType();
}
} catch (IllegalAccessException accEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
} catch (InvocationTargetException e) {
throw new WrappedException(e.getTargetException());
}
// Need to wrap the object before we return it.
scope = ScriptableObject.getTopLevelScope(scope);
return NativeJavaObject.wrap(scope, rval, type);
}
Member findExplicitFunction(String name, boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
int sigStart = name.indexOf('(');
Member[] methodsOrCtors = null;
NativeJavaMethod method = null;
boolean isCtor = (isStatic && sigStart == 0);
if (isCtor) {
// Explicit request for an overloaded constructor
methodsOrCtors = ctors;
}
else if (sigStart > 0) {
// Explicit request for an overloaded method
String trueName = name.substring(0,sigStart);
Object obj = ht.get(trueName);
if (!isStatic && obj == null) {
// Try to get static member from instance (LC3)
obj = staticMembers.get(trueName);
}
if (obj != null && obj instanceof NativeJavaMethod) {
method = (NativeJavaMethod)obj;
methodsOrCtors = method.getMethods();
}
}
if (methodsOrCtors != null) {
for (int i = 0; i < methodsOrCtors.length; i++) {
String nameWithSig =
NativeJavaMethod.signature(methodsOrCtors[i]);
if (name.equals(nameWithSig)) {
return methodsOrCtors[i];
}
}
}
return null;
}
Object getExplicitFunction(Scriptable scope, String name,
Object javaObject, boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = null;
Member methodOrCtor = this.findExplicitFunction(name, isStatic);
if (methodOrCtor != null) {
Scriptable prototype =
ScriptableObject.getFunctionPrototype(scope);
if (methodOrCtor instanceof Constructor) {
NativeJavaConstructor fun =
new NativeJavaConstructor((Constructor)methodOrCtor);
fun.setPrototype(prototype);
member = fun;
ht.put(name, fun);
} else {
String trueName = methodOrCtor.getName();
member = ht.get(trueName);
if (member instanceof NativeJavaMethod &&
((NativeJavaMethod)member).getMethods().length > 1 ) {
NativeJavaMethod fun =
new NativeJavaMethod((Method)methodOrCtor, name);
fun.setPrototype(prototype);
ht.put(name, fun);
member = fun;
}
}
}
return member;
}
public void put(String name, Object javaObject, Object value,
boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (!isStatic && member == null) {
// Try to get static member from instance (LC3)
member = staticMembers.get(name);
}
if (member == null)
throw reportMemberNotFound(name);
if (member instanceof FieldAndMethods) {
FieldAndMethods fam = (FieldAndMethods) ht.get(name);
member = fam.getField();
}
// Is this a bean property "set"?
if (member instanceof BeanProperty) {
try {
Method method = ((BeanProperty) member).setter;
if (method == null)
throw reportMemberNotFound(name);
Class[] types = method.getParameterTypes();
Object[] params = { NativeJavaObject.coerceType(types[0], value) };
method.invoke(javaObject, params);
} catch (IllegalAccessException accessEx) {
throw new RuntimeException("unexpected IllegalAccessException " +
"accessing Java field");
} catch (InvocationTargetException e) {
throw new WrappedException(e.getTargetException());
}
}
else {
Field field = null;
try {
field = (Field) member;
if (field == null) {
Object[] args = {name};
throw Context.reportRuntimeError(
Context.getMessage("msg.java.internal.private", args));
}
field.set(javaObject, NativeJavaObject.coerceType(field.getType(),
value));
} catch (ClassCastException e) {
Object errArgs[] = { name };
throw Context.reportRuntimeError(Context.getMessage
("msg.java.method.assign",
errArgs));
} catch (IllegalAccessException accessEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
} catch (IllegalArgumentException argEx) {
Object errArgs[] = { value.getClass().getName(), field,
javaObject.getClass().getName() };
throw Context.reportRuntimeError(Context.getMessage(
"msg.java.internal.field.type", errArgs));
}
}
}
Object[] getIds(boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
int len = ht.size();
Object[] result = new Object[len];
Enumeration keys = ht.keys();
for (int i=0; i < len; i++)
result[i] = keys.nextElement();
return result;
}
Class getReflectedClass() {
return cl;
}
void reflectField(Scriptable scope, Field field) {
int mods = field.getModifiers();
if (!Modifier.isPublic(mods))
return;
boolean isStatic = Modifier.isStatic(mods);
Hashtable ht = isStatic ? staticMembers : members;
String name = field.getName();
Object member = ht.get(name);
if (member != null) {
if (member instanceof NativeJavaMethod) {
NativeJavaMethod method = (NativeJavaMethod) member;
FieldAndMethods fam = new FieldAndMethods(method.getMethods(),
field,
null);
fam.setPrototype(ScriptableObject.getFunctionPrototype(scope));
getFieldAndMethodsTable(isStatic).put(name, fam);
ht.put(name, fam);
return;
}
if (member instanceof Field) {
Field oldField = (Field) member;
// If this newly reflected field shadows an inherited field,
// then replace it. Otherwise, since access to the field
// would be ambiguous from Java, no field should be reflected.
// For now, the first field found wins, unless another field
// explicitly shadows it.
if (oldField.getDeclaringClass().isAssignableFrom(field.getDeclaringClass()))
ht.put(name, field);
return;
}
throw new RuntimeException("unknown member type");
}
ht.put(name, field);
}
void reflectMethod(Scriptable scope, Method method) {
int mods = method.getModifiers();
if (!Modifier.isPublic(mods))
return;
boolean isStatic = Modifier.isStatic(mods);
Hashtable ht = isStatic ? staticMembers : members;
String name = method.getName();
NativeJavaMethod fun = (NativeJavaMethod) ht.get(name);
if (fun == null) {
fun = new NativeJavaMethod();
if (scope != null)
fun.setPrototype(ScriptableObject.getFunctionPrototype(scope));
ht.put(name, fun);
fun.add(method);
} else {
fun.add(method);
}
}
void reflect(Scriptable scope, Class cl) {
// We reflect methods first, because we want overloaded field/method
// names to be allocated to the NativeJavaMethod before the field
// gets in the way.
Method[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++)
reflectMethod(scope, methods[i]);
Field[] fields = cl.getFields();
for (int i = 0; i < fields.length; i++)
reflectField(scope, fields[i]);
makeBeanProperties(scope, false);
makeBeanProperties(scope, true);
ctors = cl.getConstructors();
}
Hashtable getFieldAndMethodsTable(boolean isStatic) {
Hashtable fmht = isStatic ? staticFieldAndMethods
: fieldAndMethods;
if (fmht == null) {
fmht = new Hashtable(11);
if (isStatic)
staticFieldAndMethods = fmht;
else
fieldAndMethods = fmht;
}
return fmht;
}
void makeBeanProperties(Scriptable scope, boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
Hashtable toAdd = new Hashtable();
// Now, For each member, make "bean" properties.
for (Enumeration e = ht.keys(); e.hasMoreElements(); ) {
// Is this a getter?
String name = (String) e.nextElement();
boolean memberIsGetMethod = name.startsWith("get");
boolean memberIsIsMethod = name.startsWith("is");
if (memberIsGetMethod || memberIsIsMethod) {
// Double check name component.
String nameComponent = name.substring(memberIsGetMethod ? 3 : 2);
if (nameComponent.length() == 0)
continue;
// Make the bean property name.
String beanPropertyName = nameComponent;
if (nameComponent.length() > 1 &&
Character.isUpperCase(nameComponent.charAt(0)) &&
!Character.isUpperCase(nameComponent.charAt(1)))
{
beanPropertyName = Character.toLowerCase(nameComponent.charAt(0)) +
nameComponent.substring(1);
}
// If we already have a member by this name, don't do this
// property.
if (ht.containsKey(beanPropertyName))
continue;
// Get the method by this name.
Object method = ht.get(name);
if (!(method instanceof NativeJavaMethod))
continue;
NativeJavaMethod getJavaMethod = (NativeJavaMethod) method;
// Grab and inspect the getter method; does it have an empty parameter list,
// with a return value (eg. a getSomething() or isSomething())?
Class[] params;
Method[] getMethods = getJavaMethod.getMethods();
Class type;
if (getMethods != null &&
getMethods.length == 1 &&
(type = getMethods[0].getReturnType()) != null &&
(params = getMethods[0].getParameterTypes()) != null &&
params.length == 0)
{
// Make sure the method static-ness is preserved for this property.
if (isStatic && !Modifier.isStatic(getMethods[0].getModifiers()))
continue;
// We have a getter. Now, do we have a setter?
Method setMethod = null;
String setter = "set" + nameComponent;
if (ht.containsKey(setter)) {
// Is this value a method?
method = ht.get(setter);
if (method instanceof NativeJavaMethod) {
//
// Note: it may be preferable to allow NativeJavaMethod.findFunction()
// to find the appropriate setter; unfortunately, it requires an
// instance of the target arg to determine that.
//
// Make two passes: one to find a method with direct type assignment,
// and one to find a widening conversion.
NativeJavaMethod setJavaMethod = (NativeJavaMethod) method;
Method[] setMethods = setJavaMethod.getMethods();
for (int pass = 1; pass <= 2 && setMethod == null; ++pass) {
for (int i = 0; i < setMethods.length; ++i) {
if (setMethods[i].getReturnType() == void.class &&
(!isStatic || Modifier.isStatic(setMethods[i].getModifiers())) &&
(params = setMethods[i].getParameterTypes()) != null &&
params.length == 1 ) {
if ((pass == 1 && params[0] == type) ||
(pass == 2 && params[0].isAssignableFrom(type))) {
setMethod = setMethods[i];
break;
}
}
}
}
}
}
// Make the property.
BeanProperty bp = new BeanProperty(getMethods[0], setMethod);
toAdd.put(beanPropertyName, bp);
}
}
}
// Add the new bean properties.
for (Enumeration e = toAdd.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
Object value = toAdd.get(key);
ht.put(key, value);
}
}
Hashtable getFieldAndMethodsObjects(Scriptable scope, Object javaObject,
boolean isStatic)
{
Hashtable ht = isStatic ? staticFieldAndMethods : fieldAndMethods;
if (ht == null)
return null;
int len = ht.size();
Hashtable result = new Hashtable(Math.max(len,1));
Enumeration e = ht.elements();
while (len-- > 0) {
FieldAndMethods fam = (FieldAndMethods) e.nextElement();
fam = (FieldAndMethods) fam.clone();
fam.setJavaObject(javaObject);
result.put(fam.getName(), fam);
}
return result;
}
Constructor[] getConstructors() {
return ctors;
}
static JavaMembers lookupClass(Scriptable scope, Class dynamicType,
Class staticType)
{
Class cl = dynamicType;
Hashtable ct = classTable; // use local reference to avoid synchronize
JavaMembers members = (JavaMembers) ct.get(cl);
if (members != null)
return members;
if (staticType != null && staticType != dynamicType &&
!Modifier.isPublic(dynamicType.getModifiers()) &&
Modifier.isPublic(staticType.getModifiers()))
{
cl = staticType;
// We can use the static type, and that is OK, but we'll trace
// back the java class chain here to look for something more suitable.
for (Class parentType = dynamicType;
parentType != null && parentType != ScriptRuntime.ObjectClass;
parentType = parentType.getSuperclass())
{
if (Modifier.isPublic(parentType.getModifiers())) {
cl = parentType;
break;
}
}
}
try {
members = new JavaMembers(scope, cl);
} catch (SecurityException e) {
// Reflection may fail for objects that are in a restricted
// access package (e.g. sun.*). If we get a security
// exception, try again with the static type. Otherwise,
// rethrow the exception.
if (cl != staticType)
members = new JavaMembers(scope, staticType);
else
throw e;
}
if (Context.isCachingEnabled)
ct.put(cl, members);
return members;
}
RuntimeException reportMemberNotFound(String memberName) {
Object errArgs[] = { cl.getName(),
memberName };
return Context.reportRuntimeError(
Context.getMessage("msg.java.member.not.found",
errArgs));
}
static Hashtable classTable = new Hashtable();
private Class cl;
private Hashtable members;
private Hashtable fieldAndMethods;
private Hashtable staticMembers;
private Hashtable staticFieldAndMethods;
private Constructor[] ctors;
}
class BeanProperty {
BeanProperty(Method getter, Method setter) {
this.getter = getter;
this.setter = setter;
}
Method getter;
Method setter;
}
class FieldAndMethods extends NativeJavaMethod {
FieldAndMethods(Method[] methods, Field field, String name) {
super(methods);
this.field = field;
this.name = name;
}
void setJavaObject(Object javaObject) {
this.javaObject = javaObject;
}
String getName() {
if (field == null)
return name;
return field.getName();
}
Field getField() {
return field;
}
public Object getDefaultValue(Class hint) {
if (hint == ScriptRuntime.FunctionClass)
return this;
Object rval;
Class type;
try {
rval = field.get(javaObject);
type = field.getType();
} catch (IllegalAccessException accEx) {
Object[] args = {getName()};
throw Context.reportRuntimeError(Context.getMessage
("msg.java.internal.private", args));
}
rval = NativeJavaObject.wrap(this, rval, type);
if (rval instanceof Scriptable) {
rval = ((Scriptable) rval).getDefaultValue(hint);
}
return rval;
}
public Object clone() {
FieldAndMethods result = new FieldAndMethods(methods, field, name);
result.javaObject = javaObject;
return result;
}
private Field field;
private Object javaObject;
private String name;
}

View File

@@ -1,109 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
// API class
package org.mozilla.javascript;
import java.lang.reflect.InvocationTargetException;
/**
* Java reflection of JavaScript exceptions. (Possibly wrapping a Java exception.)
*
* @author Mike McCabe
*/
public class JavaScriptException extends Exception {
/**
* Create a JavaScript exception wrapping the given JavaScript value.
*
* Instances of this class are thrown by the JavaScript 'throw' keyword.
*
* @param value the JavaScript value thrown.
*/
public JavaScriptException(Object value) {
super(ScriptRuntime.toString(value));
this.value = value;
}
/**
* Get the exception message.
*
* <p>Will just convert the wrapped exception to a string.
*/
public String getMessage() {
return ScriptRuntime.toString(value);
}
static JavaScriptException wrapException(Scriptable scope,
Throwable exn)
{
if (exn instanceof InvocationTargetException)
exn = ((InvocationTargetException)exn).getTargetException();
if (exn instanceof JavaScriptException)
return (JavaScriptException)exn;
Object wrapper = NativeJavaObject.wrap(scope, exn, Throwable.class);
return new JavaScriptException(wrapper);
}
/**
* Get the exception value originally thrown. This may be a
* JavaScript value (null, undefined, Boolean, Number, String,
* Scriptable or Function) or a Java exception value thrown from a
* host object or from Java called through LiveConnect.
*
* @return the value wrapped by this exception
*/
public Object getValue() {
if (value != null && value instanceof Wrapper)
// this will also catch NativeStrings...
return ((Wrapper)value).unwrap();
else
return value;
}
/**
* The JavaScript exception value. This value is not
* intended for general use; if the JavaScriptException wraps a
* Java exception, getScriptableValue may return a Scriptable
* wrapping the original Java exception object.
*
* We would prefer to go through a getter to encapsulate the value,
* however that causes the bizarre error "nanosecond timeout value
* out of range" on the MS JVM.
* @serial
*/
Object value;
}

View File

@@ -1,104 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
public class Label {
private static final int FIXUPTABLE_SIZE = 8;
private static final boolean DEBUG = true;
public Label()
{
itsPC = -1;
}
public short getPC()
{
return itsPC;
}
public void fixGotos(byte theCodeBuffer[])
{
if (DEBUG) {
if ((itsPC == -1) && (itsFixupTable != null))
throw new RuntimeException("Unlocated label");
}
if (itsFixupTable != null) {
for (int i = 0; i < itsFixupTableTop; i++) {
int fixupSite = itsFixupTable[i];
// -1 to get delta from instruction start
short offset = (short)(itsPC - (fixupSite - 1));
theCodeBuffer[fixupSite++] = (byte)(offset >> 8);
theCodeBuffer[fixupSite] = (byte)offset;
}
}
itsFixupTable = null;
}
public void setPC(short thePC)
{
if (DEBUG) {
if ((itsPC != -1) && (itsPC != thePC))
throw new RuntimeException("Duplicate label");
}
itsPC = thePC;
}
public void addFixup(int fixupSite)
{
if (itsFixupTable == null) {
itsFixupTableTop = 1;
itsFixupTable = new int[FIXUPTABLE_SIZE];
itsFixupTable[0] = fixupSite;
}
else {
if (itsFixupTableTop == itsFixupTable.length) {
int oldLength = itsFixupTable.length;
int newTable[] = new int[oldLength + FIXUPTABLE_SIZE];
System.arraycopy(itsFixupTable, 0, newTable, 0, oldLength);
itsFixupTable = newTable;
}
itsFixupTable[itsFixupTableTop++] = fixupSite;
}
}
private short itsPC;
private int itsFixupTable[];
private int itsFixupTableTop;
}

View File

@@ -1,80 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
public class LabelTable {
private static final boolean DEBUGLABELS = false;
private static final int LabelTableSize = 32;
protected Label itsLabelTable[];
protected int itsLabelTableTop;
public int acquireLabel()
{
if (itsLabelTable == null) {
itsLabelTable = new Label[LabelTableSize];
itsLabelTable[0] = new Label();
itsLabelTableTop = 1;
return 0x80000000;
}
else {
if (itsLabelTableTop == itsLabelTable.length) {
Label oldTable[] = itsLabelTable;
itsLabelTable = new Label[itsLabelTableTop * 2];
System.arraycopy(oldTable, 0, itsLabelTable, 0, itsLabelTableTop);
}
itsLabelTable[itsLabelTableTop] = new Label();
int result = itsLabelTableTop++;
return result | 0x80000000;
}
}
public int markLabel(int theLabel, int pc)
{
if (DEBUGLABELS) {
if ((theLabel & 0x80000000) != 0x80000000)
throw new RuntimeException("Bad label, no biscuit");
}
theLabel &= 0x7FFFFFFF;
if (DEBUGLABELS) {
System.out.println("Marking label " + theLabel + " at " + pc);
}
itsLabelTable[theLabel].setPC((short)pc);
return theLabel | 0x80000000;
}
}

View File

@@ -1,99 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
/**
* Avoid loading classes unless they are used.
*
* <p> This improves startup time and average memory usage.
*/
class LazilyLoadedCtor {
LazilyLoadedCtor(ScriptableObject scope, String ctorName,
String className, int attributes)
throws PropertyException
{
this.className = className;
this.ctorName = ctorName;
Class cl = getClass();
Method[] getter = FunctionObject.findMethods(cl, "getProperty");
Method[] setter = FunctionObject.findMethods(cl, "setProperty");
scope.defineProperty(this.ctorName, this, getter[0], setter[0],
attributes);
}
public Object getProperty(ScriptableObject obj) {
try {
synchronized (obj) {
if (!isReplaced)
ScriptableObject.defineClass(obj, Class.forName(className));
isReplaced = true;
}
}
catch (ClassNotFoundException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InvocationTargetException e) {
throw WrappedException.wrapException(e);
}
catch (ClassDefinitionException e) {
throw WrappedException.wrapException(e);
}
catch (PropertyException e) {
throw WrappedException.wrapException(e);
}
return obj.get(ctorName, obj);
}
public Object setProperty(ScriptableObject obj, Object val) {
synchronized (obj) {
isReplaced = true;
return val;
}
}
private String ctorName;
private String className;
private boolean isReplaced;
}

View File

@@ -1,412 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Mike McCabe
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.io.Reader;
import java.io.IOException;
/**
* An input buffer that combines fast character-based access with
* (slower) support for retrieving the text of the current line. It
* also supports building strings directly out of the internal buffer
* to support fast scanning with minimal object creation.
*
* Note that it is customized in several ways to support the
* TokenStream class, and should not be considered general.
*
* Credits to Kipp Hickman and John Bandhauer.
*
* @author Mike McCabe
*/
final class LineBuffer {
/*
* for smooth operation of getLine(), this should be greater than
* the length of any expected line. Currently, 256 is 3% slower
* than 4096 for large compiles, but seems safer given evaluateString.
* Strings for the scanner are are built with StringBuffers
* instead of directly out of the buffer whenever a string crosses
* a buffer boundary, so small buffer sizes will mean that more
* objects are created.
*/
static final int BUFLEN = 256;
LineBuffer(Reader in, int lineno) {
this.in = in;
this.lineno = lineno;
}
int read() throws IOException {
for(;;) {
if (end == offset && !fill())
return -1;
// Do only a bitmask + branch per character, at the cost of
// three branches per low-bits-only (or 2028/9) character.
if ((buffer[offset] & '\udfd0') == 0) {
if (buffer[offset] == '\r') {
// if the next character is a newline, skip past it.
if ((offset + 1) < end) {
if (buffer[offset + 1] == '\n')
offset++;
} else {
// set a flag for fill(), in case the first char of the
// next fill is a newline.
lastWasCR = true;
}
}
else
if ((buffer[offset] != '\n')
&& (buffer[offset] != '\u2028')
&& (buffer[offset] != '\u2029'))
{
if (Character.getType(buffer[offset])
== Character.FORMAT) {
hadCFSinceStringStart = true;
offset++;
continue;
}
return (int) buffer[offset++];
}
offset++;
prevStart = lineStart;
lineStart = offset;
lineno++;
return '\n';
}
if ((buffer[offset] >= 128)
&& (Character.getType(buffer[offset]) == Character.FORMAT)) {
hadCFSinceStringStart = true;
offset++;
}
else
break;
}
return (int) buffer[offset++];
}
void unread() {
if (offset == 0)
// We can get here when we're asked to unread() an
// implicit EOF_CHAR.
// This would also be wrong behavior in the general case,
// because a peek() could map a buffer.length offset to 0
// in the process of a fill(), and leave it there. But
// the scanner never calls peek() or a failed match()
// followed by unread()... this would violate 1-character
// lookahead. So we're OK.
return;
offset--;
if ((buffer[offset] & '\ufff0') == 0
&& (buffer[offset] == '\r' || buffer[offset] == '\n')) {
// back off from the line start we presumably just registered...
lineStart = prevStart;
lineno--;
}
}
int peek() throws IOException {
if (end == offset && !fill())
return -1;
if (buffer[offset] == '\r')
return '\n';
return buffer[offset];
}
boolean match(char c) throws IOException {
if (end == offset && !fill())
return false;
// This'd be a place where we'd need to map '\r' to '\n' and
// do other updates, but TokenStream never looks ahead for
// '\n', so we don't bother.
if (buffer[offset] == c) {
offset++;
return true;
}
return false;
}
// Reconstruct a source line from the buffers. This can be slow...
String getLine() {
StringBuffer result = new StringBuffer();
int start = lineStart;
if (start >= offset) {
// the line begins somewhere in the other buffer; get that first.
if (otherStart < otherEnd)
// if a line ending was seen in the other buffer... otherwise
// just ignore this strange case.
result.append(otherBuffer, otherStart,
otherEnd - otherStart);
start = 0;
}
// get the part of the line in the current buffer.
result.append(buffer, start, offset - start);
// Get the remainder of the line.
int i = offset;
while(true) {
if (i == buffer.length) {
// we're out of buffer, let's just expand it. We do
// this instead of reading into a StringBuffer to
// preserve the stream for later reads.
char[] newBuffer = new char[buffer.length * 2];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
int charsRead = 0;
try {
charsRead = in.read(buffer, end, buffer.length - end);
} catch (IOException ioe) {
// ignore it, we're already displaying an error...
}
if (charsRead < 0)
break;
end += charsRead;
}
if (buffer[i] == '\r' || buffer[i] == '\n')
break;
i++;
}
result.append(buffer, offset, i - offset);
return result.toString();
}
// Get the offset of the current character, relative to
// the line that getLine() returns.
int getOffset() {
if (lineStart >= offset)
// The line begins somewhere in the other buffer.
return offset + (otherEnd - otherStart);
else
return offset - lineStart;
}
// Set a mark to indicate that the reader should begin
// accumulating characters for getString(). The string begins
// with the last character read.
void startString() {
if (offset == 0) {
// We can get here if startString is called after a peek()
// or failed match() with offset past the end of the
// buffer.
// We're at the beginning of the buffer, and the previous character
// (which we want to include) is at the end of the last one, so
// we just go to StringBuffer mode.
stringSoFar = new StringBuffer();
stringSoFar.append(otherBuffer, otherEnd - 1, 1);
stringStart = -1; // Set sentinel value.
hadCFSinceStringStart = ((otherBuffer[otherEnd - 1] >= 128)
&& Character.getType(otherBuffer[otherEnd - 1])
== Character.FORMAT);
} else {
// Support restarting strings
stringSoFar = null;
stringStart = offset - 1;
hadCFSinceStringStart = ((buffer[stringStart] >= 128)
&& Character.getType(buffer[stringStart]) == Character.FORMAT);
}
}
// Get a string consisting of the characters seen since the last
// startString.
String getString() {
String result;
/*
* There's one strange case here: If the character offset currently
* points to (which we never want to include in the string) is
* a newline, then if the previous character is a carriage return,
* we probably want to exclude that as well. If the offset is 0,
* then we hope that fill() handled excluding it from stringSoFar.
*/
int loseCR = (offset > 0 &&
buffer[offset] == '\n' && buffer[offset - 1] == '\r') ?
1 : 0;
if (stringStart != -1) {
// String mark is valid, and in this buffer.
result = new String(buffer, stringStart,
offset - stringStart - loseCR);
} else {
if (stringSoFar == null)
stringSoFar = new StringBuffer();
// Exclude cr as well as nl of newline. If offset is 0, then
// hopefully fill() did the right thing.
result = (stringSoFar.append(buffer, 0, offset - loseCR)).toString();
}
stringStart = -1;
stringSoFar = null;
if (hadCFSinceStringStart) {
char c[] = result.toCharArray();
StringBuffer x = null;
for (int i = 0; i < c.length; i++) {
if (Character.getType(c[i]) == Character.FORMAT) {
if (x == null) {
x = new StringBuffer();
x.append(c, 0, i);
}
}
else
if (x != null) x.append(c[i]);
}
if (x != null) result = x.toString();
}
return result;
}
boolean fill() throws IOException {
// not sure I care...
if (end - offset != 0)
throw new IOException("fill of non-empty buffer");
// If there's a string currently being accumulated, save
// off the progress.
/*
* Exclude an end-of-buffer carriage return. NOTE this is not
* fully correct in the general case, because we really only
* want to exclude the carriage return if it's followed by a
* linefeed at the beginning of the next buffer. But we fudge
* because the scanner doesn't do this.
*/
int loseCR = (offset > 0 && lastWasCR) ? 1 : 0;
if (stringStart != -1) {
// The mark is in the current buffer, save off from the mark to the
// end.
stringSoFar = new StringBuffer();
stringSoFar.append(buffer, stringStart, end - stringStart - loseCR);
stringStart = -1;
} else if (stringSoFar != null) {
// the string began prior to the current buffer, so save the
// whole current buffer.
stringSoFar.append(buffer, 0, end - loseCR);
}
// swap buffers
char[] tempBuffer = buffer;
buffer = otherBuffer;
otherBuffer = tempBuffer;
// allocate the buffers lazily, in case we're handed a short string.
if (buffer == null) {
buffer = new char[BUFLEN];
}
// buffers have switched, so move the newline marker.
otherStart = lineStart;
otherEnd = end;
// set lineStart to a sentinel value, unless this is the first
// time around.
prevStart = lineStart = (otherBuffer == null) ? 0 : buffer.length + 1;
offset = 0;
end = in.read(buffer, 0, buffer.length);
if (end < 0) {
end = 0;
// can't null buffers here, because a string might be retrieved
// out of the other buffer, and a 0-length string might be
// retrieved out of this one.
hitEOF = true;
return false;
}
// If the last character of the previous fill was a carriage return,
// then ignore a newline.
// There's another bizzare special case here. If lastWasCR is
// true, and we see a newline, and the buffer length is
// 1... then we probably just read the last character of the
// file, and returning after advancing offset is not the right
// thing to do. Instead, we try to ignore the newline (and
// likely get to EOF for real) by doing yet another fill().
if (lastWasCR) {
if (buffer[0] == '\n') {
offset++;
if (end == 1)
return fill();
}
lineStart = offset;
lastWasCR = false;
}
return true;
}
int getLineno() { return lineno; }
boolean eof() { return hitEOF; }
private Reader in;
private char[] otherBuffer = null;
private char[] buffer = null;
// Yes, there are too too many of these.
private int offset = 0;
private int end = 0;
private int otherEnd;
private int lineno;
private int lineStart = 0;
private int otherStart = 0;
private int prevStart = 0;
private boolean lastWasCR = false;
private boolean hitEOF = false;
private int stringStart = -1;
private StringBuffer stringSoFar = null;
private boolean hadCFSinceStringStart = false;
}

View File

@@ -1,114 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is ListenerCollection, released
* May 15, 1998.
*
* The Initial Developer of the Original Code is Ian D. Stewart.
* Portions created by Ian D. Stewart are Copyright (C) 1998, 1999
* Ian D. Stewart.
* Rights Reserved.
*
* Contributor(s):
* Ian D. Stewart
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/* This class provides a series of methods for accessing event listeners. */
package org.mozilla.javascript;
import java.util.Enumeration;
import java.util.Vector;
/**
* This class acts as central storage location for miscelanious
* event listeners. It provides methods for adding, removing
* and accessing listeners, both individually and collectively,
* by the listener interface implemented
*
* Note: This class performs the same functions as
* javax.swing.event.EventListenerList, and is provided
* primarily for implementations lacking the Swing packages
*
* @author Ian D. Stewart
* @since JavaScript-Java 1.4 rel 3
*/
public class ListenerCollection extends Vector {
/**
* Create a new ListenerCollection
*/
public ListenerCollection() {
super();
} // Constructor
/**
* Add a new listener to the collection
* @param listener the listener
*/
public void addListener(Object listener) {
this.addElement(listener);
}
/**
* Remove a listener from the collection
* @param listener the listener
*/
public void removeListener(Object listener) {
this.removeElement(listener);
}
/**
* Returns an Enumeration of all the listeners
* being stored in this collection
* @return an Enumeration of all listeners
*/
public Enumeration getAllListeners() {
return this.elements();
}
/**
* Return all the listeners in this collection which
* implement the specified interface
*
* @param iface the interface
* @return an array of listeners which implement the given
* interface
*/
public Object[] getListeners(Class iface) {
Vector array = new Vector();
for(Enumeration enum = getAllListeners();enum.hasMoreElements();) {
Object listener = enum.nextElement();
if(iface.isInstance(listener)) {
array.addElement(listener);
}
}
Object[] result = new Object[array.size()];
array.copyInto(result);
return result;
}
} // ListenerCollection
// end of ListenerCollection.java ...

View File

@@ -1,79 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
public class LocalVariable {
public LocalVariable(String name, boolean isParameter) {
itsName = name;
itsIsParameter = isParameter;
}
public void setIndex(int index){ itsIndex = index; }
public int getIndex() { return itsIndex; }
public void setIsParameter() { itsIsParameter = true; }
public boolean isParameter() { return itsIsParameter; }
public String getName() { return itsName; }
/**
* Return the starting PC where this variable is live, or -1
* if it is not a Java register.
*/
public int getStartPC() {
return -1;
}
/**
* Return the Java register number or -1 if it is not a Java register.
*/
public short getJRegister() {
return -1;
}
/**
* Return true if the local variable is a Java register with double type.
*/
public boolean isNumber() {
return false;
}
private String itsName;
private int itsIndex = -1;
private boolean itsIsParameter;
}

View File

@@ -1,244 +0,0 @@
#! gmake
# The contents of this file are subject to the Netscape 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/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Rhino code, released
# May 6, 1998.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
# Makefile the core javascript classes.
#
# This Makefile is intended to be called from the toplevel Makefile.
#
# List files explicitly to exclude .java files in this dir we don't want
# to compile. Also hack in classfile stuff...
SOURCES = \
$(PATH_PREFIX)/Arguments.java \
$(PATH_PREFIX)/BinaryDigitReader.java \
$(PATH_PREFIX)/ClassDefinitionException.java \
$(PATH_PREFIX)/ClassNameHelper.java \
$(PATH_PREFIX)/Context.java \
$(PATH_PREFIX)/DeepBytecodeHook.java \
$(PATH_PREFIX)/DeepCallHook.java \
$(PATH_PREFIX)/DeepErrorReporterHook.java \
$(PATH_PREFIX)/DeepExecuteHook.java \
$(PATH_PREFIX)/DeepNewObjectHook.java \
$(PATH_PREFIX)/DeepScriptHook.java \
$(PATH_PREFIX)/DefaultErrorReporter.java \
$(PATH_PREFIX)/EcmaError.java \
$(PATH_PREFIX)/ErrorReporter.java \
$(PATH_PREFIX)/EvaluatorException.java \
$(PATH_PREFIX)/FlattenedObject.java \
$(PATH_PREFIX)/Function.java \
$(PATH_PREFIX)/FunctionNode.java \
$(PATH_PREFIX)/FunctionObject.java \
$(PATH_PREFIX)/IRFactory.java \
$(PATH_PREFIX)/ImporterTopLevel.java \
$(PATH_PREFIX)/InterpretedFunction.java \
$(PATH_PREFIX)/InterpretedScript.java \
$(PATH_PREFIX)/Interpreter.java \
$(PATH_PREFIX)/InterpreterData.java \
$(PATH_PREFIX)/JavaAdapter.java \
$(PATH_PREFIX)/JavaMembers.java \
$(PATH_PREFIX)/JavaScriptException.java \
$(PATH_PREFIX)/Label.java \
$(PATH_PREFIX)/LabelTable.java \
$(PATH_PREFIX)/LazilyLoadedCtor.java \
$(PATH_PREFIX)/LineBuffer.java \
$(PATH_PREFIX)/ListenerCollection.java \
$(PATH_PREFIX)/LocalVariable.java \
$(PATH_PREFIX)/NativeArray.java \
$(PATH_PREFIX)/NativeBoolean.java \
$(PATH_PREFIX)/NativeCall.java \
$(PATH_PREFIX)/NativeDate.java \
$(PATH_PREFIX)/NativeError.java \
$(PATH_PREFIX)/NativeFunction.java \
$(PATH_PREFIX)/NativeGlobal.java \
$(PATH_PREFIX)/NativeJavaArray.java \
$(PATH_PREFIX)/NativeJavaClass.java \
$(PATH_PREFIX)/NativeJavaConstructor.java \
$(PATH_PREFIX)/NativeJavaMethod.java \
$(PATH_PREFIX)/NativeJavaObject.java \
$(PATH_PREFIX)/NativeJavaPackage.java \
$(PATH_PREFIX)/NativeMath.java \
$(PATH_PREFIX)/NativeNumber.java \
$(PATH_PREFIX)/NativeObject.java \
$(PATH_PREFIX)/NativeScript.java \
$(PATH_PREFIX)/NativeString.java \
$(PATH_PREFIX)/NativeWith.java \
$(PATH_PREFIX)/Node.java \
$(PATH_PREFIX)/NodeTransformer.java \
$(PATH_PREFIX)/NotAFunctionException.java \
$(PATH_PREFIX)/Parser.java \
$(PATH_PREFIX)/PreorderNodeIterator.java \
$(PATH_PREFIX)/PropertyException.java \
$(PATH_PREFIX)/RegExpProxy.java \
$(PATH_PREFIX)/Script.java \
$(PATH_PREFIX)/ScriptRuntime.java \
$(PATH_PREFIX)/Scriptable.java \
$(PATH_PREFIX)/ScriptableObject.java \
$(PATH_PREFIX)/SecuritySupport.java \
$(PATH_PREFIX)/ShallowNodeIterator.java \
$(PATH_PREFIX)/SourceTextItem.java \
$(PATH_PREFIX)/SourceTextManager.java \
$(PATH_PREFIX)/TokenStream.java \
$(PATH_PREFIX)/Undefined.java \
$(PATH_PREFIX)/VariableTable.java \
$(PATH_PREFIX)/WrappedException.java \
$(PATH_PREFIX)/Wrapper.java \
$(PATH_PREFIX)/regexp/NativeRegExp.java \
$(PATH_PREFIX)/regexp/NativeRegExpCtor.java \
$(PATH_PREFIX)/regexp/RegExpImpl.java \
$(PATH_PREFIX)/regexp/SubString.java \
$(PATH_PREFIX)/optimizer/Block.java \
$(PATH_PREFIX)/optimizer/Codegen.java \
$(PATH_PREFIX)/optimizer/DataFlowBitSet.java \
$(PATH_PREFIX)/optimizer/FatBlock.java \
$(PATH_PREFIX)/optimizer/JavaScriptClassLoader.java\
$(PATH_PREFIX)/optimizer/OptClassNameHelper.java\
$(PATH_PREFIX)/optimizer/OptFunctionNode.java \
$(PATH_PREFIX)/optimizer/OptIRFactory.java \
$(PATH_PREFIX)/optimizer/OptLocalVariable.java \
$(PATH_PREFIX)/optimizer/OptRuntime.java \
$(PATH_PREFIX)/optimizer/OptTransformer.java \
$(PATH_PREFIX)/optimizer/OptVariableTable.java \
$(PATH_PREFIX)/optimizer/Optimizer.java \
$(PATH_PREFIX)/optimizer/StmtNodeIterator.java \
$(PATH_PREFIX)/optimizer/TypeEvent.java \
$(PATH_PREFIX)/../classfile/ByteCode.java \
$(PATH_PREFIX)/../classfile/ClassFileWriter.java\
$(NULL)
RESOURCEDIR = $(PATH_PREFIX)/resources
RESOURCES = $(RESOURCEDIR)/*.properties
# This must be evaluated in some context where the classes can be
# found; we can't use a simple translation from sources, because a
# .java file may produce more than one .class file.
# (use org/mozilla/classfile explicitly for now; should be replaced
# with something parameterized, but jar doesn't understand ..)
CLASSES = $(PATH_PREFIX)/*.class $(PATH_PREFIX)/regexp/*.class \
$(PATH_PREFIX)/optimizer/*.class org/mozilla/classfile/*.class
# A class or set of classes as visible from the top level. For want
# of ${subst ,,}. This variable is only used to trigger dependency
# analysis, and multiple words confuse gmake, so it can be smaller
# than the full set of sources. (We assume we'll never need to do the
# same thing with RESOURCES.)
TLCLASS = $(CLASSDIR)/$(PATH_PREFIX)/*.class
# An empty file, used mainly for timestamp/dependency purposes by
# "fast" builds
FASTTARGET=$(CLASSDIR)/.lastbuild
$(JAR) : $(TLCLASS) $(CLASSDIR)/$(RESOURCES)
cd $(CLASSDIR) ; \
jar cf ../$(JAR) $(CLASSES) $(RESOURCES)
$(TLCLASS) : $(SOURCES)
- mkdir -p $(CLASSDIR)
echo "" > $(FASTTARGET)
$(JAVAC) $(JFLAGS) -d $(CLASSDIR) $(SOURCES)
$(CLASSDIR)/$(RESOURCES) : $(RESOURCES)
- mkdir -p $(CLASSDIR)/$(RESOURCEDIR)
cp $(RESOURCES) $(CLASSDIR)/$(RESOURCEDIR)
# Since the jar file is a target for regular builds, "fast" builds use a
# dummy file, updated before each compilation to provide a timestamp.
# Even so, using a dummy file is far from foolproof, so we still need
# the regular build.
fast: $(FASTTARGET)
# So that we recompile only the files that have changed, we pretend
# the only real dependencies are the source files, and recopy the
# resources every time. Right now (14 Jun 99), the only resource is
# Messages.properties, so it's a small price to pay.
$(FASTTARGET) : $(SOURCES)
- mkdir -p $(CLASSDIR)/$(RESOURCEDIR)
cp $(RESOURCES) $(CLASSDIR)/$(RESOURCEDIR)
echo "" > $(FASTTARGET)
$(JAVAC) $(JFLAGS) -d $(CLASSDIR) $(?)
cd $(CLASSDIR) ; \
jar cf ../$(JAR) $(CLASSES) $(RESOURCES)
clean :
- cd $(CLASSDIR)
- rm $(CLASSES)
- rm $(PATH_PREFIX)/message.ids \
$(PATH_PREFIX)/property.ids \
$(PATH_PREFIX)/MANIFEST
clobber : clean
-rm $(JAR)
$(PATH_PREFIX)/MANIFEST : $(SOURCES) $(RESOURCES) $(PATH_PREFIX)/Makefile
ls $(SOURCES) $(RESOURCES) $(PATH_PREFIX)/Makefile \
> $(@)
# A sed/grep regular expression.
MESSAGE_PREFIX = msg\.
# Find all the msg.* strings in the source, and condense them to a sorted list,
# excluding duplicates.
$(PATH_PREFIX)/message.ids : $(SOURCES)
grep '$(MESSAGE_PREFIX)' $(SOURCES) |\
sed -e 's/.*\"\($(MESSAGE_PREFIX)\)\([^\"]*\).*/\1\2/' | \
sort | uniq > $(PATH_PREFIX)/message.ids
# Find all the msg.* strings in the resource files, and condense them to a
# sorted list, not excluding duplicates.
$(PATH_PREFIX)/property.ids : $(RESOURCES)
grep '^$(MESSAGE_PREFIX)' $(RESOURCES) |\
sed -e 's/.*\($(MESSAGE_PREFIX)\)\([^ =]*\).*/\1\2/' |\
sort > $(PATH_PREFIX)/property.ids
# Compare the resulting message.ids and property.ids files and confirm
# that they do not differ. This means that every message string used
# in the source is defined somewhere in the resource file, every
# resource in the resource file is used somewhere in the source, and
# no resource is defined more than once.
check : $(PATH_PREFIX)/message.ids $(PATH_PREFIX)/property.ids FORCE
- diff $(PATH_PREFIX)/message.ids $(PATH_PREFIX)/property.ids
# look for unmatched single quotes ... seems to fail when none!
# - sed -e s/\'\'//g $($RESOURCES) | grep \'
# Emulate .PHONY
FORCE :

View File

@@ -1,954 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Mike McCabe
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
/**
* This class implements the Array native object.
* @author Norris Boyd
* @author Mike McCabe
*/
public class NativeArray extends ScriptableObject {
/*
* Optimization possibilities and open issues:
* - Long vs. double schizophrenia. I suspect it might be better
* to use double throughout.
* - Most array operations go through getElem or setElem (defined
* in this file) to handle the full 2^32 range; it might be faster
* to have versions of most of the loops in this file for the
* (infinitely more common) case of indices < 2^31.
* - Functions that need a new Array call "new Array" in the
* current scope rather than using a hardwired constructor;
* "Array" could be redefined. It turns out that js calls the
* equivalent of "new Array" in the current scope, except that it
* always gets at least an object back, even when Array == null.
*/
/**
* Zero-parameter constructor: just used to create Array.prototype
*/
public NativeArray() {
dense = null;
this.length = 0;
}
public NativeArray(long length) {
int intLength = (int) length;
if (intLength == length && intLength > 0) {
if (intLength > maximumDenseLength)
intLength = maximumDenseLength;
dense = new Object[intLength];
for (int i=0; i < intLength; i++)
dense[i] = NOT_FOUND;
}
this.length = length;
}
public NativeArray(Object[] array) {
dense = array;
this.length = array.length;
}
public static void finishInit(Scriptable scope, FunctionObject ctor,
Scriptable proto)
{
// Set some method length values.
// See comment for NativeString.finishInit()
String[] specialLengthNames = { "reverse",
"toString",
};
short[] specialLengthValues = { 0,
0,
};
for (int i=0; i < specialLengthNames.length; i++) {
Object obj = proto.get(specialLengthNames[i], proto);
((FunctionObject) obj).setLength(specialLengthValues[i]);
}
}
public String getClassName() {
return "Array";
}
public Object get(int index, Scriptable start) {
if (dense != null && 0 <= index && index < dense.length)
return dense[index];
return super.get(index, start);
}
public boolean has(int index, Scriptable start) {
if (dense != null && 0 <= index && index < dense.length)
return dense[index] != NOT_FOUND;
return super.has(index, start);
}
public void put(String id, Scriptable start, Object value) {
// only set the array length if given an array index (ECMA 15.4.0)
// try to get an array index from id
double d = ScriptRuntime.toNumber(id);
if (ScriptRuntime.toUint32(d) == d &&
ScriptRuntime.numberToString(d, 10).equals(id) &&
this.length <= d && d != 4294967295.0)
{
this.length = (long)d + 1;
}
super.put(id, start, value);
}
public void put(int index, Scriptable start, Object value) {
// only set the array length if given an array index (ECMA 15.4.0)
if (this.length <= index) {
// avoid overflowing index!
this.length = (long)index + 1;
}
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = value;
return;
}
super.put(index, start, value);
}
public void delete(int index) {
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = NOT_FOUND;
return;
}
super.delete(index);
}
public Object[] getIds() {
Object[] superIds = super.getIds();
if (dense == null)
return superIds;
int count = 0;
int last = dense.length;
if (last > length)
last = (int) length;
for (int i=last-1; i >= 0; i--) {
if (dense[i] != NOT_FOUND)
count++;
}
count += superIds.length;
Object[] result = new Object[count];
System.arraycopy(superIds, 0, result, 0, superIds.length);
for (int i=last-1; i >= 0; i--) {
if (dense[i] != NOT_FOUND)
result[--count] = new Integer(i);
}
return result;
}
public Object getDefaultValue(Class hint) {
if (hint == ScriptRuntime.NumberClass) {
Context cx = Context.getContext();
if (cx.getLanguageVersion() == Context.VERSION_1_2)
return new Long(length);
}
return super.getDefaultValue(hint);
}
/**
* See ECMA 15.4.1,2
*/
public static Object jsConstructor(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
throws JavaScriptException
{
if (!inNewExpr) {
// FunctionObject.construct will set up parent, proto
return ctorObj.construct(cx, ctorObj.getParentScope(), args);
}
if (args.length == 0)
return new NativeArray();
// Only use 1 arg as first element for version 1.2; for
// any other version (including 1.3) follow ECMA and use it as
// a length.
if (cx.getLanguageVersion() == cx.VERSION_1_2) {
return new NativeArray(args);
}
else {
if ((args.length > 1) || (!(args[0] instanceof Number)))
return new NativeArray(args);
else {
long len = ScriptRuntime.toUint32(args[0]);
if (len != (((Number)(args[0])).doubleValue()))
throw Context.reportRuntimeError(Context.getMessage
("msg.arraylength.bad", null));
return new NativeArray(len);
}
}
}
private static final int lengthAttr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT;
public long jsGet_length() {
return length;
}
public void jsSet_length(Object val) {
/* XXX do we satisfy this?
* 15.4.5.1 [[Put]](P, V):
* 1. Call the [[CanPut]] method of A with name P.
* 2. If Result(1) is false, return.
* ?
*/
if (!(val instanceof Number))
throw Context.reportRuntimeError(Context.getMessage
("msg.arraylength.bad", null));
long longVal = ScriptRuntime.toUint32(val);
if (longVal != (((Number)val).doubleValue()))
throw Context.reportRuntimeError(Context.getMessage
("msg.arraylength.bad", null));
if (longVal < length) {
// remove all properties between longVal and length
if (length - longVal > 0x1000) {
// assume that the representation is sparse
Object[] e = getIds(); // will only find in object itself
for (int i=0; i < e.length; i++) {
if (e[i] instanceof String) {
// > MAXINT will appear as string
String id = (String) e[i];
double d = ScriptRuntime.toNumber(id);
if (d == d && d < length)
delete(id);
continue;
}
int index = ((Number) e[i]).intValue();
if (index >= longVal)
delete(index);
}
} else {
// assume a dense representation
for (long i=longVal; i < length; i++) {
// only delete if defined in the object itself
if (hasElem(this, i))
ScriptRuntime.delete(this, new Long(i));
}
}
}
length = longVal;
}
/* Support for generic Array-ish objects. Most of the Array
* functions try to be generic; anything that has a length
* property is assumed to be an array. hasLengthProperty is
* needed in addition to getLengthProperty, because
* getLengthProperty always succeeds - tries to convert strings, etc.
*/
static double getLengthProperty(Scriptable obj) {
// These will both give numeric lengths within Uint32 range.
if (obj instanceof NativeString)
return (double)((NativeString)obj).jsGet_length();
if (obj instanceof NativeArray)
return (double)((NativeArray)obj).jsGet_length();
return ScriptRuntime.toUint32(ScriptRuntime
.getProp(obj, "length", obj));
}
static boolean hasLengthProperty(Object obj) {
if (!(obj instanceof Scriptable) || obj == Context.getUndefinedValue())
return false;
if (obj instanceof NativeString || obj instanceof NativeArray)
return true;
Scriptable sobj = (Scriptable)obj;
// XXX some confusion as to whether or not to walk to get the length
// property. Pending review of js/[new ecma submission] treatment
// of 'arrayness'.
Object property = ScriptRuntime.getProp(sobj, "length", sobj);
return property instanceof Number;
}
/* Utility functions to encapsulate index > Integer.MAX_VALUE
* handling. Also avoids unnecessary object creation that would
* be necessary to use the general ScriptRuntime.get/setElem
* functions... though this is probably premature optimization.
*/
private static boolean hasElem(Scriptable target, long index) {
return index > Integer.MAX_VALUE
? target.has(Long.toString(index), target)
: target.has((int)index, target);
}
private static Object getElem(Scriptable target, long index) {
if (index > Integer.MAX_VALUE) {
String id = Long.toString(index);
return ScriptRuntime.getElem(target, id, target);
} else {
return ScriptRuntime.getElem(target, (int)index);
}
}
private static void setElem(Scriptable target, long index, Object value) {
if (index > Integer.MAX_VALUE) {
String id = Long.toString(index);
ScriptRuntime.setElem(target, id, value, target);
} else {
ScriptRuntime.setElem(target, (int)index, value);
}
}
public static String jsFunction_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
return toStringHelper(cx, thisObj,
cx.getLanguageVersion() == cx.VERSION_1_2);
}
private static String toStringHelper(Context cx, Scriptable thisObj,
boolean toSource)
{
/* It's probably redundant to handle long lengths in this
* function; StringBuffers are limited to 2^31 in java.
*/
long length = (long)getLengthProperty(thisObj);
StringBuffer result = new StringBuffer();
if (cx.iterating == null)
cx.iterating = new Hashtable(31);
boolean iterating = cx.iterating.get(thisObj) == Boolean.TRUE;
// whether to return '4,unquoted,5' or '[4, "quoted", 5]'
String separator;
if (toSource) {
result.append("[");
separator = ", ";
} else {
separator = ",";
}
boolean haslast = false;
long i = 0;
if (!iterating) {
for (i = 0; i < length; i++) {
if (i > 0)
result.append(separator);
Object elem = getElem(thisObj, i);
if (elem == null || elem == Undefined.instance) {
haslast = false;
continue;
}
haslast = true;
if (elem instanceof String) {
if (toSource) {
result.append("\"");
result.append(ScriptRuntime.escapeString
(ScriptRuntime.toString(elem)));
result.append("\"");
} else {
result.append(ScriptRuntime.toString(elem));
}
} else {
/* wrap changes to cx.iterating in a try/finally
* so that the reference always gets removed, and
* we don't leak memory. Good place for weak
* references, if we had them. */
try {
// stop recursion.
cx.iterating.put(thisObj, Boolean.TRUE);
result.append(ScriptRuntime.toString(elem));
} finally {
cx.iterating.remove(thisObj);
}
}
}
}
if (toSource) {
//for [,,].length behavior; we want toString to be symmetric.
if (!haslast && i > 0)
result.append(", ]");
else
result.append("]");
}
return result.toString();
}
/**
* See ECMA 15.4.4.3
*/
public static String jsFunction_join(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
StringBuffer result = new StringBuffer();
String separator;
double length = getLengthProperty(thisObj);
// if no args, use "," as separator
if (args.length < 1) {
separator = ",";
} else {
separator = ScriptRuntime.toString(args[0]);
}
for (long i=0; i < length; i++) {
if (i > 0)
result.append(separator);
Object temp = getElem(thisObj, i);
if (temp == null || temp == Undefined.instance)
continue;
result.append(ScriptRuntime.toString(temp));
}
return result.toString();
}
/**
* See ECMA 15.4.4.4
*/
public static Scriptable jsFunction_reverse(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
long len = (long)getLengthProperty(thisObj);
long half = len / 2;
for(long i=0; i < half; i++) {
long j = len - i - 1;
Object temp1 = getElem(thisObj, i);
Object temp2 = getElem(thisObj, j);
setElem(thisObj, i, temp2);
setElem(thisObj, j, temp1);
}
return thisObj;
}
/**
* See ECMA 15.4.4.5
*/
public static Scriptable jsFunction_sort(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
long length = (long)getLengthProperty(thisObj);
Object compare;
if (args.length > 0 && Undefined.instance != args[0])
// sort with given compare function
compare = args[0];
else
// sort with default compare
compare = null;
// OPT: Would it make sense to use the extended sort for very small
// arrays?
// Should we use the extended sort function, or the faster one?
if (length >= Integer.MAX_VALUE) {
qsort_extended(cx, compare, thisObj, 0, length - 1);
} else {
// copy the JS array into a working array, so it can be
// sorted cheaply.
Object[] working = new Object[(int)length];
for (int i=0; i<length; i++) {
working[i] = getElem(thisObj, i);
}
qsort(cx, compare, working, 0, (int)length - 1, funObj);
// copy the working array back into thisObj
for (int i=0; i<length; i++) {
setElem(thisObj, i, working[i]);
}
}
return thisObj;
}
private static double qsortCompare(Context cx, Object jsCompare, Object x,
Object y, Scriptable scope)
throws JavaScriptException
{
Object undef = Undefined.instance;
// sort undefined to end
if (undef == x || undef == y) {
if (undef != x)
return -1;
if (undef != y)
return 1;
return 0;
}
if (jsCompare == null) {
// if no compare function supplied, sort lexicographically
String a = ScriptRuntime.toString(x);
String b = ScriptRuntime.toString(y);
return a.compareTo(b);
} else {
// assemble args and call supplied JS compare function
// OPT: put this argument creation in the caller and reuse it.
// XXX what to do when compare function returns NaN? ECMA states
// that it's then not a 'consistent compararison function'... but
// then what do we do? Back out and start over with the generic
// compare function when we see a NaN? Throw an error?
Object[] args = {x, y};
// return ScriptRuntime.toNumber(ScriptRuntime.call(jsCompare, null,
// args));
// for now, just ignore it:
double d = ScriptRuntime.
toNumber(ScriptRuntime.call(cx, jsCompare, null, args, scope));
return (d == d) ? d : 0;
}
}
private static void qsort(Context cx, Object jsCompare, Object[] working,
int lo, int hi, Scriptable scope)
throws JavaScriptException
{
Object pivot;
int i, j;
int a, b;
while (lo < hi) {
i = lo;
j = hi;
a = i;
pivot = working[a];
while (i < j) {
for(;;) {
b = j;
if (qsortCompare(cx, jsCompare, working[j], pivot,
scope) <= 0)
break;
j--;
}
working[a] = working[b];
while (i < j && qsortCompare(cx, jsCompare, working[a],
pivot, scope) <= 0)
{
i++;
a = i;
}
working[b] = working[a];
}
working[a] = pivot;
if (i - lo < hi - i) {
qsort(cx, jsCompare, working, lo, i - 1, scope);
lo = i + 1;
} else {
qsort(cx, jsCompare, working, i + 1, hi, scope);
hi = i - 1;
}
}
}
// A version that knows about long indices and doesn't use
// a working array. Probably will never be used.
private static void qsort_extended(Context cx, Object jsCompare,
Scriptable target, long lo, long hi)
throws JavaScriptException
{
Object pivot;
long i, j;
long a, b;
while (lo < hi) {
i = lo;
j = hi;
a = i;
pivot = getElem(target, a);
while (i < j) {
for(;;) {
b = j;
if (qsortCompare(cx, jsCompare, getElem(target, j),
pivot, target) <= 0)
break;
j--;
}
setElem(target, a, getElem(target, b));
while (i < j && qsortCompare(cx, jsCompare,
getElem(target, a),
pivot, target) <= 0)
{
i++;
a = i;
}
setElem(target, b, getElem(target, a));
}
setElem(target, a, pivot);
if (i - lo < hi - i) {
qsort_extended(cx, jsCompare, target, lo, i - 1);
lo = i + 1;
} else {
qsort_extended(cx, jsCompare, target, i + 1, hi);
hi = i - 1;
}
}
}
/**
* Non-ECMA methods.
*/
public static Object jsFunction_push(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
double length = getLengthProperty(thisObj);
for (int i = 0; i < args.length; i++) {
setElem(thisObj, (long)length + i, args[i]);
}
length += args.length;
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
/*
* If JS1.2, follow Perl4 by returning the last thing pushed.
* Otherwise, return the new array length.
*/
if (cx.getLanguageVersion() == Context.VERSION_1_2)
// if JS1.2 && no arguments, return undefined.
return args.length == 0
? Context.getUndefinedValue()
: args[args.length - 1];
else
return new Long((long)length);
}
public static Object jsFunction_pop(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Object result;
double length = getLengthProperty(thisObj);
if (length > 0) {
length--;
// Get the to-be-deleted property's value.
result = getElem(thisObj, (long)length);
// We don't need to delete the last property, because
// setLength does that for us.
} else {
result = Context.getUndefinedValue();
}
// necessary to match js even when length < 0; js pop will give a
// length property to any target it is called on.
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
return result;
}
public static Object jsFunction_shift(Context cx, Scriptable thisObj,
Object[] args, Function funOjb)
{
Object result;
double length = getLengthProperty(thisObj);
if (length > 0) {
long i = 0;
length--;
// Get the to-be-deleted property's value.
result = getElem(thisObj, i);
/*
* Slide down the array above the first element. Leave i
* set to point to the last element.
*/
if (length > 0) {
for (i = 1; i <= length; i++) {
Object temp = getElem(thisObj, i);
setElem(thisObj, i - 1, temp);
}
}
// We don't need to delete the last property, because
// setLength does that for us.
} else {
result = Context.getUndefinedValue();
}
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
return result;
}
public static Object jsFunction_unshift(Context cx, Scriptable thisObj,
Object[] args, Function funOjb)
{
Object result;
double length = (double)getLengthProperty(thisObj);
int argc = args.length;
if (args.length > 0) {
/* Slide up the array to make room for args at the bottom */
if (length > 0) {
for (long last = (long)length - 1; last >= 0; last--) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + argc, temp);
}
}
/* Copy from argv to the bottom of the array. */
for (int i = 0; i < args.length; i++) {
setElem(thisObj, i, args[i]);
}
/* Follow Perl by returning the new array length. */
length += args.length;
ScriptRuntime.setProp(thisObj, "length",
new Double(length), thisObj);
}
return new Long((long)length);
}
public static Object jsFunction_splice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
/* create an empty Array to return. */
Scriptable scope = getTopLevelScope(funObj);
Object result = ScriptRuntime.newObject(cx, scope, "Array", null);
int argc = args.length;
if (argc == 0)
return result;
double length = getLengthProperty(thisObj);
/* Convert the first argument into a starting index. */
double begin = ScriptRuntime.toInteger(args[0]);
double end;
double delta;
double count;
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
argc--;
/* Convert the second argument from a count into a fencepost index. */
delta = length - begin;
if (args.length == 1) {
count = delta;
end = length;
} else {
count = ScriptRuntime.toInteger(args[1]);
if (count < 0)
count = 0;
else if (count > delta)
count = delta;
end = begin + count;
argc--;
}
long lbegin = (long)begin;
long lend = (long)end;
/* If there are elements to remove, put them into the return value. */
if (count > 0) {
if (count == 1
&& (cx.getLanguageVersion() == Context.VERSION_1_2))
{
/*
* JS lacks "list context", whereby in Perl one turns the
* single scalar that's spliced out into an array just by
* assigning it to @single instead of $single, or by using it
* as Perl push's first argument, for instance.
*
* JS1.2 emulated Perl too closely and returned a non-Array for
* the single-splice-out case, requiring callers to test and
* wrap in [] if necessary. So JS1.3, default, and other
* versions all return an array of length 1 for uniformity.
*/
result = getElem(thisObj, lbegin);
} else {
for (long last = lbegin; last < lend; last++) {
Scriptable resultArray = (Scriptable)result;
Object temp = getElem(thisObj, last);
setElem(resultArray, last - lbegin, temp);
}
}
} else if (count == 0
&& cx.getLanguageVersion() == Context.VERSION_1_2)
{
/* Emulate C JS1.2; if no elements are removed, return undefined. */
result = Context.getUndefinedValue();
}
/* Find the direction (up or down) to copy and make way for argv. */
delta = argc - count;
if (delta > 0) {
for (long last = (long)length - 1; last >= lend; last--) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + (long)delta, temp);
}
} else if (delta < 0) {
for (long last = lend; last < length; last++) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + (long)delta, temp);
}
}
/* Copy from argv into the hole to complete the splice. */
int argoffset = args.length - argc;
for (int i = 0; i < argc; i++) {
setElem(thisObj, lbegin + i, args[i + argoffset]);
}
/* Update length in case we deleted elements from the end. */
ScriptRuntime.setProp(thisObj, "length",
new Double(length + delta), thisObj);
return result;
}
/*
* Python-esque sequence operations.
*/
public static Scriptable jsFunction_concat(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
/* Concat tries to keep the definition of an array as general
* as possible; if it finds that an object has a numeric
* 'length' property, then it treats that object as an array.
* This treats string atoms and string objects differently; as
* string objects have a length property and are accessible by
* index, they get exploded into arrays when added, while
* atomic strings are just added as strings.
*/
// create an empty Array to return.
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
double length;
long slot = 0;
/* Put the target in the result array; only add it as an array
* if it looks like one.
*/
if (hasLengthProperty(thisObj)) {
length = getLengthProperty(thisObj);
// Copy from the target object into the result
for (slot = 0; slot < length; slot++) {
Object temp = getElem(thisObj, slot);
setElem(result, slot, temp);
}
} else {
setElem(result, slot++, thisObj);
}
/* Copy from the arguments into the result. If any argument
* has a numeric length property, treat it as an array and add
* elements separately; otherwise, just copy the argument.
*/
for (int i = 0; i < args.length; i++) {
if (hasLengthProperty(args[i])) {
// hasLengthProperty => instanceOf Scriptable.
Scriptable arg = (Scriptable)args[i];
length = getLengthProperty(arg);
for (long j = 0; j < length; j++, slot++) {
Object temp = getElem(arg, j);
setElem(result, slot, temp);
}
} else {
setElem(result, slot++, args[i]);
}
}
return result;
}
public static Scriptable jsFunction_slice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
double length = getLengthProperty(thisObj);
double begin = 0;
double end = length;
if (args.length > 0) {
begin = ScriptRuntime.toInteger(args[0]);
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
if (args.length > 1) {
end = ScriptRuntime.toInteger(args[1]);
if (end < 0) {
end += length;
if (end < 0)
end = 0;
} else if (end > length) {
end = length;
}
}
}
long lbegin = (long)begin;
long lend = (long)end;
for (long slot = lbegin; slot < lend; slot++) {
Object temp = getElem(thisObj, slot);
setElem(result, slot - lbegin, temp);
}
return result;
}
private long length;
private Object[] dense;
private static final int maximumDenseLength = 10000;
}

View File

@@ -1,92 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Mike McCabe
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
/**
* This class implements the Boolean native object.
* See ECMA 15.6.
* @author Norris Boyd
*/
public class NativeBoolean extends ScriptableObject {
/**
* Zero-parameter constructor: just used to create Boolean.prototype
*/
public NativeBoolean() {
}
public NativeBoolean(boolean b) {
booleanValue = b;
}
public String getClassName() {
return "Boolean";
}
public Object getDefaultValue(Class typeHint) {
// This is actually non-ECMA, but will be proposed
// as a change in round 2.
if (typeHint == ScriptRuntime.BooleanClass)
return booleanValue ? Boolean.TRUE : Boolean.FALSE;
return super.getDefaultValue(typeHint);
}
public static Object jsConstructor(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
boolean b = args.length >= 1
? ScriptRuntime.toBoolean(args[0])
: false;
if (inNewExpr) {
// new Boolean(val) creates a new boolean object.
return new NativeBoolean(b);
}
// Boolean(val) converts val to a boolean.
return b ? Boolean.TRUE : Boolean.FALSE;
}
public String jsFunction_toString() {
return booleanValue ? "true" : "false";
}
public boolean jsFunction_valueOf() {
return booleanValue;
}
private boolean booleanValue;
}

View File

@@ -1,135 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
/**
* This class implements the activation object.
*
* See ECMA 10.1.6
*
* @see org.mozilla.javascript.Arguments
* @author Norris Boyd
*/
public final class NativeCall extends ScriptableObject {
NativeCall(Context cx, Scriptable scope, NativeFunction funObj,
Scriptable thisObj, Object[] args)
{
this(cx, scope, funObj, thisObj);
this.originalArgs = args;
// initialize values of arguments
String[] names = funObj.names;
if (names != null) {
for (int i=0; i < funObj.argCount; i++) {
Object val = i < args.length ? args[i]
: Undefined.instance;
super.put(names[i+1], this, val);
}
}
// initialize "arguments" property
super.put("arguments", this, new Arguments(this));
}
NativeCall(Context cx, Scriptable scope, NativeFunction funObj,
Scriptable thisObj)
{
this.funObj = funObj;
this.thisObj = thisObj;
setParentScope(scope);
// leave prototype null
// save current activation
this.caller = cx.currentActivation;
cx.currentActivation = this;
}
// Needed in order to use this class with ScriptableObject.defineClass
public NativeCall() {
}
public String getClassName() {
return "Call";
}
public static Object jsConstructor(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
if (!inNewExpr) {
Object[] errArgs = { "Call" };
throw Context.reportRuntimeError(Context.getMessage
("msg.only.from.new", errArgs));
}
ScriptRuntime.checkDeprecated(cx, "Call");
NativeCall result = new NativeCall();
result.setPrototype(getObjectPrototype(ctorObj));
return result;
}
NativeCall getActivation(NativeFunction f) {
NativeCall x = this;
do {
if (x.funObj == f)
return x;
x = x.caller;
} while (x != null);
return null;
}
public NativeFunction getFunctionObject() {
return funObj;
}
public Object[] getOriginalArguments() {
return originalArgs;
}
public NativeCall getCaller() {
return caller;
}
public Scriptable getThisObj() {
return thisObj;
}
NativeCall caller;
NativeFunction funObj;
Scriptable thisObj;
Object[] originalArgs;
public int debugPC;
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More