Changes for classfile generation.

This commit is contained in:
norris%netscape.com 1999-09-27 23:17:29 +00:00
parent b7649a1e51
commit 40f1ee60cc
37 changed files with 15395 additions and 7 deletions

View File

@ -1666,9 +1666,9 @@ public final class Context {
static {
try {
codegenClass = Class.forName(
"com.netscape.javascript.optimizer.Codegen");
"org.mozilla.javascript.optimizer.Codegen");
Class nameHelperClass = Class.forName(
"com.netscape.javascript.optimizer.OptClassNameHelper");
"org.mozilla.javascript.optimizer.OptClassNameHelper");
nameHelper = (ClassNameHelper)nameHelperClass.newInstance();
} catch (ClassNotFoundException x) {
// ...must be running lite, that's ok

View File

@ -22,7 +22,7 @@
* used by other classes to turn debug code on or off (at compile time)
*/
public class GenerateDebugSwitchSourceFile
public class GenerateDebugSwitch
{
public static void main(String[] args)
{

View File

@ -0,0 +1,688 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import org.mozilla.classfile.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.PrintWriter;
import java.io.StringWriter;
public class Block {
public Block(int startNodeIndex, int endNodeIndex, Node[] statementNodes)
{
itsStartNodeIndex = startNodeIndex;
itsEndNodeIndex = endNodeIndex;
itsStatementNodes = statementNodes;
}
public void setBlockID(int id) { itsBlockID = id; }
public int getBlockID() { return itsBlockID; }
public Node getStartNode() { return itsStatementNodes[itsStartNodeIndex]; }
public Node getEndNode() { return itsStatementNodes[itsEndNodeIndex]; }
public Block[] getPredecessorList() { return itsPredecessors; }
public Block[] getSuccessorList() { return itsSuccessors; }
public static Block[] buildBlocks(Node[] statementNodes)
{
// a mapping from each target node to the block it begins
Hashtable theTargetBlocks = new Hashtable();
Vector theBlocks = new Vector();
// there's a block that starts at index 0
int beginNodeIndex = 0;
for (int i = 0; i < statementNodes.length; i++) {
switch (statementNodes[i].getType()) {
case TokenStream.TARGET :
{
if (i != beginNodeIndex) {
FatBlock fb = new FatBlock(beginNodeIndex,
i - 1, statementNodes);
if (statementNodes[beginNodeIndex].getType()
== TokenStream.TARGET)
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
theBlocks.addElement(fb);
// start the next block at this node
beginNodeIndex = i;
}
}
break;
case TokenStream.IFNE :
case TokenStream.IFEQ :
case TokenStream.GOTO :
{
FatBlock fb = new FatBlock(beginNodeIndex,
i, statementNodes);
if (statementNodes[beginNodeIndex].getType()
== TokenStream.TARGET)
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
theBlocks.addElement(fb);
// start the next block at the next node
beginNodeIndex = i + 1;
}
break;
}
}
if ((beginNodeIndex != statementNodes.length)) {
FatBlock fb = new FatBlock(beginNodeIndex,
statementNodes.length - 1,
statementNodes);
if (statementNodes[beginNodeIndex].getType() == TokenStream.TARGET)
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
theBlocks.addElement(fb);
}
// build successor and predecessor links
for (int i = 0; i < theBlocks.size(); i++) {
FatBlock fb = (FatBlock)(theBlocks.elementAt(i));
Node blockEndNode = fb.getEndNode();
int blockEndNodeType = blockEndNode.getType();
if ((blockEndNodeType != TokenStream.GOTO)
&& (i < (theBlocks.size() - 1))) {
FatBlock fallThruTarget = (FatBlock)(theBlocks.elementAt(i + 1));
fb.addSuccessor(fallThruTarget);
fallThruTarget.addPredecessor(fb);
}
if ( (blockEndNodeType == TokenStream.IFNE)
|| (blockEndNodeType == TokenStream.IFEQ)
|| (blockEndNodeType == TokenStream.GOTO) ) {
Node target = (Node)(blockEndNode.getProp(Node.TARGET_PROP));
FatBlock branchTargetBlock
= (FatBlock)(theTargetBlocks.get(target));
target.putProp(Node.TARGETBLOCK_PROP,
branchTargetBlock.getSlimmerSelf());
fb.addSuccessor(branchTargetBlock);
branchTargetBlock.addPredecessor(fb);
}
}
Block[] result = new Block[theBlocks.size()];
for (int i = 0; i < theBlocks.size(); i++) {
FatBlock fb = (FatBlock)(theBlocks.elementAt(i));
result[i] = fb.diet();
result[i].setBlockID(i);
}
return result;
}
public static String toString(Block[] blockList, Node[] statementNodes)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println(blockList.length + " Blocks");
for (int i = 0; i < blockList.length; i++) {
Block b = blockList[i];
pw.println("#" + b.itsBlockID);
pw.println("from " + b.itsStartNodeIndex
+ " "
+ statementNodes[b.itsStartNodeIndex].toString());
pw.println("thru " + b.itsEndNodeIndex
+ " "
+ statementNodes[b.itsEndNodeIndex].toString());
pw.print("Predecessors ");
if (b.itsPredecessors != null) {
for (int j = 0; j < b.itsPredecessors.length; j++)
pw.print(b.itsPredecessors[j].getBlockID() + " ");
pw.println();
}
else
pw.println("none");
pw.print("Successors ");
if (b.itsSuccessors != null) {
for (int j = 0; j < b.itsSuccessors.length; j++)
pw.print(b.itsSuccessors[j].getBlockID() + " ");
pw.println();
}
else
pw.println("none");
}
return sw.toString();
}
/*
We maintain the liveSet as each statement executes, identifying
those variables that are live across function calls
*/
void lookForVariablesAndCalls(Node n, boolean liveSet[],
VariableTable theVariables)
{
switch (n.getType()) {
case TokenStream.SETVAR :
{
Node lhs = n.getFirstChild();
Node rhs = lhs.getNextSibling();
lookForVariablesAndCalls(rhs, liveSet, theVariables);
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
liveSet[theVarIndex] = true;
}
}
break;
case TokenStream.CALL : {
Node child = n.getFirstChild();
while (child != null) {
lookForVariablesAndCalls(child, liveSet, theVariables);
child = child.getNextSibling();
}
for (int i = 0; i < liveSet.length; i++) {
if (liveSet[i])
((OptLocalVariable)theVariables.get(i)).markLiveAcrossCall();
}
}
break;
case TokenStream.GETVAR :
{
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
if ((n.getProp(Node.LASTUSE_PROP) != null)
&& !itsLiveOnExitSet.test(theVarIndex))
liveSet[theVarIndex] = false;
}
}
break;
default :
Node child = n.getFirstChild();
while (child != null) {
lookForVariablesAndCalls(child, liveSet, theVariables);
child = child.getNextSibling();
}
break;
}
}
void markVolatileVariables(VariableTable theVariables)
{
boolean liveSet[] = new boolean[theVariables.size()];
for (int i = 0; i < liveSet.length; i++)
liveSet[i] = itsLiveOnEntrySet.test(i);
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
lookForVariablesAndCalls(n, liveSet, theVariables);
}
}
/*
We're tracking uses and defs - in order to
build the def set and to identify the last use
nodes.
The itsNotDefSet is built reversed then flipped later.
*/
void lookForVariableAccess(Node n, Node lastUse[])
{
switch (n.getType()) {
case TokenStream.DEC :
case TokenStream.INC :
{
Node child = n.getFirstChild();
if (child.getType() == TokenStream.GETVAR) {
Object theVarProp = child.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
if (!itsNotDefSet.test(theVarIndex))
itsUseBeforeDefSet.set(theVarIndex);
itsNotDefSet.set(theVarIndex);
}
}
}
break;
case TokenStream.SETVAR :
{
Node lhs = n.getFirstChild();
Node rhs = lhs.getNextSibling();
lookForVariableAccess(rhs, lastUse);
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
itsNotDefSet.set(theVarIndex);
if (lastUse[theVarIndex] != null)
lastUse[theVarIndex].putProp(Node.LASTUSE_PROP,
theVarProp);
}
}
break;
case TokenStream.GETVAR :
{
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
if (!itsNotDefSet.test(theVarIndex))
itsUseBeforeDefSet.set(theVarIndex);
lastUse[theVarIndex] = n;
}
}
break;
default :
Node child = n.getFirstChild();
while (child != null) {
lookForVariableAccess(child, lastUse);
child = child.getNextSibling();
}
break;
}
}
/*
build the live on entry/exit sets.
Then walk the trees looking for defs/uses of variables
and build the def and useBeforeDef sets.
*/
public void initLiveOnEntrySets(VariableTable theVariables)
{
int listLength = theVariables.size();
Node lastUse[] = new Node[listLength];
itsUseBeforeDefSet = new DataFlowBitSet(listLength);
itsNotDefSet = new DataFlowBitSet(listLength);
itsLiveOnEntrySet = new DataFlowBitSet(listLength);
itsLiveOnExitSet = new DataFlowBitSet(listLength);
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
lookForVariableAccess(n, lastUse);
}
for (int i = 0; i < listLength; i++) {
if (lastUse[i] != null)
lastUse[i].putProp(Node.LASTUSE_PROP, this);
}
itsNotDefSet.not(); // truth in advertising
}
/*
the liveOnEntry of each successor is the liveOnExit for this block.
The liveOnEntry for this block is -
liveOnEntry = liveOnExit - defsInThisBlock + useBeforeDefsInThisBlock
*/
boolean doReachedUseDataFlow()
{
itsLiveOnExitSet.clear();
if (itsSuccessors != null)
for (int i = 0; i < itsSuccessors.length; i++)
itsLiveOnExitSet.or(itsSuccessors[i].itsLiveOnEntrySet);
return itsLiveOnEntrySet.df2(itsLiveOnExitSet,
itsUseBeforeDefSet, itsNotDefSet);
}
/*
the type of an expression is relatively unknown. Cases we can be sure
about are -
Literals,
Arithmetic operations - always return a Number
*/
int findExpressionType(Node n)
{
switch (n.getType()) {
case TokenStream.NUMBER : {
/* distinguish between integers & f.p.s ?
Number num = ((NumberNode)n).getNumber();
if ((num instanceof Byte)
|| (num instanceof Short)
|| (num instanceof Integer)) {
}
else {
}
*/
return TypeEvent.NumberType;
}
case TokenStream.NEW :
case TokenStream.CALL :
return TypeEvent.NoType;
case TokenStream.GETELEM :
return TypeEvent.AnyType;
case TokenStream.GETVAR : {
OptLocalVariable theVar = (OptLocalVariable)
(n.getProp(Node.VARIABLE_PROP));
if (theVar != null)
return theVar.getTypeUnion();
}
case TokenStream.INC :
case TokenStream.DEC :
case TokenStream.DIV:
case TokenStream.MOD:
case TokenStream.BITOR:
case TokenStream.BITXOR:
case TokenStream.BITAND:
case TokenStream.LSH:
case TokenStream.RSH:
case TokenStream.URSH:
case TokenStream.SUB : {
return TypeEvent.NumberType;
}
case TokenStream.ADD : {
// if the lhs & rhs are known to be numbers, we can be sure that's
// the result, otherwise it could be a string.
Node child = n.getFirstChild();
int lType = findExpressionType(child);
int rType = findExpressionType(child.getNextSibling());
return lType | rType; // we're not distinguishng strings yet
}
default : {
Node child = n.getFirstChild();
if (child == null)
return TypeEvent.AnyType;
else {
int result = TypeEvent.NoType;
while (child != null) {
result |= findExpressionType(child);
child = child.getNextSibling();
}
return result;
}
}
}
}
boolean findDefPoints(Node n)
{
boolean result = false;
switch (n.getType()) {
default : {
Node child = n.getFirstChild();
while (child != null) {
result |= findDefPoints(child);
child = child.getNextSibling();
}
}
break;
case TokenStream.DEC :
case TokenStream.INC : {
Node firstChild = n.getFirstChild();
OptLocalVariable theVar = (OptLocalVariable)
(firstChild.getProp(Node.VARIABLE_PROP));
if (theVar != null) {
// theVar is a Number now
result |= theVar.assignType(TypeEvent.NumberType);
}
}
break;
case TokenStream.SETPROP : {
Node baseChild = n.getFirstChild();
Node nameChild = baseChild.getNextSibling();
Node rhs = nameChild.getNextSibling();
if (baseChild != null) {
if (baseChild.getType() == TokenStream.GETVAR) {
OptLocalVariable theVar = (OptLocalVariable)
(baseChild.getProp(Node.VARIABLE_PROP));
if (theVar != null)
theVar.assignType(TypeEvent.AnyType);
}
result |= findDefPoints(baseChild);
}
if (nameChild != null) result |= findDefPoints(nameChild);
if (rhs != null) result |= findDefPoints(rhs);
}
break;
case TokenStream.SETVAR : {
Node firstChild = n.getFirstChild();
OptLocalVariable theVar = (OptLocalVariable)
(n.getProp(Node.VARIABLE_PROP));
if (theVar != null) {
Node rValue = firstChild.getNextSibling();
int theType = findExpressionType(rValue);
result |= theVar.assignType(theType);
}
}
break;
}
return result;
}
// a total misnomer for now. To start with we're only trying to find
// duplicate getProp calls on 'this' that can be merged
void localCSE(Node parent, Node n, Hashtable theCSETable, OptFunctionNode theFunction)
{
switch (n.getType()) {
default : {
Node child = n.getFirstChild();
while (child != null) {
localCSE(n, child, theCSETable, theFunction);
child = child.getNextSibling();
}
}
break;
case TokenStream.DEC :
case TokenStream.INC : {
Node child = n.getFirstChild();
if (child.getType() == TokenStream.GETPROP) {
Node nameChild = child.getFirstChild().getNextSibling();
if (nameChild.getType() == TokenStream.STRING)
theCSETable.remove(nameChild.getString());
else
theCSETable.clear();
}
else
if (child.getType() != TokenStream.GETVAR)
theCSETable.clear();
}
break;
case TokenStream.SETPROP : {
Node baseChild = n.getFirstChild();
Node nameChild = baseChild.getNextSibling();
Node rhs = nameChild.getNextSibling();
if (baseChild != null) localCSE(n, baseChild, theCSETable, theFunction);
if (nameChild != null) localCSE(n, nameChild, theCSETable, theFunction);
if (rhs != null) localCSE(n, rhs, theCSETable, theFunction);
if (nameChild.getType() == TokenStream.STRING) {
theCSETable.remove(nameChild.getString());
// System.out.println("clear at SETPROP " + ((StringNode)nameChild).getString());
}
else {
theCSETable.clear();
// System.out.println("clear all at SETPROP");
}
}
break;
case TokenStream.GETPROP : {
Node baseChild = n.getFirstChild();
if (baseChild != null) localCSE(n, baseChild, theCSETable, theFunction);
if ((baseChild.getType() == TokenStream.PRIMARY)
&& (baseChild.getInt() == TokenStream.THIS)) {
Node nameChild = baseChild.getNextSibling();
if (nameChild.getType() == TokenStream.STRING) {
String theName = nameChild.getString();
// System.out.println("considering " + theName);
Object cse = theCSETable.get(theName);
if (cse == null) {
theCSETable.put(theName, new CSEHolder(parent, n));
}
else {
if (parent != null) {
// System.out.println("Yay for " + theName);
Node theCSE;
if (cse instanceof CSEHolder) {
CSEHolder cseHolder = (CSEHolder)cse;
Node nextChild = cseHolder.getPropChild.getNextSibling();
cseHolder.getPropParent.removeChild(cseHolder.getPropChild);
theCSE = itsIRFactory.createNewLocal(cseHolder.getPropChild);
theFunction.incrementLocalCount();
if (nextChild == null)
cseHolder.getPropParent.addChildToBack(theCSE);
else
cseHolder.getPropParent.addChildBefore(theCSE, nextChild);
theCSETable.put(theName, theCSE);
}
else
theCSE = (Node)cse;
Node nextChild = n.getNextSibling();
parent.removeChild(n);
Node cseUse = itsIRFactory.createUseLocal(theCSE);
if (nextChild == null)
parent.addChildToBack(cseUse);
else
parent.addChildBefore(cseUse, nextChild);
}
}
}
}
}
break;
case TokenStream.SETELEM : {
Node lhsBase = n.getFirstChild();
Node lhsIndex = lhsBase.getNextSibling();
Node rhs = lhsIndex.getNextSibling();
if (lhsBase != null) localCSE(n, lhsBase, theCSETable, theFunction);
if (lhsIndex != null) localCSE(n, lhsIndex, theCSETable, theFunction);
if (rhs != null) localCSE(n, rhs, theCSETable, theFunction);
theCSETable.clear();
//System.out.println("clear all at SETELEM");
}
break;
case TokenStream.CALL : {
Node child = n.getFirstChild();
while (child != null) {
localCSE(n, child, theCSETable, theFunction);
child = child.getNextSibling();
}
theCSETable.clear();
//System.out.println("clear all at CALL");
}
break;
}
}
private IRFactory itsIRFactory;
Hashtable localCSE(Hashtable theCSETable, OptFunctionNode theFunction)
{
itsIRFactory = new IRFactory(null);
if (theCSETable == null) theCSETable = new Hashtable(5);
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
if (n != null)
localCSE(null, n, theCSETable, theFunction);
}
return theCSETable;
}
void findDefs()
{
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
if (n != null)
findDefPoints(n);
}
}
public boolean doTypeFlow()
{
boolean changed = false;
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
if (n != null)
changed |= findDefPoints(n);
}
return changed;
}
public boolean isLiveOnEntry(int index)
{
return (itsLiveOnEntrySet != null) && (itsLiveOnEntrySet.test(index));
}
public void printLiveOnEntrySet(PrintWriter pw, VariableTable theVariables)
{
for (int i = 0; i < theVariables.size(); i++) {
if (itsUseBeforeDefSet.test(i))
pw.println(theVariables.get(i).getName() + " is used before def'd");
if (itsNotDefSet.test(i))
pw.println(theVariables.get(i).getName() + " is not def'd");
if (itsLiveOnEntrySet.test(i))
pw.println(theVariables.get(i).getName() + " is live on entry");
if (itsLiveOnExitSet.test(i))
pw.println(theVariables.get(i).getName() + " is live on exit");
}
}
public void setSuccessorList(Block[] b) { itsSuccessors = b; }
public void setPredecessorList(Block[] b) { itsPredecessors = b; }
// all the Blocks that come immediately after this
private Block[] itsSuccessors;
// all the Blocks that come immediately before this
private Block[] itsPredecessors;
private int itsStartNodeIndex; // the Node at the start of the block
private int itsEndNodeIndex; // the Node at the end of the block
private Node itsStatementNodes[]; // the list of all statement nodes
private int itsBlockID; // a unique index for each block
// reaching def bit sets -
private DataFlowBitSet itsLiveOnEntrySet;
private DataFlowBitSet itsLiveOnExitSet;
private DataFlowBitSet itsUseBeforeDefSet;
private DataFlowBitSet itsNotDefSet;
}
class CSEHolder {
CSEHolder(Node parent, Node child)
{
getPropParent = parent;
getPropChild = child;
}
Node getPropParent;
Node getPropChild;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
class DataFlowBitSet {
private int itsBits[];
int itsSize;
DataFlowBitSet(int size)
{
itsSize = size;
itsBits = new int[(size >> 5) + 1];
}
int size()
{
return itsSize;
}
void set(int n)
{
if ((n < 0) || (n >= itsSize))
throw new RuntimeException("DataFlowBitSet bad index " + n);
itsBits[n >> 5] |= 1 << (n & 31);
}
boolean test(int n)
{
if ((n < 0) || (n >= itsSize))
throw new RuntimeException("DataFlowBitSet bad index " + n);
return ((itsBits[n >> 5] & (1 << (n & 31))) != 0);
}
void not()
{
int bitsLength = itsBits.length;
for (int i = 0; i < bitsLength; i++)
itsBits[i] = ~itsBits[i];
}
void clear(int n)
{
if ((n < 0) || (n >= itsSize))
throw new RuntimeException("DataFlowBitSet bad index " + n);
itsBits[n >> 5] &= ~(1 << (n & 31));
}
void clear()
{
int bitsLength = itsBits.length;
for (int i = 0; i < bitsLength; i++)
itsBits[i] = 0;
}
void or(DataFlowBitSet b)
{
int bitsLength = itsBits.length;
for (int i = 0; i < bitsLength; i++)
itsBits[i] |= b.itsBits[i];
}
public String toString()
{
StringBuffer result = new StringBuffer();
result.append("DataFlowBitSet, size = " + itsSize + "\n");
for (int i = 0; i < itsBits.length; i++)
result.append(Integer.toHexString(itsBits[i]) + " ");
return result.toString();
}
boolean df(DataFlowBitSet in, DataFlowBitSet gen, DataFlowBitSet notKill)
{
int bitsLength = itsBits.length;
boolean changed = false;
for (int i = 0; i < bitsLength; i++) {
int oldBits = itsBits[i];
itsBits[i] = (in.itsBits[i] | gen.itsBits[i]) & notKill.itsBits[i];
changed |= (oldBits != itsBits[i]);
}
return changed;
}
boolean df2(DataFlowBitSet in, DataFlowBitSet gen, DataFlowBitSet notKill)
{
int bitsLength = itsBits.length;
boolean changed = false;
for (int i = 0; i < bitsLength; i++) {
int oldBits = itsBits[i];
itsBits[i] = (in.itsBits[i] & notKill.itsBits[i]) | gen.itsBits[i];
changed |= (oldBits != itsBits[i]);
}
return changed;
}
}

View File

@ -0,0 +1,92 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
public class FatBlock {
public FatBlock(int startNodeIndex, int endNodeIndex, Node[] statementNodes)
{
itsShadowOfFormerSelf = new Block(startNodeIndex, endNodeIndex, statementNodes);
}
public Node getEndNode()
{ return itsShadowOfFormerSelf.getEndNode(); }
public Block getSlimmerSelf()
{ return itsShadowOfFormerSelf; }
private Block[] reduceToArray(Hashtable h)
{
Block[] result = null;
if (!h.isEmpty()) {
result = new Block[h.size()];
Enumeration enum = h.elements();
int i = 0;
while (enum.hasMoreElements()) {
FatBlock fb = (FatBlock)(enum.nextElement());
result[i++] = fb.itsShadowOfFormerSelf;
}
}
return result;
}
Block diet()
{
itsShadowOfFormerSelf.setSuccessorList(reduceToArray(itsSuccessors));
itsShadowOfFormerSelf.setPredecessorList(reduceToArray(itsPredecessors));
return itsShadowOfFormerSelf;
}
public void addSuccessor(FatBlock b) { itsSuccessors.put(b, b); }
public void addPredecessor(FatBlock b) { itsPredecessors.put(b, b); }
// all the Blocks that come immediately after this
private Hashtable itsSuccessors = new Hashtable(4);
// all the Blocks that come immediately before this
private Hashtable itsPredecessors = new Hashtable(4);
private Block itsShadowOfFormerSelf;
}

View File

@ -0,0 +1,71 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import java.util.*;
/**
* Load generated classes that implement JavaScript scripts
* or functions.
*
* @author Norris Boyd
*/
final class JavaScriptClassLoader extends ClassLoader {
JavaScriptClassLoader() {
}
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) {
// Experimental change for JShell, use outer class loader.
ClassLoader loader = JavaScriptClassLoader.class.getClassLoader();
if (loader != null)
return loader.loadClass(name);
clazz = findSystemClass(name);
}
if (resolve)
resolveClass(clazz);
return clazz;
}
}

