mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-20 01:51:39 +00:00
Changes for classfile generation.
This commit is contained in:
parent
b7649a1e51
commit
40f1ee60cc
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
688
js/rhino/org/mozilla/javascript/optimizer/Block.java
Normal file
688
js/rhino/org/mozilla/javascript/optimizer/Block.java
Normal 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;
|
||||
|
||||
}
|
4172
js/rhino/org/mozilla/javascript/optimizer/Codegen.java
Normal file
4172
js/rhino/org/mozilla/javascript/optimizer/Codegen.java
Normal file
File diff suppressed because it is too large
Load Diff
130
js/rhino/org/mozilla/javascript/optimizer/DataFlowBitSet.java
Normal file
130
js/rhino/org/mozilla/javascript/optimizer/DataFlowBitSet.java
Normal 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;
|
||||
}
|
||||
}
|
92
js/rhino/org/mozilla/javascript/optimizer/FatBlock.java
Normal file
92
js/rhino/org/mozilla/javascript/optimizer/FatBlock.java
Normal 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;
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
128
js/rhino/org/mozilla/javascript/optimizer/OptFunctionNode.java
Normal file
128
js/rhino/org/mozilla/javascript/optimizer/OptFunctionNode.java
Normal 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;
|
||||
}
|
69
js/rhino/org/mozilla/javascript/optimizer/OptIRFactory.java
Normal file
69
js/rhino/org/mozilla/javascript/optimizer/OptIRFactory.java
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
311
js/rhino/org/mozilla/javascript/optimizer/OptRuntime.java
Normal file
311
js/rhino/org/mozilla/javascript/optimizer/OptRuntime.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
190
js/rhino/org/mozilla/javascript/optimizer/OptTransformer.java
Normal file
190
js/rhino/org/mozilla/javascript/optimizer/OptTransformer.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
1080
js/rhino/org/mozilla/javascript/optimizer/Optimizer.java
Normal file
1080
js/rhino/org/mozilla/javascript/optimizer/Optimizer.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
}
|
67
js/rhino/org/mozilla/javascript/optimizer/TypeEvent.java
Normal file
67
js/rhino/org/mozilla/javascript/optimizer/TypeEvent.java
Normal 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;
|
||||
}
|
||||
|
293
js/rhino/org/mozilla/javascript/tools/jsc/Main.java
Normal file
293
js/rhino/org/mozilla/javascript/tools/jsc/Main.java
Normal 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
688
js/rhino/src/org/mozilla/javascript/optimizer/Block.java
Normal file
688
js/rhino/src/org/mozilla/javascript/optimizer/Block.java
Normal 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;
|
||||
|
||||
}
|
4172
js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
Normal file
4172
js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
}
|
92
js/rhino/src/org/mozilla/javascript/optimizer/FatBlock.java
Normal file
92
js/rhino/src/org/mozilla/javascript/optimizer/FatBlock.java
Normal 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;
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
311
js/rhino/src/org/mozilla/javascript/optimizer/OptRuntime.java
Normal file
311
js/rhino/src/org/mozilla/javascript/optimizer/OptRuntime.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
1080
js/rhino/src/org/mozilla/javascript/optimizer/Optimizer.java
Normal file
1080
js/rhino/src/org/mozilla/javascript/optimizer/Optimizer.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
}
|
67
js/rhino/src/org/mozilla/javascript/optimizer/TypeEvent.java
Normal file
67
js/rhino/src/org/mozilla/javascript/optimizer/TypeEvent.java
Normal 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;
|
||||
}
|
||||
|
293
js/rhino/toolsrc/org/mozilla/javascript/tools/jsc/Main.java
Normal file
293
js/rhino/toolsrc/org/mozilla/javascript/tools/jsc/Main.java
Normal 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user