56318  function literals with names don't work right
57045  negative integers as object properties: weird behavior
58479  functions defined within conditional phrases are always crea
This commit is contained in:
nboyd%atg.com 2000-10-30 19:34:11 +00:00
Родитель a1da49183a
Коммит fa72e89acf
22 изменённых файлов: 288 добавлений и 3555 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -174,8 +174,8 @@ public class Interpreter extends LabelTable {
boolean needsActivation = theFunction.requiresActivation() || boolean needsActivation = theFunction.requiresActivation() ||
cx.isGeneratingDebug(); cx.isGeneratingDebug();
generateICodeFromTree(theFunction.getLastChild(), generateICodeFromTree(theFunction.getLastChild(),
varTable, needsActivation, varTable, needsActivation,
securityDomain); securityDomain);
itsData.itsName = theFunction.getFunctionName(); itsData.itsName = theFunction.getFunctionName();
itsData.itsSourceFile = (String) theFunction.getProp( itsData.itsSourceFile = (String) theFunction.getProp(
@ -1204,6 +1204,7 @@ public class Interpreter extends LabelTable {
case TokenStream.ONE : case TokenStream.ONE :
case TokenStream.NULL : case TokenStream.NULL :
case TokenStream.THIS : case TokenStream.THIS :
case TokenStream.THISFN :
case TokenStream.FALSE : case TokenStream.FALSE :
case TokenStream.TRUE : case TokenStream.TRUE :
case TokenStream.UNDEFINED : case TokenStream.UNDEFINED :
@ -1802,6 +1803,9 @@ public class Interpreter extends LabelTable {
case TokenStream.THIS : case TokenStream.THIS :
stack[++stackTop] = thisObj; stack[++stackTop] = thisObj;
break; break;
case TokenStream.THISFN :
stack[++stackTop] = fnOrScript;
break;
case TokenStream.FALSE : case TokenStream.FALSE :
stack[++stackTop] = Boolean.FALSE; stack[++stackTop] = Boolean.FALSE;
break; break;

Просмотреть файл

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

Просмотреть файл

@ -449,7 +449,7 @@ public class NodeTransformer {
((FunctionNode) tree).setRequiresActivation(true); ((FunctionNode) tree).setRequiresActivation(true);
} }
VariableTable vars = getVariableTable(tree); VariableTable vars = getVariableTable(tree);
if (vars.get(name) != null) { if (vars.getVariable(name) != null) {
if (type == TokenStream.SETNAME) { if (type == TokenStream.SETNAME) {
node.setType(TokenStream.SETVAR); node.setType(TokenStream.SETVAR);
bind.setType(TokenStream.STRING); bind.setType(TokenStream.STRING);
@ -489,7 +489,7 @@ public class NodeTransformer {
((FunctionNode) tree).setRequiresActivation(true); ((FunctionNode) tree).setRequiresActivation(true);
} }
VariableTable vars = getVariableTable(tree); VariableTable vars = getVariableTable(tree);
if (vars.get(name) != null) { if (vars.getVariable(name) != null) {
node.setType(TokenStream.GETVAR); node.setType(TokenStream.GETVAR);
} }
break; break;
@ -510,7 +510,9 @@ public class NodeTransformer {
while ((node = iterator.nextNode()) != null) { while ((node = iterator.nextNode()) != null) {
int nodeType = node.getType(); int nodeType = node.getType();
if (inFunction && nodeType == TokenStream.FUNCTION && if (inFunction && nodeType == TokenStream.FUNCTION &&
node != tree) node != tree &&
((FunctionNode) node.getProp(Node.FUNCTION_PROP)).getFunctionType() ==
FunctionNode.FUNCTION_EXPRESSION_STATEMENT)
{ {
// In a function with both "var x" and "function x", // In a function with both "var x" and "function x",
// disregard the var statement, independent of order. // disregard the var statement, independent of order.
@ -531,6 +533,26 @@ public class NodeTransformer {
vars.addLocal(n.getString()); vars.addLocal(n.getString());
} }
} }
String name = (String) tree.getDatum();
if (inFunction && ((FunctionNode) tree).getFunctionType() ==
FunctionNode.FUNCTION_EXPRESSION &&
name != null && name.length() > 0 &&
vars.getVariable(name) == null)
{
// A function expression needs to have its name as a variable
// (if it isn't already allocated as a variable). See
// ECMA Ch. 13. We add code to the beginning of the function
// to initialize a local variable of the function's name
// to the function value.
vars.addLocal(name);
Node block = tree.getLastChild();
Node setFn = new Node(TokenStream.POP,
new Node(TokenStream.SETVAR,
new Node(TokenStream.STRING, name),
new Node(TokenStream.PRIMARY,
new Integer(TokenStream.THISFN))));
block.addChildrenToFront(setFn);
}
} }
protected void addParameters(FunctionNode fnNode) { protected void addParameters(FunctionNode fnNode) {
@ -580,7 +602,9 @@ public class NodeTransformer {
if (left.getType() == TokenStream.NAME) { if (left.getType() == TokenStream.NAME) {
VariableTable vars = getVariableTable(tree); VariableTable vars = getVariableTable(tree);
String name = left.getString(); String name = left.getString();
if (inFunction && vars.get(name) != null && !inWithStatement()) { if (inFunction && vars.getVariable(name) != null &&
!inWithStatement())
{
// call to a var. Transform to Call(GetVar("a"), b, c) // call to a var. Transform to Call(GetVar("a"), b, c)
left.setType(TokenStream.GETVAR); left.setType(TokenStream.GETVAR);
// fall through to code to add GetParent // fall through to code to add GetParent

Просмотреть файл

@ -854,12 +854,18 @@ public class ScriptRuntime {
/* It must be a string. */ /* It must be a string. */
int len = str.length(); int len = str.length();
char c; char c;
if (len > 0 && '0' <= (c = str.charAt(0)) && c <= '9' && boolean negate = false;
int i = 0;
if (len > 0 && (c = str.charAt(0)) == '-') {
negate = true;
i = 1;
}
if (len > 0 && '0' <= (c = str.charAt(i)) && c <= '9' &&
len <= MAX_VALUE_LENGTH) len <= MAX_VALUE_LENGTH)
{ {
int index = c - '0'; int index = c - '0';
int oldIndex = 0; int oldIndex = 0;
int i = 1; i++;
if (index != 0) { if (index != 0) {
while (i < len && '0' <= (c = str.charAt(i)) && c <= '9') { while (i < len && '0' <= (c = str.charAt(i)) && c <= '9') {
oldIndex = index; oldIndex = index;
@ -875,7 +881,7 @@ public class ScriptRuntime {
(oldIndex == (Integer.MAX_VALUE / 10) && (oldIndex == (Integer.MAX_VALUE / 10) &&
c < (Integer.MAX_VALUE % 10)))) c < (Integer.MAX_VALUE % 10))))
{ {
return index; return negate ? -index : index;
} }
} }
return NO_INDEX; return NO_INDEX;
@ -1159,9 +1165,14 @@ public class ScriptRuntime {
} while (next != null); } while (next != null);
bound.put(id, bound, value); bound.put(id, bound, value);
/*
This code is causing immense performance problems in
scripts that assign to the variables as a way of creating them.
XXX need strict mode
String[] args = { id }; String[] args = { id };
String message = getMessage("msg.assn.create", args); String message = getMessage("msg.assn.create", args);
Context.reportWarning(message); Context.reportWarning(message);
*/
return value; return value;
} }
return setProp(bound, id, value, scope); return setProp(bound, id, value, scope);
@ -1947,11 +1958,12 @@ public class ScriptRuntime {
public static NativeFunction initFunction(NativeFunction fn, public static NativeFunction initFunction(NativeFunction fn,
Scriptable scope, Scriptable scope,
String fnName, String fnName,
Context cx) Context cx,
boolean doSetName)
{ {
fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function")); fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function"));
fn.setParentScope(scope); fn.setParentScope(scope);
if (fnName != null && fnName.length() != 0) if (doSetName)
setName(scope, fn, scope, fnName); setName(scope, fn, scope, fnName);
return fn; return fn;
} }

Просмотреть файл

@ -168,47 +168,48 @@ public class TokenStream {
SETPARENT = 84, SETPARENT = 84,
SCOPE = 85, SCOPE = 85,
GETSCOPEPARENT = 86, GETSCOPEPARENT = 86,
JTHROW = 87, THISFN = 87,
JTHROW = 88,
// End of interpreter bytecodes // End of interpreter bytecodes
SEMI = 88, // semicolon SEMI = 89, // semicolon
LB = 89, // left and right brackets LB = 90, // left and right brackets
RB = 90, RB = 91,
LC = 91, // left and right curlies (braces) LC = 92, // left and right curlies (braces)
RC = 92, RC = 93,
LP = 93, // left and right parentheses LP = 94, // left and right parentheses
RP = 94, RP = 95,
COMMA = 95, // comma operator COMMA = 96, // comma operator
ASSIGN = 96, // assignment ops (= += -= etc.) ASSIGN = 97, // assignment ops (= += -= etc.)
HOOK = 97, // conditional (?:) HOOK = 98, // conditional (?:)
COLON = 98, COLON = 99,
OR = 99, // logical or (||) OR = 100, // logical or (||)
AND = 100, // logical and (&&) AND = 101, // logical and (&&)
EQOP = 101, // equality ops (== !=) EQOP = 102, // equality ops (== !=)
RELOP = 102, // relational ops (< <= > >=) RELOP = 103, // relational ops (< <= > >=)
SHOP = 103, // shift ops (<< >> >>>) SHOP = 104, // shift ops (<< >> >>>)
UNARYOP = 104, // unary prefix operator UNARYOP = 105, // unary prefix operator
INC = 105, // increment/decrement (++ --) INC = 106, // increment/decrement (++ --)
DEC = 106, DEC = 107,
DOT = 107, // member operator (.) DOT = 108, // member operator (.)
PRIMARY = 108, // true, false, null, this PRIMARY = 109, // true, false, null, this
FUNCTION = 109, // function keyword FUNCTION = 110, // function keyword
EXPORT = 110, // export keyword EXPORT = 111, // export keyword
IMPORT = 111, // import keyword IMPORT = 112, // import keyword
IF = 112, // if keyword IF = 113, // if keyword
ELSE = 113, // else keyword ELSE = 114, // else keyword
SWITCH = 114, // switch keyword SWITCH = 115, // switch keyword
CASE = 115, // case keyword CASE = 116, // case keyword
DEFAULT = 116, // default keyword DEFAULT = 117, // default keyword
WHILE = 117, // while keyword WHILE = 118, // while keyword
DO = 118, // do keyword DO = 119, // do keyword
FOR = 119, // for keyword FOR = 120, // for keyword
BREAK = 120, // break keyword BREAK = 121, // break keyword
CONTINUE = 121, // continue keyword CONTINUE = 122, // continue keyword
VAR = 122, // var keyword VAR = 123, // var keyword
WITH = 123, // with keyword WITH = 124, // with keyword
CATCH = 124, // catch keyword CATCH = 125, // catch keyword
FINALLY = 125, // finally keyword FINALLY = 126, // finally keyword
RESERVED = 126, // reserved keywords RESERVED = 127, // reserved keywords
/** Added by Mike - these are JSOPs in the jsref, but I /** Added by Mike - these are JSOPs in the jsref, but I
* don't have them yet in the java implementation... * don't have them yet in the java implementation...
@ -217,45 +218,45 @@ public class TokenStream {
* Most of these go in the 'op' field when returning * Most of these go in the 'op' field when returning
* more general token types, eg. 'DIV' as the op of 'ASSIGN'. * more general token types, eg. 'DIV' as the op of 'ASSIGN'.
*/ */
NOP = 127, // NOP NOP = 128, // NOP
NOT = 128, // etc. NOT = 129, // etc.
PRE = 129, // for INC, DEC nodes. PRE = 130, // for INC, DEC nodes.
POST = 130, POST = 131,
/** /**
* For JSOPs associated with keywords... * For JSOPs associated with keywords...
* eg. op = THIS; token = PRIMARY * eg. op = THIS; token = PRIMARY
*/ */
VOID = 131, VOID = 132,
/* types used for the parse tree - these never get returned /* types used for the parse tree - these never get returned
* by the scanner. * by the scanner.
*/ */
BLOCK = 132, // statement block BLOCK = 133, // statement block
ARRAYLIT = 133, // array literal ARRAYLIT = 134, // array literal
OBJLIT = 134, // object literal OBJLIT = 135, // object literal
LABEL = 135, // label LABEL = 136, // label
TARGET = 136, TARGET = 137,
LOOP = 137, LOOP = 138,
ENUMDONE = 138, ENUMDONE = 139,
EXPRSTMT = 139, EXPRSTMT = 140,
PARENT = 140, PARENT = 141,
CONVERT = 141, CONVERT = 142,
JSR = 142, JSR = 143,
NEWLOCAL = 143, NEWLOCAL = 144,
USELOCAL = 144, USELOCAL = 145,
SCRIPT = 145, // top-level node for entire script SCRIPT = 146, // top-level node for entire script
/** /**
* For the interpreted mode indicating a line number change in icodes. * For the interpreted mode indicating a line number change in icodes.
*/ */
LINE = 146, LINE = 147,
SOURCEFILE = 147, SOURCEFILE = 148,
// For debugger // For debugger
BREAKPOINT = 148; BREAKPOINT = 149;
// end enum // end enum
@ -354,6 +355,7 @@ public class TokenStream {
"setparent", "setparent",
"scope", "scope",
"getscopeparent", "getscopeparent",
"thisfn",
"jthrow", "jthrow",
"semi", "semi",
"lb", "lb",

Просмотреть файл

@ -49,4 +49,6 @@ public interface DebuggableEngine {
public Debugger getDebugger(); public Debugger getDebugger();
public Frame getFrame(int frameNumber); public Frame getFrame(int frameNumber);
//public void haltExecution();
} }

Просмотреть файл

@ -46,6 +46,8 @@ import java.util.Enumeration;
* code (either functions or top-level scripts). * code (either functions or top-level scripts).
*/ */
public interface DebuggableScript { public interface DebuggableScript {
//public boolean isFunction(); // XXX
/** /**
* Get the Scriptable object (Function or Script) that is * Get the Scriptable object (Function or Script) that is

Просмотреть файл

@ -1,696 +0,0 @@
/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript.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 markAnyTypeVariables(VariableTable theVariables)
{
for (int i = 0; i < theVariables.size(); i++)
if (itsLiveOnEntrySet.test(i))
((OptLocalVariable)theVariables.get(i)).assignType(TypeEvent.AnyType);
}
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, 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;
}

Просмотреть файл

@ -457,7 +457,7 @@ public class Codegen extends Interpreter {
// make sure that all parameters are objects // make sure that all parameters are objects
itsForcedObjectParameters = true; itsForcedObjectParameters = true;
for (int i = 0; i < vars.getParameterCount(); i++) { for (int i = 0; i < vars.getParameterCount(); i++) {
OptLocalVariable lVar = (OptLocalVariable) vars.get(i); OptLocalVariable lVar = (OptLocalVariable) vars.getVariable(i);
aload(lVar.getJRegister()); aload(lVar.getJRegister());
classFile.add(ByteCode.GETSTATIC, classFile.add(ByteCode.GETSTATIC,
"java/lang/Void", "java/lang/Void",
@ -1347,12 +1347,18 @@ public class Codegen extends Interpreter {
addByteCode(ByteCode.ACONST_NULL); addByteCode(ByteCode.ACONST_NULL);
} }
// load 'cx' // load 'cx'
aload(contextLocal); aload(contextLocal);
// load boolean indicating whether fn name should be set in scope
boolean setFnName = str != null && str.length() > 0 &&
((FunctionNode) def).getFunctionType() !=
FunctionNode.FUNCTION_EXPRESSION;
addByteCode(setFnName ? ByteCode.ICONST_1 : ByteCode.ICONST_0);
addScriptRuntimeInvoke("initFunction", addScriptRuntimeInvoke("initFunction",
"(Lorg/mozilla/javascript/NativeFunction;" + "(Lorg/mozilla/javascript/NativeFunction;" +
"Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/String;" + "Ljava/lang/String;" +
"Lorg/mozilla/javascript/Context;)", "Lorg/mozilla/javascript/Context;Z)",
"Lorg/mozilla/javascript/NativeFunction;"); "Lorg/mozilla/javascript/NativeFunction;");
def.putProp(Node.FUNCTION_PROP, new Short(i)); def.putProp(Node.FUNCTION_PROP, new Short(i));
addByteCode(ByteCode.AASTORE); // store NativeFunction addByteCode(ByteCode.AASTORE); // store NativeFunction
@ -1447,7 +1453,7 @@ public class Codegen extends Interpreter {
// before the next call and are used in the function // before the next call and are used in the function
short firstUndefVar = -1; short firstUndefVar = -1;
for (int i = 0; i < vars.size(); i++) { for (int i = 0; i < vars.size(); i++) {
OptLocalVariable lVar = (OptLocalVariable) vars.get(i); OptLocalVariable lVar = (OptLocalVariable) vars.getVariable(i);
if (lVar.isNumber()) { if (lVar.isNumber()) {
lVar.assignJRegister(getNewWordPairLocal()); lVar.assignJRegister(getNewWordPairLocal());
push(0.0); push(0.0);
@ -1547,7 +1553,7 @@ public class Codegen extends Interpreter {
if (cx.isGeneratingDebug()) { if (cx.isGeneratingDebug()) {
debugVars = new OptVariableTable(); debugVars = new OptVariableTable();
debugVars.addLocal(debugVariableName); debugVars.addLocal(debugVariableName);
OptLocalVariable lv = (OptLocalVariable) debugVars.get(debugVariableName); OptLocalVariable lv = (OptLocalVariable) debugVars.getVariable(debugVariableName);
lv.assignJRegister(variableObjectLocal); lv.assignJRegister(variableObjectLocal);
lv.setStartPC(classFile.getCurrentCodeOffset()); lv.setStartPC(classFile.getCurrentCodeOffset());
} }
@ -1876,7 +1882,6 @@ public class Codegen extends Interpreter {
*/ */
{ {
if (true) {
Node callBase = callNode.getFirstChild(); Node callBase = callNode.getFirstChild();
if (callBase.getType() == TokenStream.GETPROP) { if (callBase.getType() == TokenStream.GETPROP) {
Node callBaseChild = callBase.getFirstChild(); Node callBaseChild = callBase.getFirstChild();
@ -1903,7 +1908,6 @@ if (true) {
} }
} }
} }
}
return null; return null;
} }
@ -2425,7 +2429,7 @@ if (true) {
} }
String name = node.getString(); String name = node.getString();
if (hasVarsInRegs) { if (hasVarsInRegs) {
OptLocalVariable lVar = (OptLocalVariable) vars.get(name); OptLocalVariable lVar = (OptLocalVariable) vars.getVariable(name);
if (lVar != null) { if (lVar != null) {
if (lVar.isNumber()) { if (lVar.isNumber()) {
push("number"); push("number");
@ -2463,7 +2467,7 @@ if (true) {
String routine = (isInc) ? "postIncrement" : "postDecrement"; String routine = (isInc) ? "postIncrement" : "postDecrement";
if (hasVarsInRegs && child.getType() == TokenStream.GETVAR) { if (hasVarsInRegs && child.getType() == TokenStream.GETVAR) {
if (lVar == null) if (lVar == null)
lVar = (OptLocalVariable) vars.get(child.getString()); lVar = (OptLocalVariable) vars.getVariable(child.getString());
if (lVar.getJRegister() == -1) if (lVar.getJRegister() == -1)
lVar.assignJRegister(getNewWordLocal()); lVar.assignJRegister(getNewWordLocal());
aload(lVar.getJRegister()); aload(lVar.getJRegister());
@ -3173,6 +3177,10 @@ if (true) {
aload(thisObjLocal); aload(thisObjLocal);
break; break;
case TokenStream.THISFN:
classFile.add(ByteCode.ALOAD_0);
break;
case TokenStream.NULL: case TokenStream.NULL:
addByteCode(ByteCode.ACONST_NULL); addByteCode(ByteCode.ACONST_NULL);
break; break;
@ -3232,7 +3240,7 @@ if (true) {
{ {
// TODO: Clean up use of lVar here and in set. // TODO: Clean up use of lVar here and in set.
if (hasVarsInRegs && lVar == null) if (hasVarsInRegs && lVar == null)
lVar = (OptLocalVariable) vars.get(name); lVar = (OptLocalVariable) vars.getVariable(name);
if (lVar != null) { if (lVar != null) {
if (lVar.getJRegister() == -1) if (lVar.getJRegister() == -1)
if (lVar.isNumber()) if (lVar.isNumber())
@ -3303,7 +3311,7 @@ if (true) {
OptLocalVariable lVar = (OptLocalVariable)(node.getProp(Node.VARIABLE_PROP)); OptLocalVariable lVar = (OptLocalVariable)(node.getProp(Node.VARIABLE_PROP));
// XXX is this right? If so, clean up. // XXX is this right? If so, clean up.
if (hasVarsInRegs && lVar == null) if (hasVarsInRegs && lVar == null)
lVar = (OptLocalVariable) vars.get(child.getString()); lVar = (OptLocalVariable) vars.getVariable(child.getString());
if (lVar != null) { if (lVar != null) {
generateCodeFromNode(child.getNextSibling(), node, -1, -1); generateCodeFromNode(child.getNextSibling(), node, -1, -1);
if (lVar.getJRegister() == -1) { if (lVar.getJRegister() == -1) {

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -362,7 +362,8 @@ public class ClassFileWriter extends LabelTable {
codeAttribute[index++] = (byte)(varCount >> 8); codeAttribute[index++] = (byte)(varCount >> 8);
codeAttribute[index++] = (byte)varCount; codeAttribute[index++] = (byte)varCount;
for (int i = 0; i < varCount; i++) { for (int i = 0; i < varCount; i++) {
LocalVariable lvar = vars.get(i); LocalVariable lvar = vars.getVariable(i);
// start pc // start pc
int startPc = lvar.getStartPC(); int startPc = lvar.getStartPC();
codeAttribute[index++] = (byte)(startPc >> 8); codeAttribute[index++] = (byte)(startPc >> 8);

Просмотреть файл

@ -174,8 +174,8 @@ public class Interpreter extends LabelTable {
boolean needsActivation = theFunction.requiresActivation() || boolean needsActivation = theFunction.requiresActivation() ||
cx.isGeneratingDebug(); cx.isGeneratingDebug();
generateICodeFromTree(theFunction.getLastChild(), generateICodeFromTree(theFunction.getLastChild(),
varTable, needsActivation, varTable, needsActivation,
securityDomain); securityDomain);
itsData.itsName = theFunction.getFunctionName(); itsData.itsName = theFunction.getFunctionName();
itsData.itsSourceFile = (String) theFunction.getProp( itsData.itsSourceFile = (String) theFunction.getProp(
@ -1204,6 +1204,7 @@ public class Interpreter extends LabelTable {
case TokenStream.ONE : case TokenStream.ONE :
case TokenStream.NULL : case TokenStream.NULL :
case TokenStream.THIS : case TokenStream.THIS :
case TokenStream.THISFN :
case TokenStream.FALSE : case TokenStream.FALSE :
case TokenStream.TRUE : case TokenStream.TRUE :
case TokenStream.UNDEFINED : case TokenStream.UNDEFINED :
@ -1802,6 +1803,9 @@ public class Interpreter extends LabelTable {
case TokenStream.THIS : case TokenStream.THIS :
stack[++stackTop] = thisObj; stack[++stackTop] = thisObj;
break; break;
case TokenStream.THISFN :
stack[++stackTop] = fnOrScript;
break;
case TokenStream.FALSE : case TokenStream.FALSE :
stack[++stackTop] = Boolean.FALSE; stack[++stackTop] = Boolean.FALSE;
break; break;

Просмотреть файл

@ -80,7 +80,7 @@ class InterpreterData {
public boolean removeBreakpoint(int line) { public boolean removeBreakpoint(int line) {
int offset = getOffset(line); int offset = getOffset(line);
if (offset != -1 && itsICode[offset] == TokenStream.BREAKPOINT) if (offset != -1 && itsICode[offset] == (byte) TokenStream.BREAKPOINT)
{ {
itsICode[offset] = (byte) TokenStream.LINE; itsICode[offset] = (byte) TokenStream.LINE;
return true; return true;

Просмотреть файл

@ -449,7 +449,7 @@ public class NodeTransformer {
((FunctionNode) tree).setRequiresActivation(true); ((FunctionNode) tree).setRequiresActivation(true);
} }
VariableTable vars = getVariableTable(tree); VariableTable vars = getVariableTable(tree);
if (vars.get(name) != null) { if (vars.getVariable(name) != null) {
if (type == TokenStream.SETNAME) { if (type == TokenStream.SETNAME) {
node.setType(TokenStream.SETVAR); node.setType(TokenStream.SETVAR);
bind.setType(TokenStream.STRING); bind.setType(TokenStream.STRING);
@ -489,7 +489,7 @@ public class NodeTransformer {
((FunctionNode) tree).setRequiresActivation(true); ((FunctionNode) tree).setRequiresActivation(true);
} }
VariableTable vars = getVariableTable(tree); VariableTable vars = getVariableTable(tree);
if (vars.get(name) != null) { if (vars.getVariable(name) != null) {
node.setType(TokenStream.GETVAR); node.setType(TokenStream.GETVAR);
} }
break; break;
@ -510,7 +510,9 @@ public class NodeTransformer {
while ((node = iterator.nextNode()) != null) { while ((node = iterator.nextNode()) != null) {
int nodeType = node.getType(); int nodeType = node.getType();
if (inFunction && nodeType == TokenStream.FUNCTION && if (inFunction && nodeType == TokenStream.FUNCTION &&
node != tree) node != tree &&
((FunctionNode) node.getProp(Node.FUNCTION_PROP)).getFunctionType() ==
FunctionNode.FUNCTION_EXPRESSION_STATEMENT)
{ {
// In a function with both "var x" and "function x", // In a function with both "var x" and "function x",
// disregard the var statement, independent of order. // disregard the var statement, independent of order.
@ -531,6 +533,26 @@ public class NodeTransformer {
vars.addLocal(n.getString()); vars.addLocal(n.getString());
} }
} }
String name = (String) tree.getDatum();
if (inFunction && ((FunctionNode) tree).getFunctionType() ==
FunctionNode.FUNCTION_EXPRESSION &&
name != null && name.length() > 0 &&
vars.getVariable(name) == null)
{
// A function expression needs to have its name as a variable
// (if it isn't already allocated as a variable). See
// ECMA Ch. 13. We add code to the beginning of the function
// to initialize a local variable of the function's name
// to the function value.
vars.addLocal(name);
Node block = tree.getLastChild();
Node setFn = new Node(TokenStream.POP,
new Node(TokenStream.SETVAR,
new Node(TokenStream.STRING, name),
new Node(TokenStream.PRIMARY,
new Integer(TokenStream.THISFN))));
block.addChildrenToFront(setFn);
}
} }
protected void addParameters(FunctionNode fnNode) { protected void addParameters(FunctionNode fnNode) {
@ -580,7 +602,9 @@ public class NodeTransformer {
if (left.getType() == TokenStream.NAME) { if (left.getType() == TokenStream.NAME) {
VariableTable vars = getVariableTable(tree); VariableTable vars = getVariableTable(tree);
String name = left.getString(); String name = left.getString();
if (inFunction && vars.get(name) != null && !inWithStatement()) { if (inFunction && vars.getVariable(name) != null &&
!inWithStatement())
{
// call to a var. Transform to Call(GetVar("a"), b, c) // call to a var. Transform to Call(GetVar("a"), b, c)
left.setType(TokenStream.GETVAR); left.setType(TokenStream.GETVAR);
// fall through to code to add GetParent // fall through to code to add GetParent

Просмотреть файл

@ -854,12 +854,18 @@ public class ScriptRuntime {
/* It must be a string. */ /* It must be a string. */
int len = str.length(); int len = str.length();
char c; char c;
if (len > 0 && '0' <= (c = str.charAt(0)) && c <= '9' && boolean negate = false;
int i = 0;
if (len > 0 && (c = str.charAt(0)) == '-') {
negate = true;
i = 1;
}
if (len > 0 && '0' <= (c = str.charAt(i)) && c <= '9' &&
len <= MAX_VALUE_LENGTH) len <= MAX_VALUE_LENGTH)
{ {
int index = c - '0'; int index = c - '0';
int oldIndex = 0; int oldIndex = 0;
int i = 1; i++;
if (index != 0) { if (index != 0) {
while (i < len && '0' <= (c = str.charAt(i)) && c <= '9') { while (i < len && '0' <= (c = str.charAt(i)) && c <= '9') {
oldIndex = index; oldIndex = index;
@ -875,7 +881,7 @@ public class ScriptRuntime {
(oldIndex == (Integer.MAX_VALUE / 10) && (oldIndex == (Integer.MAX_VALUE / 10) &&
c < (Integer.MAX_VALUE % 10)))) c < (Integer.MAX_VALUE % 10))))
{ {
return index; return negate ? -index : index;
} }
} }
return NO_INDEX; return NO_INDEX;
@ -1159,9 +1165,14 @@ public class ScriptRuntime {
} while (next != null); } while (next != null);
bound.put(id, bound, value); bound.put(id, bound, value);
/*
This code is causing immense performance problems in
scripts that assign to the variables as a way of creating them.
XXX need strict mode
String[] args = { id }; String[] args = { id };
String message = getMessage("msg.assn.create", args); String message = getMessage("msg.assn.create", args);
Context.reportWarning(message); Context.reportWarning(message);
*/
return value; return value;
} }
return setProp(bound, id, value, scope); return setProp(bound, id, value, scope);
@ -1947,11 +1958,12 @@ public class ScriptRuntime {
public static NativeFunction initFunction(NativeFunction fn, public static NativeFunction initFunction(NativeFunction fn,
Scriptable scope, Scriptable scope,
String fnName, String fnName,
Context cx) Context cx,
boolean doSetName)
{ {
fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function")); fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function"));
fn.setParentScope(scope); fn.setParentScope(scope);
if (fnName != null && fnName.length() != 0) if (doSetName)
setName(scope, fn, scope, fnName); setName(scope, fn, scope, fnName);
return fn; return fn;
} }

Просмотреть файл

@ -168,47 +168,48 @@ public class TokenStream {
SETPARENT = 84, SETPARENT = 84,
SCOPE = 85, SCOPE = 85,
GETSCOPEPARENT = 86, GETSCOPEPARENT = 86,
JTHROW = 87, THISFN = 87,
JTHROW = 88,
// End of interpreter bytecodes // End of interpreter bytecodes
SEMI = 88, // semicolon SEMI = 89, // semicolon
LB = 89, // left and right brackets LB = 90, // left and right brackets
RB = 90, RB = 91,
LC = 91, // left and right curlies (braces) LC = 92, // left and right curlies (braces)
RC = 92, RC = 93,
LP = 93, // left and right parentheses LP = 94, // left and right parentheses
RP = 94, RP = 95,
COMMA = 95, // comma operator COMMA = 96, // comma operator
ASSIGN = 96, // assignment ops (= += -= etc.) ASSIGN = 97, // assignment ops (= += -= etc.)
HOOK = 97, // conditional (?:) HOOK = 98, // conditional (?:)
COLON = 98, COLON = 99,
OR = 99, // logical or (||) OR = 100, // logical or (||)
AND = 100, // logical and (&&) AND = 101, // logical and (&&)
EQOP = 101, // equality ops (== !=) EQOP = 102, // equality ops (== !=)
RELOP = 102, // relational ops (< <= > >=) RELOP = 103, // relational ops (< <= > >=)
SHOP = 103, // shift ops (<< >> >>>) SHOP = 104, // shift ops (<< >> >>>)
UNARYOP = 104, // unary prefix operator UNARYOP = 105, // unary prefix operator
INC = 105, // increment/decrement (++ --) INC = 106, // increment/decrement (++ --)
DEC = 106, DEC = 107,
DOT = 107, // member operator (.) DOT = 108, // member operator (.)
PRIMARY = 108, // true, false, null, this PRIMARY = 109, // true, false, null, this
FUNCTION = 109, // function keyword FUNCTION = 110, // function keyword
EXPORT = 110, // export keyword EXPORT = 111, // export keyword
IMPORT = 111, // import keyword IMPORT = 112, // import keyword
IF = 112, // if keyword IF = 113, // if keyword
ELSE = 113, // else keyword ELSE = 114, // else keyword
SWITCH = 114, // switch keyword SWITCH = 115, // switch keyword
CASE = 115, // case keyword CASE = 116, // case keyword
DEFAULT = 116, // default keyword DEFAULT = 117, // default keyword
WHILE = 117, // while keyword WHILE = 118, // while keyword
DO = 118, // do keyword DO = 119, // do keyword
FOR = 119, // for keyword FOR = 120, // for keyword
BREAK = 120, // break keyword BREAK = 121, // break keyword
CONTINUE = 121, // continue keyword CONTINUE = 122, // continue keyword
VAR = 122, // var keyword VAR = 123, // var keyword
WITH = 123, // with keyword WITH = 124, // with keyword
CATCH = 124, // catch keyword CATCH = 125, // catch keyword
FINALLY = 125, // finally keyword FINALLY = 126, // finally keyword
RESERVED = 126, // reserved keywords RESERVED = 127, // reserved keywords
/** Added by Mike - these are JSOPs in the jsref, but I /** Added by Mike - these are JSOPs in the jsref, but I
* don't have them yet in the java implementation... * don't have them yet in the java implementation...
@ -217,45 +218,45 @@ public class TokenStream {
* Most of these go in the 'op' field when returning * Most of these go in the 'op' field when returning
* more general token types, eg. 'DIV' as the op of 'ASSIGN'. * more general token types, eg. 'DIV' as the op of 'ASSIGN'.
*/ */
NOP = 127, // NOP NOP = 128, // NOP
NOT = 128, // etc. NOT = 129, // etc.
PRE = 129, // for INC, DEC nodes. PRE = 130, // for INC, DEC nodes.
POST = 130, POST = 131,
/** /**
* For JSOPs associated with keywords... * For JSOPs associated with keywords...
* eg. op = THIS; token = PRIMARY * eg. op = THIS; token = PRIMARY
*/ */
VOID = 131, VOID = 132,
/* types used for the parse tree - these never get returned /* types used for the parse tree - these never get returned
* by the scanner. * by the scanner.
*/ */
BLOCK = 132, // statement block BLOCK = 133, // statement block
ARRAYLIT = 133, // array literal ARRAYLIT = 134, // array literal
OBJLIT = 134, // object literal OBJLIT = 135, // object literal
LABEL = 135, // label LABEL = 136, // label
TARGET = 136, TARGET = 137,
LOOP = 137, LOOP = 138,
ENUMDONE = 138, ENUMDONE = 139,
EXPRSTMT = 139, EXPRSTMT = 140,
PARENT = 140, PARENT = 141,
CONVERT = 141, CONVERT = 142,
JSR = 142, JSR = 143,
NEWLOCAL = 143, NEWLOCAL = 144,
USELOCAL = 144, USELOCAL = 145,
SCRIPT = 145, // top-level node for entire script SCRIPT = 146, // top-level node for entire script
/** /**
* For the interpreted mode indicating a line number change in icodes. * For the interpreted mode indicating a line number change in icodes.
*/ */
LINE = 146, LINE = 147,
SOURCEFILE = 147, SOURCEFILE = 148,
// For debugger // For debugger
BREAKPOINT = 148; BREAKPOINT = 149;
// end enum // end enum
@ -354,6 +355,7 @@ public class TokenStream {
"setparent", "setparent",
"scope", "scope",
"getscopeparent", "getscopeparent",
"thisfn",
"jthrow", "jthrow",
"semi", "semi",
"lb", "lb",

Просмотреть файл

@ -49,4 +49,6 @@ public interface DebuggableEngine {
public Debugger getDebugger(); public Debugger getDebugger();
public Frame getFrame(int frameNumber); public Frame getFrame(int frameNumber);
//public void haltExecution();
} }

Просмотреть файл

@ -46,6 +46,8 @@ import java.util.Enumeration;
* code (either functions or top-level scripts). * code (either functions or top-level scripts).
*/ */
public interface DebuggableScript { public interface DebuggableScript {
//public boolean isFunction(); // XXX
/** /**
* Get the Scriptable object (Function or Script) that is * Get the Scriptable object (Function or Script) that is

Просмотреть файл

@ -217,7 +217,7 @@ public class Block {
} }
for (int i = 0; i < liveSet.length; i++) { for (int i = 0; i < liveSet.length; i++) {
if (liveSet[i]) if (liveSet[i])
((OptLocalVariable)theVariables.get(i)).markLiveAcrossCall(); ((OptLocalVariable)theVariables.getVariable(i)).markLiveAcrossCall();
} }
} }
break; break;
@ -246,7 +246,7 @@ public class Block {
{ {
for (int i = 0; i < theVariables.size(); i++) for (int i = 0; i < theVariables.size(); i++)
if (itsLiveOnEntrySet.test(i)) if (itsLiveOnEntrySet.test(i))
((OptLocalVariable)theVariables.get(i)).assignType(TypeEvent.AnyType); ((OptLocalVariable)theVariables.getVariable(i)).assignType(TypeEvent.AnyType);
} }
@ -650,13 +650,13 @@ public class Block {
{ {
for (int i = 0; i < theVariables.size(); i++) { for (int i = 0; i < theVariables.size(); i++) {
if (itsUseBeforeDefSet.test(i)) if (itsUseBeforeDefSet.test(i))
pw.println(theVariables.get(i).getName() + " is used before def'd"); pw.println(theVariables.getVariable(i).getName() + " is used before def'd");
if (itsNotDefSet.test(i)) if (itsNotDefSet.test(i))
pw.println(theVariables.get(i).getName() + " is not def'd"); pw.println(theVariables.getVariable(i).getName() + " is not def'd");
if (itsLiveOnEntrySet.test(i)) if (itsLiveOnEntrySet.test(i))
pw.println(theVariables.get(i).getName() + " is live on entry"); pw.println(theVariables.getVariable(i).getName() + " is live on entry");
if (itsLiveOnExitSet.test(i)) if (itsLiveOnExitSet.test(i))
pw.println(theVariables.get(i).getName() + " is live on exit"); pw.println(theVariables.getVariable(i).getName() + " is live on exit");
} }
} }

Просмотреть файл

@ -457,7 +457,7 @@ public class Codegen extends Interpreter {
// make sure that all parameters are objects // make sure that all parameters are objects
itsForcedObjectParameters = true; itsForcedObjectParameters = true;
for (int i = 0; i < vars.getParameterCount(); i++) { for (int i = 0; i < vars.getParameterCount(); i++) {
OptLocalVariable lVar = (OptLocalVariable) vars.get(i); OptLocalVariable lVar = (OptLocalVariable) vars.getVariable(i);
aload(lVar.getJRegister()); aload(lVar.getJRegister());
classFile.add(ByteCode.GETSTATIC, classFile.add(ByteCode.GETSTATIC,
"java/lang/Void", "java/lang/Void",
@ -1347,12 +1347,18 @@ public class Codegen extends Interpreter {
addByteCode(ByteCode.ACONST_NULL); addByteCode(ByteCode.ACONST_NULL);
} }
// load 'cx' // load 'cx'
aload(contextLocal); aload(contextLocal);
// load boolean indicating whether fn name should be set in scope
boolean setFnName = str != null && str.length() > 0 &&
((FunctionNode) def).getFunctionType() !=
FunctionNode.FUNCTION_EXPRESSION;
addByteCode(setFnName ? ByteCode.ICONST_1 : ByteCode.ICONST_0);
addScriptRuntimeInvoke("initFunction", addScriptRuntimeInvoke("initFunction",
"(Lorg/mozilla/javascript/NativeFunction;" + "(Lorg/mozilla/javascript/NativeFunction;" +
"Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/String;" + "Ljava/lang/String;" +
"Lorg/mozilla/javascript/Context;)", "Lorg/mozilla/javascript/Context;Z)",
"Lorg/mozilla/javascript/NativeFunction;"); "Lorg/mozilla/javascript/NativeFunction;");
def.putProp(Node.FUNCTION_PROP, new Short(i)); def.putProp(Node.FUNCTION_PROP, new Short(i));
addByteCode(ByteCode.AASTORE); // store NativeFunction addByteCode(ByteCode.AASTORE); // store NativeFunction
@ -1447,7 +1453,7 @@ public class Codegen extends Interpreter {
// before the next call and are used in the function // before the next call and are used in the function
short firstUndefVar = -1; short firstUndefVar = -1;
for (int i = 0; i < vars.size(); i++) { for (int i = 0; i < vars.size(); i++) {
OptLocalVariable lVar = (OptLocalVariable) vars.get(i); OptLocalVariable lVar = (OptLocalVariable) vars.getVariable(i);
if (lVar.isNumber()) { if (lVar.isNumber()) {
lVar.assignJRegister(getNewWordPairLocal()); lVar.assignJRegister(getNewWordPairLocal());
push(0.0); push(0.0);
@ -1547,7 +1553,7 @@ public class Codegen extends Interpreter {
if (cx.isGeneratingDebug()) { if (cx.isGeneratingDebug()) {
debugVars = new OptVariableTable(); debugVars = new OptVariableTable();
debugVars.addLocal(debugVariableName); debugVars.addLocal(debugVariableName);
OptLocalVariable lv = (OptLocalVariable) debugVars.get(debugVariableName); OptLocalVariable lv = (OptLocalVariable) debugVars.getVariable(debugVariableName);
lv.assignJRegister(variableObjectLocal); lv.assignJRegister(variableObjectLocal);
lv.setStartPC(classFile.getCurrentCodeOffset()); lv.setStartPC(classFile.getCurrentCodeOffset());
} }
@ -1876,7 +1882,6 @@ public class Codegen extends Interpreter {
*/ */
{ {
if (true) {
Node callBase = callNode.getFirstChild(); Node callBase = callNode.getFirstChild();
if (callBase.getType() == TokenStream.GETPROP) { if (callBase.getType() == TokenStream.GETPROP) {
Node callBaseChild = callBase.getFirstChild(); Node callBaseChild = callBase.getFirstChild();
@ -1903,7 +1908,6 @@ if (true) {
} }
} }
} }
}
return null; return null;
} }
@ -2425,7 +2429,7 @@ if (true) {
} }
String name = node.getString(); String name = node.getString();
if (hasVarsInRegs) { if (hasVarsInRegs) {
OptLocalVariable lVar = (OptLocalVariable) vars.get(name); OptLocalVariable lVar = (OptLocalVariable) vars.getVariable(name);
if (lVar != null) { if (lVar != null) {
if (lVar.isNumber()) { if (lVar.isNumber()) {
push("number"); push("number");
@ -2463,7 +2467,7 @@ if (true) {
String routine = (isInc) ? "postIncrement" : "postDecrement"; String routine = (isInc) ? "postIncrement" : "postDecrement";
if (hasVarsInRegs && child.getType() == TokenStream.GETVAR) { if (hasVarsInRegs && child.getType() == TokenStream.GETVAR) {
if (lVar == null) if (lVar == null)
lVar = (OptLocalVariable) vars.get(child.getString()); lVar = (OptLocalVariable) vars.getVariable(child.getString());
if (lVar.getJRegister() == -1) if (lVar.getJRegister() == -1)
lVar.assignJRegister(getNewWordLocal()); lVar.assignJRegister(getNewWordLocal());
aload(lVar.getJRegister()); aload(lVar.getJRegister());
@ -3173,6 +3177,10 @@ if (true) {
aload(thisObjLocal); aload(thisObjLocal);
break; break;
case TokenStream.THISFN:
classFile.add(ByteCode.ALOAD_0);
break;
case TokenStream.NULL: case TokenStream.NULL:
addByteCode(ByteCode.ACONST_NULL); addByteCode(ByteCode.ACONST_NULL);
break; break;
@ -3232,7 +3240,7 @@ if (true) {
{ {
// TODO: Clean up use of lVar here and in set. // TODO: Clean up use of lVar here and in set.
if (hasVarsInRegs && lVar == null) if (hasVarsInRegs && lVar == null)
lVar = (OptLocalVariable) vars.get(name); lVar = (OptLocalVariable) vars.getVariable(name);
if (lVar != null) { if (lVar != null) {
if (lVar.getJRegister() == -1) if (lVar.getJRegister() == -1)
if (lVar.isNumber()) if (lVar.isNumber())
@ -3303,7 +3311,7 @@ if (true) {
OptLocalVariable lVar = (OptLocalVariable)(node.getProp(Node.VARIABLE_PROP)); OptLocalVariable lVar = (OptLocalVariable)(node.getProp(Node.VARIABLE_PROP));
// XXX is this right? If so, clean up. // XXX is this right? If so, clean up.
if (hasVarsInRegs && lVar == null) if (hasVarsInRegs && lVar == null)
lVar = (OptLocalVariable) vars.get(child.getString()); lVar = (OptLocalVariable) vars.getVariable(child.getString());
if (lVar != null) { if (lVar != null) {
generateCodeFromNode(child.getNextSibling(), node, -1, -1); generateCodeFromNode(child.getNextSibling(), node, -1, -1);
if (lVar.getJRegister() == -1) { if (lVar.getJRegister() == -1) {

Просмотреть файл

@ -168,7 +168,7 @@ public class Optimizer {
} }
} }
for (int i = 0; i < theVariables.size(); i++) { for (int i = 0; i < theVariables.size(); i++) {
OptLocalVariable lVar = (OptLocalVariable) theVariables.get(i); OptLocalVariable lVar = (OptLocalVariable) theVariables.getVariable(i);
if (!lVar.isParameter()) { if (!lVar.isParameter()) {
int theType = lVar.getTypeUnion(); int theType = lVar.getTypeUnion();
if (theType == TypeEvent.NumberType) { if (theType == TypeEvent.NumberType) {
@ -1043,7 +1043,7 @@ public class Optimizer {
case TokenStream.SETVAR : { case TokenStream.SETVAR : {
String name = n.getFirstChild().getString(); String name = n.getFirstChild().getString();
OptLocalVariable theVar = (OptLocalVariable) OptLocalVariable theVar = (OptLocalVariable)
theVariables.get(name); theVariables.getVariable(name);
if (theVar != null) if (theVar != null)
n.putProp(Node.VARIABLE_PROP, theVar); n.putProp(Node.VARIABLE_PROP, theVar);
} }
@ -1051,7 +1051,7 @@ public class Optimizer {
case TokenStream.GETVAR : { case TokenStream.GETVAR : {
String name = n.getString(); String name = n.getString();
OptLocalVariable theVar = (OptLocalVariable) OptLocalVariable theVar = (OptLocalVariable)
theVariables.get(name); theVariables.getVariable(name);
if (theVar != null) if (theVar != null)
n.putProp(Node.VARIABLE_PROP, theVar); n.putProp(Node.VARIABLE_PROP, theVar);
} }