View File

@ -0,0 +1,142 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.io.*;
public class OptClassNameHelper implements ClassNameHelper {
public String getGeneratingDirectory() {
return generatingDirectory;
}
public synchronized String getJavaScriptClassName(String functionName,
boolean primary)
{
StringBuffer s = new StringBuffer();
if (packageName != null && packageName.length() > 0) {
s.append(packageName);
s.append('.');
}
s.append(initialName);
if (generatingDirectory != null) {
if (functionName != null) {
s.append('$');
s.append(functionName);
} else if (!primary) {
s.append(++serial);
}
} else {
s.append(globalSerial++);
}
return s.toString();
}
public String getTargetClassFileName() {
return getTargetClassFileName(getInitialClassName());
}
public void setTargetClassFileName(String classFileName) {
int lastSeparator = classFileName.lastIndexOf('/');
String initialName;
if (lastSeparator == -1) {
generatingDirectory = "";
initialName = classFileName;
} else {
generatingDirectory = classFileName.substring(0, lastSeparator);
initialName = classFileName.substring(lastSeparator+1);
}
if (initialName.endsWith(".class"))
initialName = initialName.substring(0, initialName.length() - 6);
setInitialClassName(initialName);
}
public String getTargetPackage() {
return packageName;
}
public void setTargetPackage(String targetPackage) {
this.packageName = targetPackage;
}
public String getTargetClassFileName(String className) {
if (generatingDirectory == null)
return null;
StringBuffer sb = new StringBuffer();
if (generatingDirectory.length() > 0) {
sb.append(generatingDirectory);
sb.append(File.separator);
}
sb.append(className);
sb.append(".class");
return sb.toString();
}
public Class getTargetExtends() {
return targetExtends;
}
public void setTargetExtends(Class extendsClass) {
targetExtends = extendsClass;
}
public Class[] getTargetImplements() {
return targetImplements;
}
public void setTargetImplements(Class[] implementsClasses) {
targetImplements = implementsClasses;
}
String getInitialClassName() {
return initialName;
}
void setInitialClassName(String initialName) {
this.initialName = initialName;
serial = 0;
}
private String generatingDirectory;
private String packageName = "org.mozilla.javascript.gen";
private String initialName = "c";
private static int globalSerial=1;
private int serial=1;
private Class targetExtends;
private Class[] targetImplements;
}

View File

@ -0,0 +1,128 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.*;
public class OptFunctionNode extends FunctionNode {
public OptFunctionNode(String name, Node left, Node right,
ClassNameHelper nameHelper)
{
super(name, left, right);
itsVariableTable = new OptVariableTable();
OptClassNameHelper nh = (OptClassNameHelper) nameHelper;
itsClassName = nh.getJavaScriptClassName(name, false);
}
public String getDirectCallParameterSignature() {
StringBuffer parameterSig = new StringBuffer(
"(Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ "Lorg/mozilla/javascript/Scriptable;");
int pCount = itsVariableTable.getParameterCount();
for (int i = 0; i < pCount; i++) {
parameterSig.append("Ljava/lang/Object;D");
}
parameterSig.append("[Ljava/lang/Object;)");
return parameterSig.toString();
}
public String getClassName() {
return itsClassName;
}
public boolean isTargetOfDirectCall() {
return itsIsTargetOfDirectCall;
}
public void addDirectCallTarget(FunctionNode target) {
if (itsDirectCallTargets == null)
itsDirectCallTargets = new Vector();
for (int i = 0; i < itsDirectCallTargets.size(); i++) // OPT !!
if (((FunctionNode)itsDirectCallTargets.elementAt(i)) == target)
return;
itsDirectCallTargets.addElement(target);
}
public Vector getDirectCallTargets() {
return itsDirectCallTargets;
}
public void setIsTargetOfDirectCall() {
itsIsTargetOfDirectCall = true;
}
public void setParameterNumberContext(boolean b) {
itsParameterNumberContext = b;
}
public boolean getParameterNumberContext() {
return itsParameterNumberContext;
}
public boolean containsCalls(int argCount) {
if ((argCount < itsContainsCallsCount.length) && (argCount >= 0))
return itsContainsCallsCount[argCount];
else
return itsContainsCalls;
}
public void setContainsCalls(int argCount) {
if (argCount < itsContainsCallsCount.length)
itsContainsCallsCount[argCount] = true;
itsContainsCalls = true;
}
public void incrementLocalCount() {
Integer localCount = (Integer)(getProp(Node.LOCALCOUNT_PROP));
if (localCount == null) {
putProp(Node.LOCALCOUNT_PROP, new Integer(1));
} else {
putProp(Node.LOCALCOUNT_PROP,
new Integer(localCount.intValue() + 1));
}
}
private String itsClassName;
private boolean itsIsTargetOfDirectCall;
private boolean itsContainsCalls;
private boolean[] itsContainsCallsCount = new boolean[4];
private boolean itsParameterNumberContext;
private Vector itsDirectCallTargets;
}

View File

@ -0,0 +1,69 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
/**
* This class allows the creation of nodes, and follows the Factory pattern.
*
* @see IRFactory
* @author Norris Boyd
*/
public class OptIRFactory extends IRFactory {
public OptIRFactory(TokenStream ts, ClassNameHelper nameHelper) {
super(ts);
this.nameHelper = nameHelper;
}
public Object createFunctionNode(String name, Object args,
Object statements)
{
if (name == null)
name = "";
OptFunctionNode result = new OptFunctionNode(name, (Node) args,
(Node) statements,
nameHelper);
Context cx = Context.getCurrentContext();
if (cx.getDebugLevel() > 0)
result.setRequiresActivation(true);
return result;
}
private ClassNameHelper nameHelper;
}

View File

@ -0,0 +1,93 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
public class OptLocalVariable extends LocalVariable {
public OptLocalVariable(String name, boolean isParameter) {
super(name, isParameter);
}
public String toString() {
return "LocalVariable : '" + getName()
+ "', index = " + getIndex()
+ ", LiveAcrossCall = " + itsLiveAcrossCall
+ ", isNumber = " + itsIsNumber
+ ", isParameter = " + isParameter()
+ ", JRegister = " + itsJRegister;
}
public void setIsNumber() { itsIsNumber = true; }
public boolean isNumber() { return itsIsNumber; }
public void markLiveAcrossCall() { itsLiveAcrossCall = true; }
public void clearLiveAcrossCall() { itsLiveAcrossCall = false; }
public boolean isLiveAcrossCall() { return itsLiveAcrossCall; }
public void assignJRegister(short aJReg) { itsJRegister = aJReg; }
public short getJRegister() { return itsJRegister; }
public boolean assignType(int aType) { return itsTypeUnion.add(aType); }
public int getTypeUnion() { return itsTypeUnion.getEvent(); }
/**
* Get the offset into the bytecode where the variable becomes live.
* Used for generating the local variable table.
*/
public int getStartPC() {
return initPC;
}
/**
* Set the offset into the bytecode where the variable becomes live.
* Used for generating the local variable table.
*/
public void setStartPC(int pc) {
initPC = pc;
}
private short itsJRegister = -1; // unassigned
private boolean itsLiveAcrossCall;
private boolean itsIsNumber;
private TypeEvent itsTypeUnion = new TypeEvent(); // the union of all assigned types
private int initPC;
}

View File

@ -0,0 +1,311 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
public final class OptRuntime extends ScriptRuntime {
/**
* No instances should be created.
*/
private OptRuntime() {
}
public static Object getElem(Object obj, double dblIndex, Scriptable scope) {
int index;
String s;
index = (int) dblIndex;
s = ((double) index) == dblIndex ? null : toString(new Double(dblIndex));
Scriptable start = obj instanceof Scriptable
? (Scriptable) obj
: toObject(scope, obj);
Scriptable m = start;
if (s != null) {
while (m != null) {
Object result = m.get(s, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
}
return Undefined.instance;
}
while (m != null) {
Object result = m.get(index, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
}
return Undefined.instance;
}
public static Object setElem(Object obj, double dblIndex, Object value,
Scriptable scope)
{
int index;
String s;
index = (int) dblIndex;
s = ((double) index) == dblIndex ?
null : toString(new Double(dblIndex));
Scriptable start = obj instanceof Scriptable
? (Scriptable) obj
: toObject(scope, obj);
Scriptable m = start;
if (s != null) {
do {
if (m.has(s, start)) {
m.put(s, start, value);
return value;
}
m = m.getPrototype();
} while (m != null);
start.put(s, start, value);
return value;
}
do {
if (m.has(index, start)) {
m.put(index, start, value);
return value;
}
m = m.getPrototype();
} while (m != null);
start.put(index, start, value);
return value;
}
public static Object add(Object val1, double val2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(null);
if (!(val1 instanceof String))
return new Double(toNumber(val1) + val2);
return toString(val1) + numberToString(val2, 10);
}
public static Object add(double val1, Object val2) {
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(null);
if (!(val2 instanceof String))
return new Double(toNumber(val2) + val1);
return numberToString(val1, 10) + toString(val2);
}
public static boolean neq(Object x, Object y) {
return !eq(x, y);
}
public static boolean shallowNeq(Object x, Object y) {
return !shallowEq(x, y);
}
public static Boolean cmp_LTB(double d1, Object val2) {
if (cmp_LT(d1, val2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LT(double d1, Object val2) {
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
if (!(val2 instanceof String)) {
if (d1 != d1)
return 0;
double d2 = toNumber(val2);
if (d2 != d2)
return 0;
return d1 < d2 ? 1 : 0;
}
return toString(new Double(d1)).compareTo(toString(val2)) < 0 ? 1 : 0;
}
public static Boolean cmp_LTB(Object val1, double d2) {
if (cmp_LT(val1, d2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LT(Object val1, double d2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
if (!(val1 instanceof String)) {
double d1 = toNumber(val1);
if (d1 != d1)
return 0;
if (d2 != d2)
return 0;
return d1 < d2 ? 1 : 0;
}
return toString(val1).compareTo(toString(new Double(d2))) < 0 ? 1 : 0;
}
public static Boolean cmp_LEB(double d1, Object val2) {
if (cmp_LE(d1, val2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LE(double d1, Object val2) {
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
if (!(val2 instanceof String)) {
if (d1 != d1)
return 0;
double d2 = toNumber(val2);
if (d2 != d2)
return 0;
return d1 <= d2 ? 1 : 0;
}
return toString(new Double(d1)).compareTo(toString(val2)) <= 0 ? 1 : 0;
}
public static Boolean cmp_LEB(Object val1, double d2) {
if (cmp_LE(val1, d2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LE(Object val1, double d2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
if (!(val1 instanceof String)) {
double d1 = toNumber(val1);
if (d1 != d1)
return 0;
if (d2 != d2)
return 0;
return d1 <= d2 ? 1 : 0;
}
return toString(val1).compareTo(toString(new Double(d2))) <= 0 ? 1 : 0;
}
public static int cmp(Object val1, Object val2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
if (!(val1 instanceof String) || !(val2 instanceof String)) {
double d1 = toNumber(val1);
if (d1 != d1)
return -1;
double d2 = toNumber(val2);
if (d2 != d2)
return -1;
return d1 < d2 ? 1 : 0;
}
return toString(val1).compareTo(toString(val2)) < 0 ? 1 : 0;
}
public static Object callSimple(Context cx, String id, Scriptable scope,
Object[] args)
throws JavaScriptException
{
Scriptable obj = scope;
Object prop = null;
Scriptable thisArg = null;
search:
while (obj != null) {
Scriptable m = obj;
do {
prop = m.get(id, obj);
if (prop != Scriptable.NOT_FOUND) {
thisArg = obj;
break search;
}
m = m.getPrototype();
} while (m != null);
obj = obj.getParentScope();
}
if ((prop == null) || (prop == Scriptable.NOT_FOUND)) {
Object[] errorArgs = { id };
throw Context.reportRuntimeError(
getMessage("msg.is.not.defined", errorArgs));
}
while (thisArg instanceof NativeWith)
thisArg = thisArg.getPrototype();
if (thisArg instanceof NativeCall)
thisArg = ScriptableObject.getTopLevelScope(thisArg);
Function function;
try {
function = (Function) prop;
}
catch (ClassCastException e) {
Object[] errorArgs = { toString(prop) };
throw cx.reportRuntimeError(
getMessage("msg.isnt.function", errorArgs));
}
return function.call(cx, function.getParentScope(), thisArg, args);
}
public static Object thisGet(Scriptable thisObj, String id,
Scriptable scope)
{
Object result = thisObj.get(id, thisObj);
if (result != Scriptable.NOT_FOUND)
return result;
Scriptable start = thisObj;
if (start == null) {
throw Context.reportRuntimeError(
getMessage("msg.null.to.object", null));
}
Scriptable m = start;
do {
result = m.get(id, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
} while (m != null);
return Undefined.instance;
}
public static Object[] padStart(Object[] currentArgs, int count) {
Object[] result = new Object[currentArgs.length + count];
System.arraycopy(currentArgs, 0, result, count, currentArgs.length);
return result;
}
}

View File

@ -0,0 +1,190 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;
/**
* This class performs node transforms to prepare for optimization.
*
* @see NodeTransformer
* @author Norris Boyd
*/
class OptTransformer extends NodeTransformer {
private Hashtable theFnClassNameList;
OptTransformer(Hashtable theFnClassNameList) {
this.theFnClassNameList = theFnClassNameList;
}
public NodeTransformer newInstance() {
return new OptTransformer((Hashtable) theFnClassNameList.clone());
}
public IRFactory createIRFactory(TokenStream ts) {
return new IRFactory(ts);
}
public Node transform(Node tree, Node enclosing, TokenStream ts) {
// Collect all of the contained functions into a hashtable
// so that the call optimizer can access the class name & parameter
// count for any call it encounters
collectContainedFunctions(tree.getFirstChild());
return super.transform(tree, enclosing, ts);
}
protected VariableTable createVariableTable() {
return new OptVariableTable();
}
private int detectDirectCall(Node node, Node tree)
{
Context cx = Context.getCurrentContext();
int optLevel = cx.getOptimizationLevel();
Node left = node.getFirstChild();
// count the arguments
int argCount = 0;
Node arg = left.getNextSibling();
while (arg != null) {
arg = arg.getNextSibling();
argCount++;
}
if (tree.getType() == TokenStream.FUNCTION && optLevel > 0) {
if (left.getType() == TokenStream.NAME) {
markDirectCall(tree, node, argCount, left.getString());
} else {
if (left.getType() == TokenStream.GETPROP) {
Node name = left.getFirstChild().getNextSibling();
markDirectCall(tree, node, argCount, name.getString());
}
}
}
return argCount;
}
protected void visitNew(Node node, Node tree) {
detectDirectCall(node, tree);
super.visitNew(node, tree);
}
protected void visitCall(Node node, Node tree) {
int argCount = detectDirectCall(node, tree);
if (inFunction && (argCount == 0))
((OptFunctionNode)tree).setContainsCalls(argCount);
super.visitCall(node, tree);
}
/*
* Optimize a call site by converting call("a", b, c) into :
*
* FunctionObjectFor"a" <-- instance variable init'd by constructor
*
* // this is a DIRECTCALL node
* fn = GetProp(tmp = GetBase("a"), "a");
* if (fn == FunctionObjectFor"a")
* fn.call(tmp, b, c)
* else
* ScriptRuntime.Call(fn, tmp, b, c)
*/
void markDirectCall(Node containingTree, Node callNode, int argCount,
String targetName)
{
OptFunctionNode theFunction
= (OptFunctionNode)theFnClassNameList.get(targetName);
if (theFunction != null) {
VariableTable varTable = theFunction.getVariableTable();
// Refuse to directCall any function with more
// than 32 parameters - prevent code explosion
// for wacky test cases
if (varTable.getParameterCount() > 32)
return;
if (argCount == varTable.getParameterCount()) {
callNode.putProp(Node.DIRECTCALL_PROP, theFunction);
((OptFunctionNode)containingTree)
.addDirectCallTarget(theFunction);
theFunction.setIsTargetOfDirectCall();
}
}
}
/**
* Collect all of the contained functions into a hashtable
* so that the call optimizer can access the class name & parameter
* count for any call it encounters
*/
void collectContainedFunctions(Node node) {
for (Node tNode=node; tNode != null; tNode = tNode.getNextSibling()) {
if (tNode.getType() == TokenStream.FUNCTION) {
FunctionNode fnNode = (FunctionNode)
tNode.getProp(Node.FUNCTION_PROP);
if (fnNode.getFunctionName().length() != 0) {
String name = fnNode.getFunctionName();
Object oldFn = theFnClassNameList.get(name);
if (oldFn == fnNode) {
// already processed this list of functions
return;
}
/*
if (oldFn != null) {
Object prop = fnNode.getProp(Node.BASE_LINENO_PROP);
Object[] errArgs = { name };
Context.reportWarning(
Context.getMessage("msg.fn.redecl", errArgs),
(String) fnNode.getProp(Node.SOURCENAME_PROP),
prop == null ? 0 : ((Integer) prop).intValue(),
null, 0);
}
*/
theFnClassNameList.put(name, fnNode);
}
addParameters(fnNode);
}
}
}
}

View File

@ -0,0 +1,74 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.io.*;
import java.util.*;
public class OptVariableTable extends VariableTable {
public void print(PrintWriter pw)
{
System.out.println("Variable Table, size = " + itsVariables.size());
for (int i = 0; i < itsVariables.size(); i++) {
LocalVariable lVar = (LocalVariable)(itsVariables.elementAt(i));
pw.println(lVar.toString());
}
}
public void assignParameterJRegs()
{
// 0 is reserved for function Object 'this'
// 1 is reserved for context
// 2 is reserved for parentScope
// 3 is reserved for script 'this'
short jReg = 4;
for (int i = 0; i < varStart; i++) {
OptLocalVariable lVar = (OptLocalVariable)
itsVariables.elementAt(i);
lVar.assignJRegister(jReg);
jReg += 3; // 3 is 1 for Object parm and 2 for double parm
}
}
public LocalVariable createLocalVariable(String name, boolean isParameter)
{
return new OptLocalVariable(name, isParameter);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.Stack;
public class StmtNodeIterator {
public StmtNodeIterator(Node start)
{
itsStart = start;
}
private Node findFirstInterestingNode(Node theNode)
{
if (theNode == null) return null;
if ((theNode.getType() == TokenStream.BLOCK)
|| (theNode.getType() == TokenStream.LOOP)
|| (theNode.getType() == TokenStream.FUNCTION)) {
if (theNode.getFirst() == null) {
return findFirstInterestingNode(theNode.getNext());
}
else {
itsStack.push(theNode);
return findFirstInterestingNode(theNode.getFirst());
}
}
else
return theNode;
}
public Node nextNode()
{
if (itsCurrentNode == null)
return itsCurrentNode = findFirstInterestingNode(itsStart);
itsCurrentNode = itsCurrentNode.getNext();
if (itsCurrentNode == null) {
while ( ! itsStack.isEmpty()) {
Node n = (Node)(itsStack.pop());
if (n.getNext() != null) {
return itsCurrentNode = findFirstInterestingNode(n.getNext());
}
}
return null;
}
else
return itsCurrentNode = findFirstInterestingNode(itsCurrentNode);
}
private Stack itsStack = new Stack();
private Node itsStart;
private Node itsCurrentNode;
}

View File

@ -0,0 +1,67 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
public class TypeEvent {
public static final int EventBitLength = 2;
public static final int
AnyType = (1 << EventBitLength) - 1,
NumberType = 0x1,
NoType = 0x0;
public TypeEvent(int theEvent)
{
itsEvent = theEvent;
}
public TypeEvent()
{
itsEvent = NoType;
}
public boolean add(int anOther)
{
return ((itsEvent |= anOther) != anOther);
}
public int getEvent() { return itsEvent; }
private int itsEvent;
}

View File

@ -0,0 +1,293 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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):
* Christine Begle
* 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.tools.jsc;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import java.text.MessageFormat;
import org.mozilla.javascript.*;
import org.mozilla.javascript.tools.ToolErrorReporter;
/**
* @author Norris Boyd
*/
public class Main {
/**
* 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
* compile scripts.
*/
public static void main(String args[]) {
Context cx = Context.enter();
reporter = new ToolErrorReporter(true);
cx.setErrorReporter(reporter);
args = processOptions(cx, args);
if ( ! reporter.hasReportedError())
processSource(cx, args);
cx.exit();
}
/**
* Parse arguments.
*
*/
public static String[] processOptions(Context cx, String args[]) {
cx.setTargetPackage(""); // default to no package
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;
}
try {
if (arg.equals("-version") && ++i < args.length) {
int version = Integer.parseInt(args[i]);
cx.setLanguageVersion(version);
continue;
}
if ((arg.equals("-opt") || arg.equals("-O")) &&
++i < args.length)
{
int optLevel = Integer.parseInt(args[i]);
cx.setOptimizationLevel(optLevel);
continue;
}
if (arg.equals("-debuglevel") && ++i < args.length) {
int debugLevel = Integer.parseInt(args[i]);
cx.setDebugLevel(debugLevel);
continue;
}
}
catch (NumberFormatException e) {
cx.reportError( ToolErrorReporter.getMessage("msg.jsc.usage",
args[i] ));
continue;
}
if (arg.equals("-nosource")) {
cx.setGeneratingSource(false);
continue;
}
if (arg.equals("-debug") || arg.equals("-g")) {
cx.setGeneratingDebug(true);
continue;
}
if (arg.equals("-o") && ++i < args.length) {
String outFile = args[i];
if (!Character.isJavaIdentifierStart(outFile.charAt(0))) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.invalid.classfile.name",
outFile));
continue;
}
for ( int j = 1; j < outFile.length(); j++ ) {
if ( (!Character.isJavaIdentifierPart(outFile.charAt(j)) &&
outFile.charAt(j) != '.') || (outFile.charAt(j) == '.' &&
(!outFile.endsWith(".class") || j != outFile.length()-6 )) )
{
cx.reportError(ToolErrorReporter.getMessage(
"msg.invalid.classfile.name",
outFile ));
break;
}
}
cx.setTargetClassFileName(outFile);
hasOutOption = true;
continue;
}
if (arg.equals("-package") && ++i < args.length) {
String targetPackage = args[i];
for ( int j = 0; j < targetPackage.length(); j++ ) {
if ( !Character.isJavaIdentifierStart(targetPackage.charAt(j))) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.package.name",
targetPackage));
continue;
}
for ( int k = ++j; k< targetPackage.length(); k++, j++ ) {
if (targetPackage.charAt(k) == '.' &&
targetPackage.charAt(k-1) != '.' &&
k != targetPackage.length()-1)
{
continue;
}
if (!Character.isJavaIdentifierPart(
targetPackage.charAt(k)))
{
cx.reportError(ToolErrorReporter.getMessage(
"msg.package.name",
targetPackage));
continue;
}
continue;
}
}
cx.setTargetPackage(targetPackage);
continue;
}
if (arg.equals("-extends") && ++i < args.length) {
String targetExtends = args[i];
try {
cx.setTargetExtends(Class.forName(targetExtends));
} catch (ClassNotFoundException e) {
throw new Error(e.toString()); // TODO: better error
}
continue;
}
if (arg.equals("-implements") && ++i < args.length) {
// TODO: allow for multiple comma-separated interfaces.
String targetImplements = args[i];
try {
Class[] implementsClasses = { Class.forName(targetImplements) };
cx.setTargetImplements(implementsClasses);
} catch (ClassNotFoundException e) {
throw new Error(e.toString()); // TODO: better error
}
continue;
}
usage(arg);
}
// no file name
p(ToolErrorReporter.getMessage("msg.no.file"));
System.exit(1);
return null;
}
/**
* Print a usage message.
*/
public static void usage(String s) {
p(ToolErrorReporter.getMessage("msg.jsc.usage", s));
System.exit(1);
}
/**
* Compile JavaScript source.
*
*/
public static void processSource(Context cx, String[] filenames) {
if (hasOutOption && filenames.length > 1) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.multiple.js.to.file",
cx.getTargetClassFileName()));
}
for (int i=0; i < filenames.length; i++) {
String filename = filenames[i];
File f = new File(filename);
if (!f.exists()) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.jsfile.not.found",
filename));
return;
}
if (!filename.endsWith(".js")) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.extension.not.js",
filename));
return;
}
if (!hasOutOption) {
String name = f.getName();
String nojs = name.substring(0, name.length() - 3);
String className = getClassName(nojs) + ".class";
String out = f.getParent() == null ? className : f.getParent() +
File.separator + className;
cx.setTargetClassFileName(out);
}
if (cx.getTargetClassFileName() == null) {
cx.reportError(ToolErrorReporter.getMessage("msg.no-opt"));
}
try {
Reader in = new FileReader(filename);
cx.compileReader(null, in, filename, 1, null);
}
catch (FileNotFoundException ex) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.couldnt.open",
filename));
return;
}
catch (IOException ioe) {
cx.reportError(ioe.toString());
}
}
}
/**
* Verify that class file names are legal Java identifiers. Substitute
* illegal characters with underscores, and prepend the name with an
* underscore if the file name does not begin with a JavaLetter.
*/
static String getClassName(String name) {
char[] s = new char[name.length()+1];
char c;
int j = 0;
if (!Character.isJavaIdentifierStart(name.charAt(0))) {
s[j++] = '_';
}
for (int i=0; i < name.length(); i++, j++) {
c = name.charAt(i);
if ( Character.isJavaIdentifierPart(c) ) {
s[j] = c;
} else {
s[j] = '_';
}
}
return (new String(s)).trim();
}
private static void p(String s) {
System.out.println(s);
}
private static boolean hasOutOption = false;
private static ToolErrorReporter reporter;
}

View File

@ -108,7 +108,7 @@ public class Main extends ScriptableObject {
try {
Class clazz = Class.forName(
"com.netscape.jsdebugging.ifcui.launcher.rhino.LaunchNetscapeJavaScriptDebugger");
"org.mozilla.jsdebugging.ifcui.launcher.rhino.LaunchNetscapeJavaScriptDebugger");
ILaunchableDebugger debugger =
(ILaunchableDebugger) clazz.newInstance();
debugger.launch(global.debug_dm, global.debug_stm, false);

View File

@ -1666,9 +1666,9 @@ public final class Context {
static {
try {
codegenClass = Class.forName(
"com.netscape.javascript.optimizer.Codegen");
"org.mozilla.javascript.optimizer.Codegen");
Class nameHelperClass = Class.forName(
"com.netscape.javascript.optimizer.OptClassNameHelper");
"org.mozilla.javascript.optimizer.OptClassNameHelper");
nameHelper = (ClassNameHelper)nameHelperClass.newInstance();
} catch (ClassNotFoundException x) {
// ...must be running lite, that's ok

View File

@ -0,0 +1,688 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import org.mozilla.classfile.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.PrintWriter;
import java.io.StringWriter;
public class Block {
public Block(int startNodeIndex, int endNodeIndex, Node[] statementNodes)
{
itsStartNodeIndex = startNodeIndex;
itsEndNodeIndex = endNodeIndex;
itsStatementNodes = statementNodes;
}
public void setBlockID(int id) { itsBlockID = id; }
public int getBlockID() { return itsBlockID; }
public Node getStartNode() { return itsStatementNodes[itsStartNodeIndex]; }
public Node getEndNode() { return itsStatementNodes[itsEndNodeIndex]; }
public Block[] getPredecessorList() { return itsPredecessors; }
public Block[] getSuccessorList() { return itsSuccessors; }
public static Block[] buildBlocks(Node[] statementNodes)
{
// a mapping from each target node to the block it begins
Hashtable theTargetBlocks = new Hashtable();
Vector theBlocks = new Vector();
// there's a block that starts at index 0
int beginNodeIndex = 0;
for (int i = 0; i < statementNodes.length; i++) {
switch (statementNodes[i].getType()) {
case TokenStream.TARGET :
{
if (i != beginNodeIndex) {
FatBlock fb = new FatBlock(beginNodeIndex,
i - 1, statementNodes);
if (statementNodes[beginNodeIndex].getType()
== TokenStream.TARGET)
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
theBlocks.addElement(fb);
// start the next block at this node
beginNodeIndex = i;
}
}
break;
case TokenStream.IFNE :
case TokenStream.IFEQ :
case TokenStream.GOTO :
{
FatBlock fb = new FatBlock(beginNodeIndex,
i, statementNodes);
if (statementNodes[beginNodeIndex].getType()
== TokenStream.TARGET)
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
theBlocks.addElement(fb);
// start the next block at the next node
beginNodeIndex = i + 1;
}
break;
}
}
if ((beginNodeIndex != statementNodes.length)) {
FatBlock fb = new FatBlock(beginNodeIndex,
statementNodes.length - 1,
statementNodes);
if (statementNodes[beginNodeIndex].getType() == TokenStream.TARGET)
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
theBlocks.addElement(fb);
}
// build successor and predecessor links
for (int i = 0; i < theBlocks.size(); i++) {
FatBlock fb = (FatBlock)(theBlocks.elementAt(i));
Node blockEndNode = fb.getEndNode();
int blockEndNodeType = blockEndNode.getType();
if ((blockEndNodeType != TokenStream.GOTO)
&& (i < (theBlocks.size() - 1))) {
FatBlock fallThruTarget = (FatBlock)(theBlocks.elementAt(i + 1));
fb.addSuccessor(fallThruTarget);
fallThruTarget.addPredecessor(fb);
}
if ( (blockEndNodeType == TokenStream.IFNE)
|| (blockEndNodeType == TokenStream.IFEQ)
|| (blockEndNodeType == TokenStream.GOTO) ) {
Node target = (Node)(blockEndNode.getProp(Node.TARGET_PROP));
FatBlock branchTargetBlock
= (FatBlock)(theTargetBlocks.get(target));
target.putProp(Node.TARGETBLOCK_PROP,
branchTargetBlock.getSlimmerSelf());
fb.addSuccessor(branchTargetBlock);
branchTargetBlock.addPredecessor(fb);
}
}
Block[] result = new Block[theBlocks.size()];
for (int i = 0; i < theBlocks.size(); i++) {
FatBlock fb = (FatBlock)(theBlocks.elementAt(i));
result[i] = fb.diet();
result[i].setBlockID(i);
}
return result;
}
public static String toString(Block[] blockList, Node[] statementNodes)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.println(blockList.length + " Blocks");
for (int i = 0; i < blockList.length; i++) {
Block b = blockList[i];
pw.println("#" + b.itsBlockID);
pw.println("from " + b.itsStartNodeIndex
+ " "
+ statementNodes[b.itsStartNodeIndex].toString());
pw.println("thru " + b.itsEndNodeIndex
+ " "
+ statementNodes[b.itsEndNodeIndex].toString());
pw.print("Predecessors ");
if (b.itsPredecessors != null) {
for (int j = 0; j < b.itsPredecessors.length; j++)
pw.print(b.itsPredecessors[j].getBlockID() + " ");
pw.println();
}
else
pw.println("none");
pw.print("Successors ");
if (b.itsSuccessors != null) {
for (int j = 0; j < b.itsSuccessors.length; j++)
pw.print(b.itsSuccessors[j].getBlockID() + " ");
pw.println();
}
else
pw.println("none");
}
return sw.toString();
}
/*
We maintain the liveSet as each statement executes, identifying
those variables that are live across function calls
*/
void lookForVariablesAndCalls(Node n, boolean liveSet[],
VariableTable theVariables)
{
switch (n.getType()) {
case TokenStream.SETVAR :
{
Node lhs = n.getFirstChild();
Node rhs = lhs.getNextSibling();
lookForVariablesAndCalls(rhs, liveSet, theVariables);
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
liveSet[theVarIndex] = true;
}
}
break;
case TokenStream.CALL : {
Node child = n.getFirstChild();
while (child != null) {
lookForVariablesAndCalls(child, liveSet, theVariables);
child = child.getNextSibling();
}
for (int i = 0; i < liveSet.length; i++) {
if (liveSet[i])
((OptLocalVariable)theVariables.get(i)).markLiveAcrossCall();
}
}
break;
case TokenStream.GETVAR :
{
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
if ((n.getProp(Node.LASTUSE_PROP) != null)
&& !itsLiveOnExitSet.test(theVarIndex))
liveSet[theVarIndex] = false;
}
}
break;
default :
Node child = n.getFirstChild();
while (child != null) {
lookForVariablesAndCalls(child, liveSet, theVariables);
child = child.getNextSibling();
}
break;
}
}
void markVolatileVariables(VariableTable theVariables)
{
boolean liveSet[] = new boolean[theVariables.size()];
for (int i = 0; i < liveSet.length; i++)
liveSet[i] = itsLiveOnEntrySet.test(i);
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
lookForVariablesAndCalls(n, liveSet, theVariables);
}
}
/*
We're tracking uses and defs - in order to
build the def set and to identify the last use
nodes.
The itsNotDefSet is built reversed then flipped later.
*/
void lookForVariableAccess(Node n, Node lastUse[])
{
switch (n.getType()) {
case TokenStream.DEC :
case TokenStream.INC :
{
Node child = n.getFirstChild();
if (child.getType() == TokenStream.GETVAR) {
Object theVarProp = child.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
if (!itsNotDefSet.test(theVarIndex))
itsUseBeforeDefSet.set(theVarIndex);
itsNotDefSet.set(theVarIndex);
}
}
}
break;
case TokenStream.SETVAR :
{
Node lhs = n.getFirstChild();
Node rhs = lhs.getNextSibling();
lookForVariableAccess(rhs, lastUse);
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
itsNotDefSet.set(theVarIndex);
if (lastUse[theVarIndex] != null)
lastUse[theVarIndex].putProp(Node.LASTUSE_PROP,
theVarProp);
}
}
break;
case TokenStream.GETVAR :
{
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
if (theVarProp != null) {
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
if (!itsNotDefSet.test(theVarIndex))
itsUseBeforeDefSet.set(theVarIndex);
lastUse[theVarIndex] = n;
}
}
break;
default :
Node child = n.getFirstChild();
while (child != null) {
lookForVariableAccess(child, lastUse);
child = child.getNextSibling();
}
break;
}
}
/*
build the live on entry/exit sets.
Then walk the trees looking for defs/uses of variables
and build the def and useBeforeDef sets.
*/
public void initLiveOnEntrySets(VariableTable theVariables)
{
int listLength = theVariables.size();
Node lastUse[] = new Node[listLength];
itsUseBeforeDefSet = new DataFlowBitSet(listLength);
itsNotDefSet = new DataFlowBitSet(listLength);
itsLiveOnEntrySet = new DataFlowBitSet(listLength);
itsLiveOnExitSet = new DataFlowBitSet(listLength);
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
lookForVariableAccess(n, lastUse);
}
for (int i = 0; i < listLength; i++) {
if (lastUse[i] != null)
lastUse[i].putProp(Node.LASTUSE_PROP, this);
}
itsNotDefSet.not(); // truth in advertising
}
/*
the liveOnEntry of each successor is the liveOnExit for this block.
The liveOnEntry for this block is -
liveOnEntry = liveOnExit - defsInThisBlock + useBeforeDefsInThisBlock
*/
boolean doReachedUseDataFlow()
{
itsLiveOnExitSet.clear();
if (itsSuccessors != null)
for (int i = 0; i < itsSuccessors.length; i++)
itsLiveOnExitSet.or(itsSuccessors[i].itsLiveOnEntrySet);
return itsLiveOnEntrySet.df2(itsLiveOnExitSet,
itsUseBeforeDefSet, itsNotDefSet);
}
/*
the type of an expression is relatively unknown. Cases we can be sure
about are -
Literals,
Arithmetic operations - always return a Number
*/
int findExpressionType(Node n)
{
switch (n.getType()) {
case TokenStream.NUMBER : {
/* distinguish between integers & f.p.s ?
Number num = ((NumberNode)n).getNumber();
if ((num instanceof Byte)
|| (num instanceof Short)
|| (num instanceof Integer)) {
}
else {
}
*/
return TypeEvent.NumberType;
}
case TokenStream.NEW :
case TokenStream.CALL :
return TypeEvent.NoType;
case TokenStream.GETELEM :
return TypeEvent.AnyType;
case TokenStream.GETVAR : {
OptLocalVariable theVar = (OptLocalVariable)
(n.getProp(Node.VARIABLE_PROP));
if (theVar != null)
return theVar.getTypeUnion();
}
case TokenStream.INC :
case TokenStream.DEC :
case TokenStream.DIV:
case TokenStream.MOD:
case TokenStream.BITOR:
case TokenStream.BITXOR:
case TokenStream.BITAND:
case TokenStream.LSH:
case TokenStream.RSH:
case TokenStream.URSH:
case TokenStream.SUB : {
return TypeEvent.NumberType;
}
case TokenStream.ADD : {
// if the lhs & rhs are known to be numbers, we can be sure that's
// the result, otherwise it could be a string.
Node child = n.getFirstChild();
int lType = findExpressionType(child);
int rType = findExpressionType(child.getNextSibling());
return lType | rType; // we're not distinguishng strings yet
}
default : {
Node child = n.getFirstChild();
if (child == null)
return TypeEvent.AnyType;
else {
int result = TypeEvent.NoType;
while (child != null) {
result |= findExpressionType(child);
child = child.getNextSibling();
}
return result;
}
}
}
}
boolean findDefPoints(Node n)
{
boolean result = false;
switch (n.getType()) {
default : {
Node child = n.getFirstChild();
while (child != null) {
result |= findDefPoints(child);
child = child.getNextSibling();
}
}
break;
case TokenStream.DEC :
case TokenStream.INC : {
Node firstChild = n.getFirstChild();
OptLocalVariable theVar = (OptLocalVariable)
(firstChild.getProp(Node.VARIABLE_PROP));
if (theVar != null) {
// theVar is a Number now
result |= theVar.assignType(TypeEvent.NumberType);
}
}
break;
case TokenStream.SETPROP : {
Node baseChild = n.getFirstChild();
Node nameChild = baseChild.getNextSibling();
Node rhs = nameChild.getNextSibling();
if (baseChild != null) {
if (baseChild.getType() == TokenStream.GETVAR) {
OptLocalVariable theVar = (OptLocalVariable)
(baseChild.getProp(Node.VARIABLE_PROP));
if (theVar != null)
theVar.assignType(TypeEvent.AnyType);
}
result |= findDefPoints(baseChild);
}
if (nameChild != null) result |= findDefPoints(nameChild);
if (rhs != null) result |= findDefPoints(rhs);
}
break;
case TokenStream.SETVAR : {
Node firstChild = n.getFirstChild();
OptLocalVariable theVar = (OptLocalVariable)
(n.getProp(Node.VARIABLE_PROP));
if (theVar != null) {
Node rValue = firstChild.getNextSibling();
int theType = findExpressionType(rValue);
result |= theVar.assignType(theType);
}
}
break;
}
return result;
}
// a total misnomer for now. To start with we're only trying to find
// duplicate getProp calls on 'this' that can be merged
void localCSE(Node parent, Node n, Hashtable theCSETable, OptFunctionNode theFunction)
{
switch (n.getType()) {
default : {
Node child = n.getFirstChild();
while (child != null) {
localCSE(n, child, theCSETable, theFunction);
child = child.getNextSibling();
}
}
break;
case TokenStream.DEC :
case TokenStream.INC : {
Node child = n.getFirstChild();
if (child.getType() == TokenStream.GETPROP) {
Node nameChild = child.getFirstChild().getNextSibling();
if (nameChild.getType() == TokenStream.STRING)
theCSETable.remove(nameChild.getString());
else
theCSETable.clear();
}
else
if (child.getType() != TokenStream.GETVAR)
theCSETable.clear();
}
break;
case TokenStream.SETPROP : {
Node baseChild = n.getFirstChild();
Node nameChild = baseChild.getNextSibling();
Node rhs = nameChild.getNextSibling();
if (baseChild != null) localCSE(n, baseChild, theCSETable, theFunction);
if (nameChild != null) localCSE(n, nameChild, theCSETable, theFunction);
if (rhs != null) localCSE(n, rhs, theCSETable, theFunction);
if (nameChild.getType() == TokenStream.STRING) {
theCSETable.remove(nameChild.getString());
// System.out.println("clear at SETPROP " + ((StringNode)nameChild).getString());
}
else {
theCSETable.clear();
// System.out.println("clear all at SETPROP");
}
}
break;
case TokenStream.GETPROP : {
Node baseChild = n.getFirstChild();
if (baseChild != null) localCSE(n, baseChild, theCSETable, theFunction);
if ((baseChild.getType() == TokenStream.PRIMARY)
&& (baseChild.getInt() == TokenStream.THIS)) {
Node nameChild = baseChild.getNextSibling();
if (nameChild.getType() == TokenStream.STRING) {
String theName = nameChild.getString();
// System.out.println("considering " + theName);
Object cse = theCSETable.get(theName);
if (cse == null) {
theCSETable.put(theName, new CSEHolder(parent, n));
}
else {
if (parent != null) {
// System.out.println("Yay for " + theName);
Node theCSE;
if (cse instanceof CSEHolder) {
CSEHolder cseHolder = (CSEHolder)cse;
Node nextChild = cseHolder.getPropChild.getNextSibling();
cseHolder.getPropParent.removeChild(cseHolder.getPropChild);
theCSE = itsIRFactory.createNewLocal(cseHolder.getPropChild);
theFunction.incrementLocalCount();
if (nextChild == null)
cseHolder.getPropParent.addChildToBack(theCSE);
else
cseHolder.getPropParent.addChildBefore(theCSE, nextChild);
theCSETable.put(theName, theCSE);
}
else
theCSE = (Node)cse;
Node nextChild = n.getNextSibling();
parent.removeChild(n);
Node cseUse = itsIRFactory.createUseLocal(theCSE);
if (nextChild == null)
parent.addChildToBack(cseUse);
else
parent.addChildBefore(cseUse, nextChild);
}
}
}
}
}
break;
case TokenStream.SETELEM : {
Node lhsBase = n.getFirstChild();
Node lhsIndex = lhsBase.getNextSibling();
Node rhs = lhsIndex.getNextSibling();
if (lhsBase != null) localCSE(n, lhsBase, theCSETable, theFunction);
if (lhsIndex != null) localCSE(n, lhsIndex, theCSETable, theFunction);
if (rhs != null) localCSE(n, rhs, theCSETable, theFunction);
theCSETable.clear();
//System.out.println("clear all at SETELEM");
}
break;
case TokenStream.CALL : {
Node child = n.getFirstChild();
while (child != null) {
localCSE(n, child, theCSETable, theFunction);
child = child.getNextSibling();
}
theCSETable.clear();
//System.out.println("clear all at CALL");
}
break;
}
}
private IRFactory itsIRFactory;
Hashtable localCSE(Hashtable theCSETable, OptFunctionNode theFunction)
{
itsIRFactory = new IRFactory(null);
if (theCSETable == null) theCSETable = new Hashtable(5);
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
if (n != null)
localCSE(null, n, theCSETable, theFunction);
}
return theCSETable;
}
void findDefs()
{
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
if (n != null)
findDefPoints(n);
}
}
public boolean doTypeFlow()
{
boolean changed = false;
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
Node n = itsStatementNodes[i];
if (n != null)
changed |= findDefPoints(n);
}
return changed;
}
public boolean isLiveOnEntry(int index)
{
return (itsLiveOnEntrySet != null) && (itsLiveOnEntrySet.test(index));
}
public void printLiveOnEntrySet(PrintWriter pw, VariableTable theVariables)
{
for (int i = 0; i < theVariables.size(); i++) {
if (itsUseBeforeDefSet.test(i))
pw.println(theVariables.get(i).getName() + " is used before def'd");
if (itsNotDefSet.test(i))
pw.println(theVariables.get(i).getName() + " is not def'd");
if (itsLiveOnEntrySet.test(i))
pw.println(theVariables.get(i).getName() + " is live on entry");
if (itsLiveOnExitSet.test(i))
pw.println(theVariables.get(i).getName() + " is live on exit");
}
}
public void setSuccessorList(Block[] b) { itsSuccessors = b; }
public void setPredecessorList(Block[] b) { itsPredecessors = b; }
// all the Blocks that come immediately after this
private Block[] itsSuccessors;
// all the Blocks that come immediately before this
private Block[] itsPredecessors;
private int itsStartNodeIndex; // the Node at the start of the block
private int itsEndNodeIndex; // the Node at the end of the block
private Node itsStatementNodes[]; // the list of all statement nodes
private int itsBlockID; // a unique index for each block
// reaching def bit sets -
private DataFlowBitSet itsLiveOnEntrySet;
private DataFlowBitSet itsLiveOnExitSet;
private DataFlowBitSet itsUseBeforeDefSet;
private DataFlowBitSet itsNotDefSet;
}
class CSEHolder {
CSEHolder(Node parent, Node child)
{
getPropParent = parent;
getPropChild = child;
}
Node getPropParent;
Node getPropChild;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
class DataFlowBitSet {
private int itsBits[];
int itsSize;
DataFlowBitSet(int size)
{
itsSize = size;
itsBits = new int[(size >> 5) + 1];
}
int size()
{
return itsSize;
}
void set(int n)
{
if ((n < 0) || (n >= itsSize))
throw new RuntimeException("DataFlowBitSet bad index " + n);
itsBits[n >> 5] |= 1 << (n & 31);
}
boolean test(int n)
{
if ((n < 0) || (n >= itsSize))
throw new RuntimeException("DataFlowBitSet bad index " + n);
return ((itsBits[n >> 5] & (1 << (n & 31))) != 0);
}
void not()
{
int bitsLength = itsBits.length;
for (int i = 0; i < bitsLength; i++)
itsBits[i] = ~itsBits[i];
}
void clear(int n)
{
if ((n < 0) || (n >= itsSize))
throw new RuntimeException("DataFlowBitSet bad index " + n);
itsBits[n >> 5] &= ~(1 << (n & 31));
}
void clear()
{
int bitsLength = itsBits.length;
for (int i = 0; i < bitsLength; i++)
itsBits[i] = 0;
}
void or(DataFlowBitSet b)
{
int bitsLength = itsBits.length;
for (int i = 0; i < bitsLength; i++)
itsBits[i] |= b.itsBits[i];
}
public String toString()
{
StringBuffer result = new StringBuffer();
result.append("DataFlowBitSet, size = " + itsSize + "\n");
for (int i = 0; i < itsBits.length; i++)
result.append(Integer.toHexString(itsBits[i]) + " ");
return result.toString();
}
boolean df(DataFlowBitSet in, DataFlowBitSet gen, DataFlowBitSet notKill)
{
int bitsLength = itsBits.length;
boolean changed = false;
for (int i = 0; i < bitsLength; i++) {
int oldBits = itsBits[i];
itsBits[i] = (in.itsBits[i] | gen.itsBits[i]) & notKill.itsBits[i];
changed |= (oldBits != itsBits[i]);
}
return changed;
}
boolean df2(DataFlowBitSet in, DataFlowBitSet gen, DataFlowBitSet notKill)
{
int bitsLength = itsBits.length;
boolean changed = false;
for (int i = 0; i < bitsLength; i++) {
int oldBits = itsBits[i];
itsBits[i] = (in.itsBits[i] & notKill.itsBits[i]) | gen.itsBits[i];
changed |= (oldBits != itsBits[i]);
}
return changed;
}
}

View File

@ -0,0 +1,92 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
public class FatBlock {
public FatBlock(int startNodeIndex, int endNodeIndex, Node[] statementNodes)
{
itsShadowOfFormerSelf = new Block(startNodeIndex, endNodeIndex, statementNodes);
}
public Node getEndNode()
{ return itsShadowOfFormerSelf.getEndNode(); }
public Block getSlimmerSelf()
{ return itsShadowOfFormerSelf; }
private Block[] reduceToArray(Hashtable h)
{
Block[] result = null;
if (!h.isEmpty()) {
result = new Block[h.size()];
Enumeration enum = h.elements();
int i = 0;
while (enum.hasMoreElements()) {
FatBlock fb = (FatBlock)(enum.nextElement());
result[i++] = fb.itsShadowOfFormerSelf;
}
}
return result;
}
Block diet()
{
itsShadowOfFormerSelf.setSuccessorList(reduceToArray(itsSuccessors));
itsShadowOfFormerSelf.setPredecessorList(reduceToArray(itsPredecessors));
return itsShadowOfFormerSelf;
}
public void addSuccessor(FatBlock b) { itsSuccessors.put(b, b); }
public void addPredecessor(FatBlock b) { itsPredecessors.put(b, b); }
// all the Blocks that come immediately after this
private Hashtable itsSuccessors = new Hashtable(4);
// all the Blocks that come immediately before this
private Hashtable itsPredecessors = new Hashtable(4);
private Block itsShadowOfFormerSelf;
}

View File

@ -0,0 +1,71 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import java.util.*;
/**
* Load generated classes that implement JavaScript scripts
* or functions.
*
* @author Norris Boyd
*/
final class JavaScriptClassLoader extends ClassLoader {
JavaScriptClassLoader() {
}
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) {
// Experimental change for JShell, use outer class loader.
ClassLoader loader = JavaScriptClassLoader.class.getClassLoader();
if (loader != null)
return loader.loadClass(name);
clazz = findSystemClass(name);
}
if (resolve)
resolveClass(clazz);
return clazz;
}
}

View File

@ -0,0 +1,142 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.io.*;
public class OptClassNameHelper implements ClassNameHelper {
public String getGeneratingDirectory() {
return generatingDirectory;
}
public synchronized String getJavaScriptClassName(String functionName,
boolean primary)
{
StringBuffer s = new StringBuffer();
if (packageName != null && packageName.length() > 0) {
s.append(packageName);
s.append('.');
}
s.append(initialName);
if (generatingDirectory != null) {
if (functionName != null) {
s.append('$');
s.append(functionName);
} else if (!primary) {
s.append(++serial);
}
} else {
s.append(globalSerial++);
}
return s.toString();
}
public String getTargetClassFileName() {
return getTargetClassFileName(getInitialClassName());
}
public void setTargetClassFileName(String classFileName) {
int lastSeparator = classFileName.lastIndexOf('/');
String initialName;
if (lastSeparator == -1) {
generatingDirectory = "";
initialName = classFileName;
} else {
generatingDirectory = classFileName.substring(0, lastSeparator);
initialName = classFileName.substring(lastSeparator+1);
}
if (initialName.endsWith(".class"))
initialName = initialName.substring(0, initialName.length() - 6);
setInitialClassName(initialName);
}
public String getTargetPackage() {
return packageName;
}
public void setTargetPackage(String targetPackage) {
this.packageName = targetPackage;
}
public String getTargetClassFileName(String className) {
if (generatingDirectory == null)
return null;
StringBuffer sb = new StringBuffer();
if (generatingDirectory.length() > 0) {
sb.append(generatingDirectory);
sb.append(File.separator);
}
sb.append(className);
sb.append(".class");
return sb.toString();
}
public Class getTargetExtends() {
return targetExtends;
}
public void setTargetExtends(Class extendsClass) {
targetExtends = extendsClass;
}
public Class[] getTargetImplements() {
return targetImplements;
}
public void setTargetImplements(Class[] implementsClasses) {
targetImplements = implementsClasses;
}
String getInitialClassName() {
return initialName;
}
void setInitialClassName(String initialName) {
this.initialName = initialName;
serial = 0;
}
private String generatingDirectory;
private String packageName = "org.mozilla.javascript.gen";
private String initialName = "c";
private static int globalSerial=1;
private int serial=1;
private Class targetExtends;
private Class[] targetImplements;
}

View File

@ -0,0 +1,128 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.*;
public class OptFunctionNode extends FunctionNode {
public OptFunctionNode(String name, Node left, Node right,
ClassNameHelper nameHelper)
{
super(name, left, right);
itsVariableTable = new OptVariableTable();
OptClassNameHelper nh = (OptClassNameHelper) nameHelper;
itsClassName = nh.getJavaScriptClassName(name, false);
}
public String getDirectCallParameterSignature() {
StringBuffer parameterSig = new StringBuffer(
"(Lorg/mozilla/javascript/Context;"
+ "Lorg/mozilla/javascript/Scriptable;"
+ "Lorg/mozilla/javascript/Scriptable;");
int pCount = itsVariableTable.getParameterCount();
for (int i = 0; i < pCount; i++) {
parameterSig.append("Ljava/lang/Object;D");
}
parameterSig.append("[Ljava/lang/Object;)");
return parameterSig.toString();
}
public String getClassName() {
return itsClassName;
}
public boolean isTargetOfDirectCall() {
return itsIsTargetOfDirectCall;
}
public void addDirectCallTarget(FunctionNode target) {
if (itsDirectCallTargets == null)
itsDirectCallTargets = new Vector();
for (int i = 0; i < itsDirectCallTargets.size(); i++) // OPT !!
if (((FunctionNode)itsDirectCallTargets.elementAt(i)) == target)
return;
itsDirectCallTargets.addElement(target);
}
public Vector getDirectCallTargets() {
return itsDirectCallTargets;
}
public void setIsTargetOfDirectCall() {
itsIsTargetOfDirectCall = true;
}
public void setParameterNumberContext(boolean b) {
itsParameterNumberContext = b;
}
public boolean getParameterNumberContext() {
return itsParameterNumberContext;
}
public boolean containsCalls(int argCount) {
if ((argCount < itsContainsCallsCount.length) && (argCount >= 0))
return itsContainsCallsCount[argCount];
else
return itsContainsCalls;
}
public void setContainsCalls(int argCount) {
if (argCount < itsContainsCallsCount.length)
itsContainsCallsCount[argCount] = true;
itsContainsCalls = true;
}
public void incrementLocalCount() {
Integer localCount = (Integer)(getProp(Node.LOCALCOUNT_PROP));
if (localCount == null) {
putProp(Node.LOCALCOUNT_PROP, new Integer(1));
} else {
putProp(Node.LOCALCOUNT_PROP,
new Integer(localCount.intValue() + 1));
}
}
private String itsClassName;
private boolean itsIsTargetOfDirectCall;
private boolean itsContainsCalls;
private boolean[] itsContainsCallsCount = new boolean[4];
private boolean itsParameterNumberContext;
private Vector itsDirectCallTargets;
}

View File

@ -0,0 +1,69 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
/**
* This class allows the creation of nodes, and follows the Factory pattern.
*
* @see IRFactory
* @author Norris Boyd
*/
public class OptIRFactory extends IRFactory {
public OptIRFactory(TokenStream ts, ClassNameHelper nameHelper) {
super(ts);
this.nameHelper = nameHelper;
}
public Object createFunctionNode(String name, Object args,
Object statements)
{
if (name == null)
name = "";
OptFunctionNode result = new OptFunctionNode(name, (Node) args,
(Node) statements,
nameHelper);
Context cx = Context.getCurrentContext();
if (cx.getDebugLevel() > 0)
result.setRequiresActivation(true);
return result;
}
private ClassNameHelper nameHelper;
}

View File

@ -0,0 +1,93 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
public class OptLocalVariable extends LocalVariable {
public OptLocalVariable(String name, boolean isParameter) {
super(name, isParameter);
}
public String toString() {
return "LocalVariable : '" + getName()
+ "', index = " + getIndex()
+ ", LiveAcrossCall = " + itsLiveAcrossCall
+ ", isNumber = " + itsIsNumber
+ ", isParameter = " + isParameter()
+ ", JRegister = " + itsJRegister;
}
public void setIsNumber() { itsIsNumber = true; }
public boolean isNumber() { return itsIsNumber; }
public void markLiveAcrossCall() { itsLiveAcrossCall = true; }
public void clearLiveAcrossCall() { itsLiveAcrossCall = false; }
public boolean isLiveAcrossCall() { return itsLiveAcrossCall; }
public void assignJRegister(short aJReg) { itsJRegister = aJReg; }
public short getJRegister() { return itsJRegister; }
public boolean assignType(int aType) { return itsTypeUnion.add(aType); }
public int getTypeUnion() { return itsTypeUnion.getEvent(); }
/**
* Get the offset into the bytecode where the variable becomes live.
* Used for generating the local variable table.
*/
public int getStartPC() {
return initPC;
}
/**
* Set the offset into the bytecode where the variable becomes live.
* Used for generating the local variable table.
*/
public void setStartPC(int pc) {
initPC = pc;
}
private short itsJRegister = -1; // unassigned
private boolean itsLiveAcrossCall;
private boolean itsIsNumber;
private TypeEvent itsTypeUnion = new TypeEvent(); // the union of all assigned types
private int initPC;
}

View File

@ -0,0 +1,311 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
public final class OptRuntime extends ScriptRuntime {
/**
* No instances should be created.
*/
private OptRuntime() {
}
public static Object getElem(Object obj, double dblIndex, Scriptable scope) {
int index;
String s;
index = (int) dblIndex;
s = ((double) index) == dblIndex ? null : toString(new Double(dblIndex));
Scriptable start = obj instanceof Scriptable
? (Scriptable) obj
: toObject(scope, obj);
Scriptable m = start;
if (s != null) {
while (m != null) {
Object result = m.get(s, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
}
return Undefined.instance;
}
while (m != null) {
Object result = m.get(index, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
}
return Undefined.instance;
}
public static Object setElem(Object obj, double dblIndex, Object value,
Scriptable scope)
{
int index;
String s;
index = (int) dblIndex;
s = ((double) index) == dblIndex ?
null : toString(new Double(dblIndex));
Scriptable start = obj instanceof Scriptable
? (Scriptable) obj
: toObject(scope, obj);
Scriptable m = start;
if (s != null) {
do {
if (m.has(s, start)) {
m.put(s, start, value);
return value;
}
m = m.getPrototype();
} while (m != null);
start.put(s, start, value);
return value;
}
do {
if (m.has(index, start)) {
m.put(index, start, value);
return value;
}
m = m.getPrototype();
} while (m != null);
start.put(index, start, value);
return value;
}
public static Object add(Object val1, double val2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(null);
if (!(val1 instanceof String))
return new Double(toNumber(val1) + val2);
return toString(val1) + numberToString(val2, 10);
}
public static Object add(double val1, Object val2) {
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(null);
if (!(val2 instanceof String))
return new Double(toNumber(val2) + val1);
return numberToString(val1, 10) + toString(val2);
}
public static boolean neq(Object x, Object y) {
return !eq(x, y);
}
public static boolean shallowNeq(Object x, Object y) {
return !shallowEq(x, y);
}
public static Boolean cmp_LTB(double d1, Object val2) {
if (cmp_LT(d1, val2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LT(double d1, Object val2) {
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
if (!(val2 instanceof String)) {
if (d1 != d1)
return 0;
double d2 = toNumber(val2);
if (d2 != d2)
return 0;
return d1 < d2 ? 1 : 0;
}
return toString(new Double(d1)).compareTo(toString(val2)) < 0 ? 1 : 0;
}
public static Boolean cmp_LTB(Object val1, double d2) {
if (cmp_LT(val1, d2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LT(Object val1, double d2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
if (!(val1 instanceof String)) {
double d1 = toNumber(val1);
if (d1 != d1)
return 0;
if (d2 != d2)
return 0;
return d1 < d2 ? 1 : 0;
}
return toString(val1).compareTo(toString(new Double(d2))) < 0 ? 1 : 0;
}
public static Boolean cmp_LEB(double d1, Object val2) {
if (cmp_LE(d1, val2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LE(double d1, Object val2) {
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
if (!(val2 instanceof String)) {
if (d1 != d1)
return 0;
double d2 = toNumber(val2);
if (d2 != d2)
return 0;
return d1 <= d2 ? 1 : 0;
}
return toString(new Double(d1)).compareTo(toString(val2)) <= 0 ? 1 : 0;
}
public static Boolean cmp_LEB(Object val1, double d2) {
if (cmp_LE(val1, d2) == 1)
return Boolean.TRUE;
else
return Boolean.FALSE;
}
public static int cmp_LE(Object val1, double d2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
if (!(val1 instanceof String)) {
double d1 = toNumber(val1);
if (d1 != d1)
return 0;
if (d2 != d2)
return 0;
return d1 <= d2 ? 1 : 0;
}
return toString(val1).compareTo(toString(new Double(d2))) <= 0 ? 1 : 0;
}
public static int cmp(Object val1, Object val2) {
if (val1 instanceof Scriptable)
val1 = ((Scriptable) val1).getDefaultValue(NumberClass);
if (val2 instanceof Scriptable)
val2 = ((Scriptable) val2).getDefaultValue(NumberClass);
if (!(val1 instanceof String) || !(val2 instanceof String)) {
double d1 = toNumber(val1);
if (d1 != d1)
return -1;
double d2 = toNumber(val2);
if (d2 != d2)
return -1;
return d1 < d2 ? 1 : 0;
}
return toString(val1).compareTo(toString(val2)) < 0 ? 1 : 0;
}
public static Object callSimple(Context cx, String id, Scriptable scope,
Object[] args)
throws JavaScriptException
{
Scriptable obj = scope;
Object prop = null;
Scriptable thisArg = null;
search:
while (obj != null) {
Scriptable m = obj;
do {
prop = m.get(id, obj);
if (prop != Scriptable.NOT_FOUND) {
thisArg = obj;
break search;
}
m = m.getPrototype();
} while (m != null);
obj = obj.getParentScope();
}
if ((prop == null) || (prop == Scriptable.NOT_FOUND)) {
Object[] errorArgs = { id };
throw Context.reportRuntimeError(
getMessage("msg.is.not.defined", errorArgs));
}
while (thisArg instanceof NativeWith)
thisArg = thisArg.getPrototype();
if (thisArg instanceof NativeCall)
thisArg = ScriptableObject.getTopLevelScope(thisArg);
Function function;
try {
function = (Function) prop;
}
catch (ClassCastException e) {
Object[] errorArgs = { toString(prop) };
throw cx.reportRuntimeError(
getMessage("msg.isnt.function", errorArgs));
}
return function.call(cx, function.getParentScope(), thisArg, args);
}
public static Object thisGet(Scriptable thisObj, String id,
Scriptable scope)
{
Object result = thisObj.get(id, thisObj);
if (result != Scriptable.NOT_FOUND)
return result;
Scriptable start = thisObj;
if (start == null) {
throw Context.reportRuntimeError(
getMessage("msg.null.to.object", null));
}
Scriptable m = start;
do {
result = m.get(id, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
} while (m != null);
return Undefined.instance;
}
public static Object[] padStart(Object[] currentArgs, int count) {
Object[] result = new Object[currentArgs.length + count];
System.arraycopy(currentArgs, 0, result, count, currentArgs.length);
return result;
}
}

View File

@ -0,0 +1,190 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;
/**
* This class performs node transforms to prepare for optimization.
*
* @see NodeTransformer
* @author Norris Boyd
*/
class OptTransformer extends NodeTransformer {
private Hashtable theFnClassNameList;
OptTransformer(Hashtable theFnClassNameList) {
this.theFnClassNameList = theFnClassNameList;
}
public NodeTransformer newInstance() {
return new OptTransformer((Hashtable) theFnClassNameList.clone());
}
public IRFactory createIRFactory(TokenStream ts) {
return new IRFactory(ts);
}
public Node transform(Node tree, Node enclosing, TokenStream ts) {
// Collect all of the contained functions into a hashtable
// so that the call optimizer can access the class name & parameter
// count for any call it encounters
collectContainedFunctions(tree.getFirstChild());
return super.transform(tree, enclosing, ts);
}
protected VariableTable createVariableTable() {
return new OptVariableTable();
}
private int detectDirectCall(Node node, Node tree)
{
Context cx = Context.getCurrentContext();
int optLevel = cx.getOptimizationLevel();
Node left = node.getFirstChild();
// count the arguments
int argCount = 0;
Node arg = left.getNextSibling();
while (arg != null) {
arg = arg.getNextSibling();
argCount++;
}
if (tree.getType() == TokenStream.FUNCTION && optLevel > 0) {
if (left.getType() == TokenStream.NAME) {
markDirectCall(tree, node, argCount, left.getString());
} else {
if (left.getType() == TokenStream.GETPROP) {
Node name = left.getFirstChild().getNextSibling();
markDirectCall(tree, node, argCount, name.getString());
}
}
}
return argCount;
}
protected void visitNew(Node node, Node tree) {
detectDirectCall(node, tree);
super.visitNew(node, tree);
}
protected void visitCall(Node node, Node tree) {
int argCount = detectDirectCall(node, tree);
if (inFunction && (argCount == 0))
((OptFunctionNode)tree).setContainsCalls(argCount);
super.visitCall(node, tree);
}
/*
* Optimize a call site by converting call("a", b, c) into :
*
* FunctionObjectFor"a" <-- instance variable init'd by constructor
*
* // this is a DIRECTCALL node
* fn = GetProp(tmp = GetBase("a"), "a");
* if (fn == FunctionObjectFor"a")
* fn.call(tmp, b, c)
* else
* ScriptRuntime.Call(fn, tmp, b, c)
*/
void markDirectCall(Node containingTree, Node callNode, int argCount,
String targetName)
{
OptFunctionNode theFunction
= (OptFunctionNode)theFnClassNameList.get(targetName);
if (theFunction != null) {
VariableTable varTable = theFunction.getVariableTable();
// Refuse to directCall any function with more
// than 32 parameters - prevent code explosion
// for wacky test cases
if (varTable.getParameterCount() > 32)
return;
if (argCount == varTable.getParameterCount()) {
callNode.putProp(Node.DIRECTCALL_PROP, theFunction);
((OptFunctionNode)containingTree)
.addDirectCallTarget(theFunction);
theFunction.setIsTargetOfDirectCall();
}
}
}
/**
* Collect all of the contained functions into a hashtable
* so that the call optimizer can access the class name & parameter
* count for any call it encounters
*/
void collectContainedFunctions(Node node) {
for (Node tNode=node; tNode != null; tNode = tNode.getNextSibling()) {
if (tNode.getType() == TokenStream.FUNCTION) {
FunctionNode fnNode = (FunctionNode)
tNode.getProp(Node.FUNCTION_PROP);
if (fnNode.getFunctionName().length() != 0) {
String name = fnNode.getFunctionName();
Object oldFn = theFnClassNameList.get(name);
if (oldFn == fnNode) {
// already processed this list of functions
return;
}
/*
if (oldFn != null) {
Object prop = fnNode.getProp(Node.BASE_LINENO_PROP);
Object[] errArgs = { name };
Context.reportWarning(
Context.getMessage("msg.fn.redecl", errArgs),
(String) fnNode.getProp(Node.SOURCENAME_PROP),
prop == null ? 0 : ((Integer) prop).intValue(),
null, 0);
}
*/
theFnClassNameList.put(name, fnNode);
}
addParameters(fnNode);
}
}
}
}

View File

@ -0,0 +1,74 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.io.*;
import java.util.*;
public class OptVariableTable extends VariableTable {
public void print(PrintWriter pw)
{
System.out.println("Variable Table, size = " + itsVariables.size());
for (int i = 0; i < itsVariables.size(); i++) {
LocalVariable lVar = (LocalVariable)(itsVariables.elementAt(i));
pw.println(lVar.toString());
}
}
public void assignParameterJRegs()
{
// 0 is reserved for function Object 'this'
// 1 is reserved for context
// 2 is reserved for parentScope
// 3 is reserved for script 'this'
short jReg = 4;
for (int i = 0; i < varStart; i++) {
OptLocalVariable lVar = (OptLocalVariable)
itsVariables.elementAt(i);
lVar.assignJRegister(jReg);
jReg += 3; // 3 is 1 for Object parm and 2 for double parm
}
}
public LocalVariable createLocalVariable(String name, boolean isParameter)
{
return new OptLocalVariable(name, isParameter);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,94 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
import org.mozilla.javascript.*;
import java.util.Stack;
public class StmtNodeIterator {
public StmtNodeIterator(Node start)
{
itsStart = start;
}
private Node findFirstInterestingNode(Node theNode)
{
if (theNode == null) return null;
if ((theNode.getType() == TokenStream.BLOCK)
|| (theNode.getType() == TokenStream.LOOP)
|| (theNode.getType() == TokenStream.FUNCTION)) {
if (theNode.getFirst() == null) {
return findFirstInterestingNode(theNode.getNext());
}
else {
itsStack.push(theNode);
return findFirstInterestingNode(theNode.getFirst());
}
}
else
return theNode;
}
public Node nextNode()
{
if (itsCurrentNode == null)
return itsCurrentNode = findFirstInterestingNode(itsStart);
itsCurrentNode = itsCurrentNode.getNext();
if (itsCurrentNode == null) {
while ( ! itsStack.isEmpty()) {
Node n = (Node)(itsStack.pop());
if (n.getNext() != null) {
return itsCurrentNode = findFirstInterestingNode(n.getNext());
}
}
return null;
}
else
return itsCurrentNode = findFirstInterestingNode(itsCurrentNode);
}
private Stack itsStack = new Stack();
private Node itsStart;
private Node itsCurrentNode;
}

View File

@ -0,0 +1,67 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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
* 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.optimizer;
public class TypeEvent {
public static final int EventBitLength = 2;
public static final int
AnyType = (1 << EventBitLength) - 1,
NumberType = 0x1,
NoType = 0x0;
public TypeEvent(int theEvent)
{
itsEvent = theEvent;
}
public TypeEvent()
{
itsEvent = NoType;
}
public boolean add(int anOther)
{
return ((itsEvent |= anOther) != anOther);
}
public int getEvent() { return itsEvent; }
private int itsEvent;
}

View File

@ -0,0 +1,293 @@
/*
* 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 Mozilla Communicator client code, released
* March 31, 1998.
*
* 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):
* Christine Begle
* 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.tools.jsc;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import java.text.MessageFormat;
import org.mozilla.javascript.*;
import org.mozilla.javascript.tools.ToolErrorReporter;
/**
* @author Norris Boyd
*/
public class Main {
/**
* 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
* compile scripts.
*/
public static void main(String args[]) {
Context cx = Context.enter();
reporter = new ToolErrorReporter(true);
cx.setErrorReporter(reporter);
args = processOptions(cx, args);
if ( ! reporter.hasReportedError())
processSource(cx, args);
cx.exit();
}
/**
* Parse arguments.
*
*/
public static String[] processOptions(Context cx, String args[]) {
cx.setTargetPackage(""); // default to no package
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;
}
try {
if (arg.equals("-version") && ++i < args.length) {
int version = Integer.parseInt(args[i]);
cx.setLanguageVersion(version);
continue;
}
if ((arg.equals("-opt") || arg.equals("-O")) &&
++i < args.length)
{
int optLevel = Integer.parseInt(args[i]);
cx.setOptimizationLevel(optLevel);
continue;
}
if (arg.equals("-debuglevel") && ++i < args.length) {
int debugLevel = Integer.parseInt(args[i]);
cx.setDebugLevel(debugLevel);
continue;
}
}
catch (NumberFormatException e) {
cx.reportError( ToolErrorReporter.getMessage("msg.jsc.usage",
args[i] ));
continue;
}
if (arg.equals("-nosource")) {
cx.setGeneratingSource(false);
continue;
}
if (arg.equals("-debug") || arg.equals("-g")) {
cx.setGeneratingDebug(true);
continue;
}
if (arg.equals("-o") && ++i < args.length) {
String outFile = args[i];
if (!Character.isJavaIdentifierStart(outFile.charAt(0))) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.invalid.classfile.name",
outFile));
continue;
}
for ( int j = 1; j < outFile.length(); j++ ) {
if ( (!Character.isJavaIdentifierPart(outFile.charAt(j)) &&
outFile.charAt(j) != '.') || (outFile.charAt(j) == '.' &&
(!outFile.endsWith(".class") || j != outFile.length()-6 )) )
{
cx.reportError(ToolErrorReporter.getMessage(
"msg.invalid.classfile.name",
outFile ));
break;
}
}
cx.setTargetClassFileName(outFile);
hasOutOption = true;
continue;
}
if (arg.equals("-package") && ++i < args.length) {
String targetPackage = args[i];
for ( int j = 0; j < targetPackage.length(); j++ ) {
if ( !Character.isJavaIdentifierStart(targetPackage.charAt(j))) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.package.name",
targetPackage));
continue;
}
for ( int k = ++j; k< targetPackage.length(); k++, j++ ) {
if (targetPackage.charAt(k) == '.' &&
targetPackage.charAt(k-1) != '.' &&
k != targetPackage.length()-1)
{
continue;
}
if (!Character.isJavaIdentifierPart(
targetPackage.charAt(k)))
{
cx.reportError(ToolErrorReporter.getMessage(
"msg.package.name",
targetPackage));
continue;
}
continue;
}
}
cx.setTargetPackage(targetPackage);
continue;
}
if (arg.equals("-extends") && ++i < args.length) {
String targetExtends = args[i];
try {
cx.setTargetExtends(Class.forName(targetExtends));
} catch (ClassNotFoundException e) {
throw new Error(e.toString()); // TODO: better error
}
continue;
}
if (arg.equals("-implements") && ++i < args.length) {
// TODO: allow for multiple comma-separated interfaces.
String targetImplements = args[i];
try {
Class[] implementsClasses = { Class.forName(targetImplements) };
cx.setTargetImplements(implementsClasses);
} catch (ClassNotFoundException e) {
throw new Error(e.toString()); // TODO: better error
}
continue;
}
usage(arg);
}
// no file name
p(ToolErrorReporter.getMessage("msg.no.file"));
System.exit(1);
return null;
}
/**
* Print a usage message.
*/
public static void usage(String s) {
p(ToolErrorReporter.getMessage("msg.jsc.usage", s));
System.exit(1);
}
/**
* Compile JavaScript source.
*
*/
public static void processSource(Context cx, String[] filenames) {
if (hasOutOption && filenames.length > 1) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.multiple.js.to.file",
cx.getTargetClassFileName()));
}
for (int i=0; i < filenames.length; i++) {
String filename = filenames[i];
File f = new File(filename);
if (!f.exists()) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.jsfile.not.found",
filename));
return;
}
if (!filename.endsWith(".js")) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.extension.not.js",
filename));
return;
}
if (!hasOutOption) {
String name = f.getName();
String nojs = name.substring(0, name.length() - 3);
String className = getClassName(nojs) + ".class";
String out = f.getParent() == null ? className : f.getParent() +
File.separator + className;
cx.setTargetClassFileName(out);
}
if (cx.getTargetClassFileName() == null) {
cx.reportError(ToolErrorReporter.getMessage("msg.no-opt"));
}
try {
Reader in = new FileReader(filename);
cx.compileReader(null, in, filename, 1, null);
}
catch (FileNotFoundException ex) {
cx.reportError(ToolErrorReporter.getMessage(
"msg.couldnt.open",
filename));
return;
}
catch (IOException ioe) {
cx.reportError(ioe.toString());
}
}
}
/**
* Verify that class file names are legal Java identifiers. Substitute
* illegal characters with underscores, and prepend the name with an
* underscore if the file name does not begin with a JavaLetter.
*/
static String getClassName(String name) {
char[] s = new char[name.length()+1];
char c;
int j = 0;
if (!Character.isJavaIdentifierStart(name.charAt(0))) {
s[j++] = '_';
}
for (int i=0; i < name.length(); i++, j++) {
c = name.charAt(i);
if ( Character.isJavaIdentifierPart(c) ) {
s[j] = c;
} else {
s[j] = '_';
}
}
return (new String(s)).trim();
}
private static void p(String s) {
System.out.println(s);
}
private static boolean hasOutOption = false;
private static ToolErrorReporter reporter;
}

View File

@ -108,7 +108,7 @@ public class Main extends ScriptableObject {
try {
Class clazz = Class.forName(
"com.netscape.jsdebugging.ifcui.launcher.rhino.LaunchNetscapeJavaScriptDebugger");
"org.mozilla.jsdebugging.ifcui.launcher.rhino.LaunchNetscapeJavaScriptDebugger");
ILaunchableDebugger debugger =
(ILaunchableDebugger) clazz.newInstance();
debugger.launch(global.debug_dm, global.debug_stm, false);