mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 10:00:54 +00:00
Decompling parsing from code generation: compiler instances are created only when parsing tree is build.
This commit is contained in:
parent
ea68f99149
commit
3cab5b3e26
128
js/rhino/src/org/mozilla/javascript/CompilerEnvirons.java
Normal file
128
js/rhino/src/org/mozilla/javascript/CompilerEnvirons.java
Normal file
@ -0,0 +1,128 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is representation of compiler options for Rhino.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* RUnit Software AS.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2003
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Igor Bukanov, igor@fastmail.fm
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
public class CompilerEnvirons
|
||||
{
|
||||
public void initFromContext(Context cx, ErrorReporter syntaxErrorReporter)
|
||||
{
|
||||
setSyntaxErrorReporter(syntaxErrorReporter);
|
||||
this.languageVersion = cx.getLanguageVersion();
|
||||
useDynamicScope = cx.hasCompileFunctionsWithDynamicScope();
|
||||
generateDebugInfo = (!cx.isGeneratingDebugChanged()
|
||||
|| cx.isGeneratingDebug());
|
||||
this.reservedKeywordAsIdentifier
|
||||
= cx.hasFeature(Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER);
|
||||
this.allowMemberExprAsFunctionName
|
||||
= cx.hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME);
|
||||
}
|
||||
|
||||
public final int getSyntaxErrorCount()
|
||||
{
|
||||
return syntaxErrorCount;
|
||||
}
|
||||
|
||||
public void setSyntaxErrorReporter(ErrorReporter syntaxErrorReporter)
|
||||
{
|
||||
if (syntaxErrorReporter == null) Kit.argBug();
|
||||
this.syntaxErrorReporter = syntaxErrorReporter;
|
||||
}
|
||||
|
||||
public final void reportSyntaxError(boolean isError,
|
||||
String messageProperty, Object[] args,
|
||||
String sourceName, int lineno,
|
||||
String line, int lineOffset)
|
||||
{
|
||||
String message = Context.getMessage(messageProperty, args);
|
||||
if (isError) {
|
||||
++syntaxErrorCount;
|
||||
if (fromEval) {
|
||||
// We're probably in an eval. Need to throw an exception.
|
||||
throw ScriptRuntime.constructError(
|
||||
"SyntaxError", message, sourceName,
|
||||
lineno, line, lineOffset);
|
||||
} else {
|
||||
syntaxErrorReporter.error(message, sourceName,
|
||||
lineno, line, lineOffset);
|
||||
}
|
||||
} else {
|
||||
syntaxErrorReporter.warning(message, sourceName,
|
||||
lineno, line, lineOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isFromEval()
|
||||
{
|
||||
return fromEval;
|
||||
}
|
||||
|
||||
public void setFromEval(boolean fromEval)
|
||||
{
|
||||
this.fromEval = fromEval;
|
||||
}
|
||||
|
||||
public final int getLanguageVersion()
|
||||
{
|
||||
return languageVersion;
|
||||
}
|
||||
|
||||
public final boolean isGenerateDebugInfo()
|
||||
{
|
||||
return generateDebugInfo;
|
||||
}
|
||||
|
||||
public final boolean isUseDynamicScope()
|
||||
{
|
||||
return useDynamicScope;
|
||||
}
|
||||
|
||||
private ErrorReporter syntaxErrorReporter;
|
||||
private int syntaxErrorCount;
|
||||
|
||||
private boolean fromEval;
|
||||
|
||||
int languageVersion = Context.VERSION_DEFAULT;
|
||||
boolean generateDebugInfo;
|
||||
boolean useDynamicScope;
|
||||
boolean reservedKeywordAsIdentifier;
|
||||
boolean allowMemberExprAsFunctionName;
|
||||
|
||||
|
||||
}
|
||||
|
@ -977,17 +977,17 @@ public class Context
|
||||
public boolean stringIsCompilableUnit(String source)
|
||||
{
|
||||
boolean errorseen = false;
|
||||
Interpreter compiler = new Interpreter();
|
||||
compiler.setSyntaxErrorReporter(new DefaultErrorReporter(), false);
|
||||
CompilerEnvirons compilerEnv = new CompilerEnvirons();
|
||||
compilerEnv.initFromContext(this, new DefaultErrorReporter());
|
||||
// no source name or source text manager, because we're just
|
||||
// going to throw away the result.
|
||||
TokenStream ts = new TokenStream(this, compiler, null, source, null, 1);
|
||||
TokenStream ts = new TokenStream(compilerEnv,
|
||||
null, source, null, 1);
|
||||
|
||||
IRFactory irf = new IRFactory(compiler, ts);
|
||||
Parser p = createParser();
|
||||
Parser p = new Parser(compilerEnv);
|
||||
Decompiler decompiler = new Decompiler();
|
||||
try {
|
||||
p.parse(ts, irf, decompiler);
|
||||
p.parse(ts, decompiler);
|
||||
} catch (IOException ioe) {
|
||||
errorseen = true;
|
||||
} catch (EvaluatorException ee) {
|
||||
@ -2014,16 +2014,10 @@ public class Context
|
||||
// scope should be given if and only if compiling function
|
||||
if (!(scope == null ^ returnFunction)) Kit.codeBug();
|
||||
|
||||
Interpreter compiler = createCompiler();
|
||||
CompilerEnvirons compilerEnv = new CompilerEnvirons();
|
||||
ErrorReporter reporter = getErrorReporter();
|
||||
compiler.setSyntaxErrorReporter(reporter, fromEval);
|
||||
|
||||
if (securityController != null) {
|
||||
securityDomain = securityController.
|
||||
getDynamicSecurityDomain(securityDomain);
|
||||
} else {
|
||||
securityDomain = null;
|
||||
}
|
||||
compilerEnv.initFromContext(this, reporter);
|
||||
compilerEnv.setFromEval(fromEval);
|
||||
|
||||
if (debugger != null) {
|
||||
if (sourceReader != null) {
|
||||
@ -2032,15 +2026,23 @@ public class Context
|
||||
}
|
||||
}
|
||||
|
||||
TokenStream ts = new TokenStream(this, compiler,
|
||||
TokenStream ts = new TokenStream(compilerEnv,
|
||||
sourceReader, sourceString,
|
||||
sourceName, lineno);
|
||||
Parser p = createParser();
|
||||
|
||||
IRFactory irf = new IRFactory(compiler, ts);
|
||||
Parser p = new Parser(compilerEnv);
|
||||
Decompiler decompiler = new Decompiler();
|
||||
ScriptOrFnNode tree = p.parse(ts, irf, decompiler);
|
||||
if (compiler.syntaxErrorCount == 0) {
|
||||
ScriptOrFnNode tree = p.parse(ts, decompiler);
|
||||
int syntaxErrorCount = compilerEnv.getSyntaxErrorCount();
|
||||
if (syntaxErrorCount == 0) {
|
||||
Interpreter compiler = createCompiler();
|
||||
compiler.compilerEnv = compilerEnv;
|
||||
if (securityController != null) {
|
||||
securityDomain = securityController.
|
||||
getDynamicSecurityDomain(securityDomain);
|
||||
} else {
|
||||
securityDomain = null;
|
||||
}
|
||||
|
||||
String encodedSource = null;
|
||||
if (isGeneratingSource()) {
|
||||
encodedSource = decompiler.getEncodedSource();
|
||||
@ -2063,7 +2065,8 @@ public class Context
|
||||
Object result = compiler.compile(this, scope, tree,
|
||||
securityController, securityDomain,
|
||||
encodedSource);
|
||||
if (compiler.syntaxErrorCount == 0) {
|
||||
syntaxErrorCount = compilerEnv.getSyntaxErrorCount();
|
||||
if (syntaxErrorCount == 0) {
|
||||
if (debugger != null) {
|
||||
if (sourceString == null) Kit.codeBug();
|
||||
compiler.notifyDebuggerCompilationDone(this, result,
|
||||
@ -2073,7 +2076,7 @@ public class Context
|
||||
}
|
||||
}
|
||||
String msg = Context.getMessage1("msg.got.syntax.errors",
|
||||
String.valueOf(compiler.syntaxErrorCount));
|
||||
String.valueOf(syntaxErrorCount));
|
||||
throw reporter.runtimeError(msg, sourceName, lineno, null, 0);
|
||||
}
|
||||
|
||||
@ -2091,14 +2094,6 @@ public class Context
|
||||
return result;
|
||||
}
|
||||
|
||||
private Parser createParser() {
|
||||
Parser parser = new Parser();
|
||||
parser.setLanguageVersion(getLanguageVersion());
|
||||
parser.setAllowMemberExprAsFunctionName(
|
||||
hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME));
|
||||
return parser;
|
||||
}
|
||||
|
||||
static String getSourcePositionFromStack(int[] linep) {
|
||||
Context cx = getCurrentContext();
|
||||
if (cx == null)
|
||||
|
@ -43,21 +43,22 @@ package org.mozilla.javascript;
|
||||
* @author Mike McCabe
|
||||
* @author Norris Boyd
|
||||
*/
|
||||
public class IRFactory {
|
||||
|
||||
public IRFactory(Interpreter compiler, TokenStream ts) {
|
||||
this.compiler = compiler;
|
||||
class IRFactory
|
||||
{
|
||||
IRFactory(TokenStream ts)
|
||||
{
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
public ScriptOrFnNode createScript() {
|
||||
ScriptOrFnNode createScript()
|
||||
{
|
||||
return new ScriptOrFnNode(Token.SCRIPT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Script (for associating file/url names with toplevel scripts.)
|
||||
*/
|
||||
public void initScript(ScriptOrFnNode scriptNode, Object body)
|
||||
void initScript(ScriptOrFnNode scriptNode, Object body)
|
||||
{
|
||||
Node children = ((Node) body).getFirstChild();
|
||||
if (children != null) { scriptNode.addChildrenToBack(children); }
|
||||
@ -66,11 +67,13 @@ public class IRFactory {
|
||||
/**
|
||||
* Leaf
|
||||
*/
|
||||
public Object createLeaf(int nodeType) {
|
||||
Object createLeaf(int nodeType)
|
||||
{
|
||||
return new Node(nodeType);
|
||||
}
|
||||
|
||||
public Object createLeaf(int nodeType, int nodeOp) {
|
||||
Object createLeaf(int nodeType, int nodeOp)
|
||||
{
|
||||
return new Node(nodeType, nodeOp);
|
||||
}
|
||||
|
||||
@ -78,40 +81,47 @@ public class IRFactory {
|
||||
* Statement leaf nodes.
|
||||
*/
|
||||
|
||||
public Object createSwitch(int lineno) {
|
||||
Object createSwitch(int lineno)
|
||||
{
|
||||
return new Node.Jump(Token.SWITCH, lineno);
|
||||
}
|
||||
|
||||
public Object createVariables(int lineno) {
|
||||
Object createVariables(int lineno)
|
||||
{
|
||||
return new Node(Token.VAR, lineno);
|
||||
}
|
||||
|
||||
public Object createExprStatement(Object expr, int lineno) {
|
||||
Object createExprStatement(Object expr, int lineno)
|
||||
{
|
||||
return new Node(Token.EXPRSTMT, (Node) expr, lineno);
|
||||
}
|
||||
|
||||
public Object createExprStatementNoReturn(Object expr, int lineno) {
|
||||
Object createExprStatementNoReturn(Object expr, int lineno)
|
||||
{
|
||||
return new Node(Token.POP, (Node) expr, lineno);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name
|
||||
*/
|
||||
public Object createName(String name) {
|
||||
Object createName(String name)
|
||||
{
|
||||
return Node.newString(Token.NAME, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* String (for literals)
|
||||
*/
|
||||
public Object createString(String string) {
|
||||
Object createString(String string)
|
||||
{
|
||||
return Node.newString(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number (for literals)
|
||||
*/
|
||||
public Object createNumber(double number) {
|
||||
Object createNumber(double number)
|
||||
{
|
||||
return Node.newNumber(number);
|
||||
}
|
||||
|
||||
@ -123,8 +133,8 @@ public class IRFactory {
|
||||
* @param stmts the statements in the catch clause
|
||||
* @param lineno the starting line number of the catch clause
|
||||
*/
|
||||
public Object createCatch(String varName, Object catchCond, Object stmts,
|
||||
int lineno)
|
||||
Object createCatch(String varName, Object catchCond, Object stmts,
|
||||
int lineno)
|
||||
{
|
||||
if (catchCond == null) {
|
||||
catchCond = new Node(Token.EMPTY);
|
||||
@ -136,14 +146,16 @@ public class IRFactory {
|
||||
/**
|
||||
* Throw
|
||||
*/
|
||||
public Object createThrow(Object expr, int lineno) {
|
||||
Object createThrow(Object expr, int lineno)
|
||||
{
|
||||
return new Node(Token.THROW, (Node)expr, lineno);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return
|
||||
*/
|
||||
public Object createReturn(Object expr, int lineno) {
|
||||
Object createReturn(Object expr, int lineno)
|
||||
{
|
||||
return expr == null
|
||||
? new Node(Token.RETURN, lineno)
|
||||
: new Node(Token.RETURN, (Node)expr, lineno);
|
||||
@ -152,7 +164,7 @@ public class IRFactory {
|
||||
/**
|
||||
* Label
|
||||
*/
|
||||
public Object createLabel(String label, int lineno)
|
||||
Object createLabel(String label, int lineno)
|
||||
{
|
||||
Node.Jump n = new Node.Jump(Token.LABEL, lineno);
|
||||
n.setLabel(label);
|
||||
@ -162,7 +174,7 @@ public class IRFactory {
|
||||
/**
|
||||
* Break (possibly labeled)
|
||||
*/
|
||||
public Object createBreak(String label, int lineno)
|
||||
Object createBreak(String label, int lineno)
|
||||
{
|
||||
Node.Jump n = new Node.Jump(Token.BREAK, lineno);
|
||||
if (label != null) {
|
||||
@ -174,7 +186,7 @@ public class IRFactory {
|
||||
/**
|
||||
* Continue (possibly labeled)
|
||||
*/
|
||||
public Object createContinue(String label, int lineno)
|
||||
Object createContinue(String label, int lineno)
|
||||
{
|
||||
Node.Jump n = new Node.Jump(Token.CONTINUE, lineno);
|
||||
if (label != null) {
|
||||
@ -188,16 +200,18 @@ public class IRFactory {
|
||||
* Creates the empty statement block
|
||||
* Must make subsequent calls to add statements to the node
|
||||
*/
|
||||
public Object createBlock(int lineno) {
|
||||
Object createBlock(int lineno)
|
||||
{
|
||||
return new Node(Token.BLOCK, lineno);
|
||||
}
|
||||
|
||||
public FunctionNode createFunction(String name) {
|
||||
return compiler.createFunctionNode(name);
|
||||
FunctionNode createFunction(String name)
|
||||
{
|
||||
return new FunctionNode(name);
|
||||
}
|
||||
|
||||
public Object initFunction(FunctionNode fnNode, int functionIndex,
|
||||
Object statements, int functionType)
|
||||
Object initFunction(FunctionNode fnNode, int functionIndex,
|
||||
Object statements, int functionType)
|
||||
{
|
||||
Node stmts = (Node)statements;
|
||||
fnNode.setFunctionType(functionType);
|
||||
@ -256,14 +270,16 @@ public class IRFactory {
|
||||
* breaks the Factory abstraction, but it removes a requirement
|
||||
* from implementors of Node.
|
||||
*/
|
||||
public void addChildToBack(Object parent, Object child) {
|
||||
void addChildToBack(Object parent, Object child)
|
||||
{
|
||||
((Node)parent).addChildToBack((Node)child);
|
||||
}
|
||||
|
||||
/**
|
||||
* While
|
||||
*/
|
||||
public Object createWhile(Object cond, Object body, int lineno) {
|
||||
Object createWhile(Object cond, Object body, int lineno)
|
||||
{
|
||||
return createLoop(LOOP_WHILE, (Node)body, (Node)cond, null, null,
|
||||
lineno);
|
||||
}
|
||||
@ -271,7 +287,8 @@ public class IRFactory {
|
||||
/**
|
||||
* DoWhile
|
||||
*/
|
||||
public Object createDoWhile(Object body, Object cond, int lineno) {
|
||||
Object createDoWhile(Object body, Object cond, int lineno)
|
||||
{
|
||||
return createLoop(LOOP_DO_WHILE, (Node)body, (Node)cond, null, null,
|
||||
lineno);
|
||||
}
|
||||
@ -279,8 +296,8 @@ public class IRFactory {
|
||||
/**
|
||||
* For
|
||||
*/
|
||||
public Object createFor(Object init, Object test, Object incr,
|
||||
Object body, int lineno)
|
||||
Object createFor(Object init, Object test, Object incr, Object body,
|
||||
int lineno)
|
||||
{
|
||||
return createLoop(LOOP_FOR, (Node)body, (Node)test,
|
||||
(Node)init, (Node)incr, lineno);
|
||||
@ -344,7 +361,8 @@ public class IRFactory {
|
||||
* For .. In
|
||||
*
|
||||
*/
|
||||
public Object createForIn(Object lhs, Object obj, Object body, int lineno) {
|
||||
Object createForIn(Object lhs, Object obj, Object body, int lineno)
|
||||
{
|
||||
String name;
|
||||
Node lhsNode = (Node) lhs;
|
||||
Node objNode = (Node) obj;
|
||||
@ -415,8 +433,8 @@ public class IRFactory {
|
||||
|
||||
* ... and a goto to GOTO around these handlers.
|
||||
*/
|
||||
public Object createTryCatchFinally(Object tryblock, Object catchblocks,
|
||||
Object finallyblock, int lineno)
|
||||
Object createTryCatchFinally(Object tryblock, Object catchblocks,
|
||||
Object finallyblock, int lineno)
|
||||
{
|
||||
Node trynode = (Node)tryblock;
|
||||
boolean hasFinally = false;
|
||||
@ -581,7 +599,8 @@ public class IRFactory {
|
||||
/**
|
||||
* With
|
||||
*/
|
||||
public Object createWith(Object obj, Object body, int lineno) {
|
||||
Object createWith(Object obj, Object body, int lineno)
|
||||
{
|
||||
Node result = new Node(Token.BLOCK, lineno);
|
||||
result.addChildToBack(new Node(Token.ENTERWITH, (Node)obj));
|
||||
Node bodyNode = new Node(Token.WITH, (Node) body, lineno);
|
||||
@ -596,7 +615,8 @@ public class IRFactory {
|
||||
* plus a series of array element entries, so later compiler
|
||||
* stages don't need to know about array literals.
|
||||
*/
|
||||
public Object createArrayLiteral(Object obj) {
|
||||
Object createArrayLiteral(Object obj)
|
||||
{
|
||||
Node array;
|
||||
array = new Node(Token.NEW, Node.newString(Token.NAME, "Array"));
|
||||
Node list = new Node(Token.INIT_LIST, array);
|
||||
@ -628,7 +648,7 @@ public class IRFactory {
|
||||
* (Which will make Array optimizations involving allocating a
|
||||
* Java array to back the javascript array work better.)
|
||||
*/
|
||||
if (ts.cx.getLanguageVersion() == Context.VERSION_1_2) {
|
||||
if (ts.compilerEnv.languageVersion == Context.VERSION_1_2) {
|
||||
/* When last array element is empty, we need to set the
|
||||
* length explicitly, because we can't depend on SETELEM
|
||||
* to do it for us - because empty [,,] array elements
|
||||
@ -652,7 +672,8 @@ public class IRFactory {
|
||||
* creation plus object property entries, so later compiler
|
||||
* stages don't need to know about object literals.
|
||||
*/
|
||||
public Object createObjectLiteral(Object obj) {
|
||||
Object createObjectLiteral(Object obj)
|
||||
{
|
||||
Node result = new Node(Token.NEW,
|
||||
Node.newString(Token.NAME, "Object"));
|
||||
Node list = new Node(Token.INIT_LIST, result);
|
||||
@ -675,7 +696,8 @@ public class IRFactory {
|
||||
/**
|
||||
* Regular expressions
|
||||
*/
|
||||
public Object createRegExp(int regexpIndex) {
|
||||
Object createRegExp(int regexpIndex)
|
||||
{
|
||||
Node n = new Node(Token.REGEXP);
|
||||
n.putIntProp(Node.REGEXP_PROP, regexpIndex);
|
||||
return n;
|
||||
@ -684,8 +706,7 @@ public class IRFactory {
|
||||
/**
|
||||
* If statement
|
||||
*/
|
||||
public Object createIf(Object condObj, Object ifTrue, Object ifFalse,
|
||||
int lineno)
|
||||
Object createIf(Object condObj, Object ifTrue, Object ifFalse, int lineno)
|
||||
{
|
||||
Node cond = (Node)condObj;
|
||||
int condStatus = isAlwaysDefinedBoolean(cond);
|
||||
@ -722,7 +743,7 @@ public class IRFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object createCondExpr(Object condObj, Object ifTrue, Object ifFalse)
|
||||
Object createCondExpr(Object condObj, Object ifTrue, Object ifFalse)
|
||||
{
|
||||
Node cond = (Node)condObj;
|
||||
int condStatus = isAlwaysDefinedBoolean(cond);
|
||||
@ -737,7 +758,8 @@ public class IRFactory {
|
||||
/**
|
||||
* Unary
|
||||
*/
|
||||
public Object createUnary(int nodeType, Object child) {
|
||||
Object createUnary(int nodeType, Object child)
|
||||
{
|
||||
Node childNode = (Node) child;
|
||||
int childType = childNode.getType();
|
||||
switch (nodeType) {
|
||||
@ -802,7 +824,7 @@ public class IRFactory {
|
||||
return new Node(nodeType, childNode);
|
||||
}
|
||||
|
||||
public Object createIncDec(int nodeType, boolean post, Object child)
|
||||
Object createIncDec(int nodeType, boolean post, Object child)
|
||||
{
|
||||
Node childNode = (Node)child;
|
||||
int childType = childNode.getType();
|
||||
@ -854,7 +876,7 @@ public class IRFactory {
|
||||
/**
|
||||
* Binary
|
||||
*/
|
||||
public Object createBinary(int nodeType, Object leftObj, Object rightObj)
|
||||
Object createBinary(int nodeType, Object leftObj, Object rightObj)
|
||||
{
|
||||
Node left = (Node)leftObj;
|
||||
Node right = (Node)rightObj;
|
||||
@ -1026,7 +1048,7 @@ public class IRFactory {
|
||||
return new Node(nodeType, left, right);
|
||||
}
|
||||
|
||||
public Object createAssignment(Object leftObj, Object rightObj)
|
||||
Object createAssignment(Object leftObj, Object rightObj)
|
||||
{
|
||||
Node left = (Node)leftObj;
|
||||
Node right = (Node)rightObj;
|
||||
@ -1064,7 +1086,7 @@ public class IRFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public Object createAssignmentOp(int assignOp, Object left, Object right)
|
||||
Object createAssignmentOp(int assignOp, Object left, Object right)
|
||||
{
|
||||
return createAssignmentOp(assignOp, (Node)left, (Node)right, false);
|
||||
}
|
||||
@ -1111,7 +1133,8 @@ public class IRFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public Node createUseLocal(Node localBlock) {
|
||||
Node createUseLocal(Node localBlock)
|
||||
{
|
||||
if (Token.LOCAL_BLOCK != localBlock.getType()) Kit.codeBug();
|
||||
Node result = new Node(Token.LOCAL_LOAD);
|
||||
result.putProp(Node.LOCAL_BLOCK_PROP, localBlock);
|
||||
@ -1140,7 +1163,8 @@ public class IRFactory {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean hasSideEffects(Node exprTree) {
|
||||
private static boolean hasSideEffects(Node exprTree)
|
||||
{
|
||||
switch (exprTree.getType()) {
|
||||
case Token.INC:
|
||||
case Token.DEC:
|
||||
@ -1162,8 +1186,6 @@ public class IRFactory {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Interpreter compiler;
|
||||
|
||||
// Only needed to call reportCurrentLineError.
|
||||
private TokenStream ts;
|
||||
|
||||
|
@ -110,42 +110,6 @@ public class Interpreter
|
||||
// Last icode
|
||||
END_ICODE = BASE_ICODE + 30;
|
||||
|
||||
final void setSyntaxErrorReporter(ErrorReporter syntaxErrorReporter,
|
||||
boolean fromEval)
|
||||
{
|
||||
this.syntaxErrorReporter = syntaxErrorReporter;
|
||||
this.fromEval = fromEval;
|
||||
this.syntaxErrorCount = 0;
|
||||
}
|
||||
|
||||
public void reportSyntaxError(boolean isError,
|
||||
String messageProperty, Object[] args,
|
||||
String sourceName, int lineno,
|
||||
String line, int lineOffset)
|
||||
{
|
||||
String message = Context.getMessage(messageProperty, args);
|
||||
if (isError) {
|
||||
++syntaxErrorCount;
|
||||
if (fromEval) {
|
||||
// We're probably in an eval. Need to throw an exception.
|
||||
throw ScriptRuntime.constructError(
|
||||
"SyntaxError", message, sourceName,
|
||||
lineno, line, lineOffset);
|
||||
} else {
|
||||
syntaxErrorReporter.error(message, sourceName,
|
||||
lineno, line, lineOffset);
|
||||
}
|
||||
} else {
|
||||
syntaxErrorReporter.warning(message, sourceName,
|
||||
lineno, line, lineOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public FunctionNode createFunctionNode(String name)
|
||||
{
|
||||
return new FunctionNode(name);
|
||||
}
|
||||
|
||||
public ScriptOrFnNode transform(Context cx, ScriptOrFnNode tree)
|
||||
{
|
||||
(new NodeTransformer(this)).transform(tree);
|
||||
@ -157,7 +121,8 @@ public class Interpreter
|
||||
Object securityDomain, String encodedSource)
|
||||
{
|
||||
scriptOrFn = tree;
|
||||
itsData = new InterpreterData(securityDomain, cx.getLanguageVersion());
|
||||
itsData = new InterpreterData(securityDomain,
|
||||
compilerEnv.getLanguageVersion());
|
||||
itsData.itsSourceFile = scriptOrFn.getSourceName();
|
||||
itsData.encodedSource = encodedSource;
|
||||
itsData.topLevel = true;
|
||||
@ -166,7 +131,7 @@ public class Interpreter
|
||||
return createFunction(cx, scope, itsData, false);
|
||||
} else {
|
||||
generateICodeFromTree(cx, scriptOrFn);
|
||||
itsData.itsFromEvalCode = fromEval;
|
||||
itsData.itsFromEvalCode = compilerEnv.isFromEval();
|
||||
return new InterpretedScript(itsData);
|
||||
}
|
||||
}
|
||||
@ -207,7 +172,7 @@ public class Interpreter
|
||||
itsData.itsNeedsActivation = true;
|
||||
}
|
||||
if (!theFunction.getIgnoreDynamicScope()) {
|
||||
if (cx.hasCompileFunctionsWithDynamicScope()) {
|
||||
if (compilerEnv.isUseDynamicScope()) {
|
||||
itsData.useDynamicScope = true;
|
||||
}
|
||||
}
|
||||
@ -295,6 +260,7 @@ public class Interpreter
|
||||
for (int i = 0; i != functionCount; i++) {
|
||||
FunctionNode def = scriptOrFn.getFunctionNode(i);
|
||||
Interpreter jsi = new Interpreter();
|
||||
jsi.compilerEnv = compilerEnv;
|
||||
jsi.scriptOrFn = def;
|
||||
jsi.itsData = new InterpreterData(itsData.securityDomain,
|
||||
itsData.languageVersion);
|
||||
@ -3316,11 +3282,9 @@ public class Interpreter
|
||||
return pc;
|
||||
}
|
||||
|
||||
private ErrorReporter syntaxErrorReporter;
|
||||
private boolean fromEval;
|
||||
int syntaxErrorCount;
|
||||
|
||||
private boolean itsInFunctionFlag;
|
||||
protected CompilerEnvirons compilerEnv;
|
||||
|
||||
private boolean itsInFunctionFlag;
|
||||
|
||||
private InterpreterData itsData;
|
||||
private ScriptOrFnNode scriptOrFn;
|
||||
|
@ -534,8 +534,8 @@ public class NodeTransformer
|
||||
{
|
||||
int lineno = stmt.getLineno();
|
||||
String sourceName = tree.getSourceName();
|
||||
compiler.reportSyntaxError(true, messageId, messageArgs,
|
||||
sourceName, lineno, null, 0);
|
||||
compiler.compilerEnv.reportSyntaxError(
|
||||
true, messageId, messageArgs, sourceName, lineno, null, 0);
|
||||
}
|
||||
|
||||
private ObjArray loops;
|
||||
|
@ -53,15 +53,10 @@ import java.io.IOException;
|
||||
|
||||
class Parser {
|
||||
|
||||
public Parser() { }
|
||||
|
||||
public void setLanguageVersion(int languageVersion) {
|
||||
this.languageVersion = languageVersion;
|
||||
}
|
||||
|
||||
public void setAllowMemberExprAsFunctionName(boolean flag) {
|
||||
this.allowMemberExprAsFunctionName = flag;
|
||||
}
|
||||
public Parser(CompilerEnvirons compilerEnv)
|
||||
{
|
||||
this.compilerEnv = compilerEnv;
|
||||
}
|
||||
|
||||
private void mustMatchToken(TokenStream ts, int toMatch, String messageId)
|
||||
throws IOException, ParserException
|
||||
@ -95,11 +90,10 @@ class Parser {
|
||||
* parse failure will result in a call to the current Context's
|
||||
* ErrorReporter.)
|
||||
*/
|
||||
public ScriptOrFnNode parse(TokenStream ts, IRFactory nf,
|
||||
Decompiler decompiler)
|
||||
public ScriptOrFnNode parse(TokenStream ts, Decompiler decompiler)
|
||||
throws IOException
|
||||
{
|
||||
this.nf = nf;
|
||||
this.nf = new IRFactory(ts);
|
||||
currentScriptOrFn = nf.createScript();
|
||||
this.decompiler = decompiler;
|
||||
int sourceStartOffset = decompiler.getCurrentOffset();
|
||||
@ -211,7 +205,7 @@ class Parser {
|
||||
if (ts.matchToken(Token.NAME)) {
|
||||
name = ts.getString();
|
||||
if (!ts.matchToken(Token.LP)) {
|
||||
if (allowMemberExprAsFunctionName) {
|
||||
if (compilerEnv.allowMemberExprAsFunctionName) {
|
||||
// Extension to ECMA: if 'function <name>' does not follow
|
||||
// by '(', assume <name> starts memberExpr
|
||||
decompiler.addName(name);
|
||||
@ -226,7 +220,7 @@ class Parser {
|
||||
name = "";
|
||||
} else {
|
||||
name = "";
|
||||
if (allowMemberExprAsFunctionName) {
|
||||
if (compilerEnv.allowMemberExprAsFunctionName) {
|
||||
// Note that memberExpr can not start with '(' like
|
||||
// in function (1+2).toString(), because 'function (' already
|
||||
// processed as anonymous function
|
||||
@ -385,7 +379,7 @@ class Parser {
|
||||
return;
|
||||
|
||||
case Token.FUNCTION:
|
||||
if (languageVersion < Context.VERSION_1_2) {
|
||||
if (compilerEnv.languageVersion < Context.VERSION_1_2) {
|
||||
/*
|
||||
* Checking against version < 1.2 and version >= 1.0
|
||||
* in the above line breaks old javascript, so we keep it
|
||||
@ -400,7 +394,7 @@ class Parser {
|
||||
private void checkWellTerminatedFunction(TokenStream ts)
|
||||
throws IOException, ParserException
|
||||
{
|
||||
if (languageVersion < Context.VERSION_1_2) {
|
||||
if (compilerEnv.languageVersion < Context.VERSION_1_2) {
|
||||
// See comments in checkWellTerminated
|
||||
return;
|
||||
}
|
||||
@ -1021,7 +1015,7 @@ class Parser {
|
||||
ts.getToken();
|
||||
int decompilerToken = tt;
|
||||
int parseToken = tt;
|
||||
if (languageVersion == Context.VERSION_1_2) {
|
||||
if (compilerEnv.languageVersion == Context.VERSION_1_2) {
|
||||
// JavaScript 1.2 uses shallow equality for == and != .
|
||||
// In addition, convert === and !== for decompiler into
|
||||
// == and != since the decompiler is supposed to show
|
||||
@ -1483,9 +1477,9 @@ class Parser {
|
||||
return null; // should never reach here
|
||||
}
|
||||
|
||||
private IRFactory nf;
|
||||
private int languageVersion = Context.VERSION_DEFAULT;
|
||||
private boolean allowMemberExprAsFunctionName = false;
|
||||
private CompilerEnvirons compilerEnv;
|
||||
|
||||
private IRFactory nf;
|
||||
|
||||
private boolean ok; // Did the parse encounter an error?
|
||||
|
||||
|
@ -75,12 +75,11 @@ public class TokenStream
|
||||
private final static int
|
||||
EOF_CHAR = -1;
|
||||
|
||||
public TokenStream(Context cx, Interpreter compiler,
|
||||
public TokenStream(CompilerEnvirons compilerEnv,
|
||||
Reader sourceReader, String sourceString,
|
||||
String sourceName, int lineno)
|
||||
{
|
||||
this.cx = cx;
|
||||
this.compiler = compiler;
|
||||
this.compilerEnv = compilerEnv;
|
||||
this.pushbackToken = Token.EOF;
|
||||
this.sourceName = sourceName;
|
||||
this.lineno = lineno;
|
||||
@ -296,17 +295,17 @@ public class TokenStream
|
||||
public final void reportCurrentLineError(String messageProperty,
|
||||
Object[] args)
|
||||
{
|
||||
compiler.reportSyntaxError(true, messageProperty, args,
|
||||
getSourceName(), getLineno(),
|
||||
getLine(), getOffset());
|
||||
compilerEnv.reportSyntaxError(true, messageProperty, args,
|
||||
getSourceName(), getLineno(),
|
||||
getLine(), getOffset());
|
||||
}
|
||||
|
||||
public final void reportCurrentLineWarning(String messageProperty,
|
||||
Object[] args)
|
||||
{
|
||||
compiler.reportSyntaxError(false, messageProperty, args,
|
||||
getSourceName(), getLineno(),
|
||||
getLine(), getOffset());
|
||||
compilerEnv.reportSyntaxError(false, messageProperty, args,
|
||||
getSourceName(), getLineno(),
|
||||
getLine(), getOffset());
|
||||
}
|
||||
|
||||
public final String getSourceName() { return sourceName; }
|
||||
@ -476,13 +475,10 @@ public class TokenStream
|
||||
if (result != Token.EOF) {
|
||||
if (result != Token.RESERVED) {
|
||||
return result;
|
||||
}
|
||||
else if (!cx.hasFeature(
|
||||
Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER))
|
||||
} else if (!compilerEnv.reservedKeywordAsIdentifier)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// If implementation permits to use future reserved
|
||||
// keywords in violation with the EcmaScript,
|
||||
// treat it as name but issue warning
|
||||
@ -1207,6 +1203,5 @@ public class TokenStream
|
||||
private int sourceEnd;
|
||||
private int sourceCursor;
|
||||
|
||||
private Interpreter compiler;
|
||||
Context cx;
|
||||
CompilerEnvirons compilerEnv;
|
||||
}
|
||||
|
@ -58,18 +58,9 @@ public class Codegen extends Interpreter {
|
||||
{
|
||||
}
|
||||
|
||||
public FunctionNode createFunctionNode(String name)
|
||||
{
|
||||
return new OptFunctionNode(name);
|
||||
}
|
||||
|
||||
public ScriptOrFnNode transform(Context cx, ScriptOrFnNode tree)
|
||||
{
|
||||
nameHelper = (OptClassNameHelper)ClassNameHelper.get(cx);
|
||||
itsUseDynamicScope = cx.hasCompileFunctionsWithDynamicScope();
|
||||
generateDebugInfo = (!cx.isGeneratingDebugChanged()
|
||||
|| cx.isGeneratingDebug());
|
||||
languageVersion = cx.getLanguageVersion();
|
||||
|
||||
initOptFunctions_r(tree);
|
||||
|
||||
@ -86,10 +77,10 @@ public class Codegen extends Interpreter {
|
||||
int functionCount = tree.getFunctionCount();
|
||||
for (int i = 0; i != functionCount; ++i) {
|
||||
OptFunctionNode ofn = OptFunctionNode.get(tree, i);
|
||||
if (ofn.getFunctionType()
|
||||
if (ofn.fnode.getFunctionType()
|
||||
== FunctionNode.FUNCTION_STATEMENT)
|
||||
{
|
||||
String name = ofn.getFunctionName();
|
||||
String name = ofn.fnode.getFunctionName();
|
||||
if (name.length() != 0) {
|
||||
if (possibleDirectCalls == null) {
|
||||
possibleDirectCalls = new Hashtable();
|
||||
@ -119,9 +110,9 @@ public class Codegen extends Interpreter {
|
||||
private static void initOptFunctions_r(ScriptOrFnNode scriptOrFn)
|
||||
{
|
||||
for (int i = 0, N = scriptOrFn.getFunctionCount(); i != N; ++i) {
|
||||
OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, i);
|
||||
ofn.init();
|
||||
initOptFunctions_r(ofn);
|
||||
FunctionNode fn = scriptOrFn.getFunctionNode(i);
|
||||
new OptFunctionNode(fn);
|
||||
initOptFunctions_r(fn);
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +262,7 @@ public class Codegen extends Interpreter {
|
||||
boolean hasFunctions = (scriptOrFnNodes.length > 1 || !hasScript);
|
||||
|
||||
String sourceFile = null;
|
||||
if (generateDebugInfo) {
|
||||
if (compilerEnv.isGenerateDebugInfo()) {
|
||||
sourceFile = scriptOrFnNodes[0].getSourceName();
|
||||
}
|
||||
|
||||
@ -309,6 +300,7 @@ public class Codegen extends Interpreter {
|
||||
BodyCodegen bodygen = new BodyCodegen();
|
||||
bodygen.cfw = cfw;
|
||||
bodygen.codegen = this;
|
||||
bodygen.compilerEnv = compilerEnv;
|
||||
bodygen.scriptOrFn = n;
|
||||
|
||||
bodygen.generateBodyCode();
|
||||
@ -351,12 +343,12 @@ public class Codegen extends Interpreter {
|
||||
return newInstance;
|
||||
}
|
||||
*/
|
||||
cfw.startMethod(getDirectCtorName(ofn),
|
||||
getBodyMethodSignature(ofn),
|
||||
cfw.startMethod(getDirectCtorName(ofn.fnode),
|
||||
getBodyMethodSignature(ofn.fnode),
|
||||
(short)(ClassFileWriter.ACC_STATIC
|
||||
| ClassFileWriter.ACC_PRIVATE));
|
||||
|
||||
int argCount = ofn.getParamCount();
|
||||
int argCount = ofn.fnode.getParamCount();
|
||||
int firstLocal = (4 + argCount * 3) + 1;
|
||||
|
||||
cfw.addALoad(0); // this
|
||||
@ -381,8 +373,8 @@ public class Codegen extends Interpreter {
|
||||
cfw.addALoad(4 + argCount * 3);
|
||||
cfw.addInvoke(ByteCode.INVOKESTATIC,
|
||||
mainClassName,
|
||||
getBodyMethodName(ofn),
|
||||
getBodyMethodSignature(ofn));
|
||||
getBodyMethodName(ofn.fnode),
|
||||
getBodyMethodSignature(ofn.fnode));
|
||||
int exitLabel = cfw.acquireLabel();
|
||||
cfw.add(ByteCode.DUP); // make a copy of direct call result
|
||||
cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Scriptable");
|
||||
@ -445,7 +437,7 @@ public class Codegen extends Interpreter {
|
||||
if (n.getType() == Token.FUNCTION) {
|
||||
OptFunctionNode ofn = OptFunctionNode.get(n);
|
||||
if (ofn.isTargetOfDirectCall()) {
|
||||
int pcount = ofn.getParamCount();
|
||||
int pcount = ofn.fnode.getParamCount();
|
||||
if (pcount != 0) {
|
||||
// loop invariant:
|
||||
// stack top == arguments array from addALoad4()
|
||||
@ -552,7 +544,7 @@ public class Codegen extends Interpreter {
|
||||
// NativeFunction.initScriptFunction(version, "", varNamesArray, 0)
|
||||
|
||||
cfw.addLoadThis();
|
||||
cfw.addPush(languageVersion);
|
||||
cfw.addPush(compilerEnv.getLanguageVersion());
|
||||
cfw.addPush(""); // Function name
|
||||
pushParamNamesArray(cfw, script);
|
||||
cfw.addPush(0); // No parameters, only varnames
|
||||
@ -634,10 +626,10 @@ public class Codegen extends Interpreter {
|
||||
|
||||
// Call NativeFunction.initScriptFunction
|
||||
cfw.addLoadThis();
|
||||
cfw.addPush(languageVersion);
|
||||
cfw.addPush(ofn.getFunctionName());
|
||||
pushParamNamesArray(cfw, ofn);
|
||||
cfw.addPush(ofn.getParamCount());
|
||||
cfw.addPush(compilerEnv.getLanguageVersion());
|
||||
cfw.addPush(ofn.fnode.getFunctionName());
|
||||
pushParamNamesArray(cfw, ofn.fnode);
|
||||
cfw.addPush(ofn.fnode.getParamCount());
|
||||
cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
|
||||
"org/mozilla/javascript/NativeFunction",
|
||||
"initScriptFunction",
|
||||
@ -651,10 +643,10 @@ public class Codegen extends Interpreter {
|
||||
"(Lorg/mozilla/javascript/Scriptable;)V");
|
||||
|
||||
// precompile all regexp literals
|
||||
int regexpCount = ofn.getRegexpCount();
|
||||
int regexpCount = ofn.fnode.getRegexpCount();
|
||||
if (regexpCount != 0) {
|
||||
cfw.addLoadThis();
|
||||
pushRegExpArray(cfw, ofn, CONTEXT_ARG, SCOPE_ARG);
|
||||
pushRegExpArray(cfw, ofn.fnode, CONTEXT_ARG, SCOPE_ARG);
|
||||
cfw.add(ByteCode.PUTFIELD, mainClassName,
|
||||
REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE);
|
||||
}
|
||||
@ -1007,7 +999,7 @@ public class Codegen extends Interpreter {
|
||||
if (n.getType() == Token.FUNCTION) {
|
||||
OptFunctionNode ofn = OptFunctionNode.get(n);
|
||||
if (ofn.isTargetOfDirectCall()) {
|
||||
int pCount = ofn.getParamCount();
|
||||
int pCount = ofn.fnode.getParamCount();
|
||||
for (int i = 0; i != pCount; i++) {
|
||||
sb.append("Ljava/lang/Object;D");
|
||||
}
|
||||
@ -1019,7 +1011,7 @@ public class Codegen extends Interpreter {
|
||||
|
||||
String getFunctionInitMethodName(OptFunctionNode ofn)
|
||||
{
|
||||
return "_i"+getIndex(ofn);
|
||||
return "_i"+getIndex(ofn.fnode);
|
||||
}
|
||||
|
||||
String getCompiledRegexpName(ScriptOrFnNode n, int regexpIndex)
|
||||
@ -1067,7 +1059,6 @@ public class Codegen extends Interpreter {
|
||||
private byte[] mainClassBytes;
|
||||
|
||||
boolean itsUseDynamicScope;
|
||||
boolean generateDebugInfo;
|
||||
int languageVersion;
|
||||
|
||||
private double[] itsConstantList;
|
||||
@ -1114,7 +1105,8 @@ class BodyCodegen
|
||||
inDirectCallFunction = (fnCurrent == null) ? false
|
||||
: fnCurrent.isTargetOfDirectCall();
|
||||
|
||||
hasVarsInRegs = (fnCurrent != null && !fnCurrent.requiresActivation());
|
||||
hasVarsInRegs = (fnCurrent != null
|
||||
&& !fnCurrent.fnode.requiresActivation());
|
||||
|
||||
locals = new boolean[MAX_LOCALS];
|
||||
|
||||
@ -1172,8 +1164,8 @@ class BodyCodegen
|
||||
}
|
||||
|
||||
if (fnCurrent != null && directParameterCount == -1
|
||||
&& (!codegen.itsUseDynamicScope
|
||||
|| fnCurrent.getIgnoreDynamicScope()))
|
||||
&& (!compilerEnv.isUseDynamicScope()
|
||||
|| fnCurrent.fnode.getIgnoreDynamicScope()))
|
||||
{
|
||||
// Unless we're either in a direct call or using dynamic scope,
|
||||
// use the enclosing scope of the function as our variable object.
|
||||
@ -1203,7 +1195,7 @@ class BodyCodegen
|
||||
}
|
||||
}
|
||||
|
||||
if (fnCurrent != null && fnCurrent.getCheckThis()) {
|
||||
if (fnCurrent != null && fnCurrent.fnode.getCheckThis()) {
|
||||
// Nested functions must check their 'this' value to
|
||||
// insure it is not an activation object:
|
||||
// see 10.1.6 Activation Object
|
||||
@ -1327,13 +1319,15 @@ class BodyCodegen
|
||||
int functionCount = scriptOrFn.getFunctionCount();
|
||||
for (int i = 0; i != functionCount; i++) {
|
||||
OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, i);
|
||||
if (ofn.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) {
|
||||
if (ofn.fnode.getFunctionType()
|
||||
== FunctionNode.FUNCTION_STATEMENT)
|
||||
{
|
||||
visitFunction(ofn, FunctionNode.FUNCTION_STATEMENT);
|
||||
}
|
||||
}
|
||||
|
||||
// default is to generate debug info
|
||||
if (codegen.generateDebugInfo) {
|
||||
if (compilerEnv.isGenerateDebugInfo()) {
|
||||
OptLocalVariable lv = new OptLocalVariable(debugVariableName,
|
||||
false);
|
||||
lv.assignJRegister(variableObjectLocal);
|
||||
@ -1440,7 +1434,7 @@ class BodyCodegen
|
||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||
OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn,
|
||||
fnIndex);
|
||||
int t = ofn.getFunctionType();
|
||||
int t = ofn.fnode.getFunctionType();
|
||||
if (t != FunctionNode.FUNCTION_STATEMENT) {
|
||||
visitFunction(ofn, t);
|
||||
}
|
||||
@ -2029,7 +2023,7 @@ class BodyCodegen
|
||||
|
||||
private void visitFunction(OptFunctionNode ofn, int functionType)
|
||||
{
|
||||
int fnIndex = codegen.getIndex(ofn);
|
||||
int fnIndex = codegen.getIndex(ofn.fnode);
|
||||
cfw.add(ByteCode.NEW, codegen.mainClassName);
|
||||
// Call function constructor
|
||||
cfw.add(ByteCode.DUP);
|
||||
@ -2223,7 +2217,7 @@ class BodyCodegen
|
||||
cfw.add(ByteCode.SWAP);
|
||||
cfw.add(ByteCode.POP);
|
||||
|
||||
if (!codegen.itsUseDynamicScope) {
|
||||
if (!compilerEnv.isUseDynamicScope()) {
|
||||
cfw.add(ByteCode.DUP);
|
||||
cfw.addInvoke(ByteCode.INVOKEINTERFACE,
|
||||
"org/mozilla/javascript/Scriptable",
|
||||
@ -2286,9 +2280,9 @@ class BodyCodegen
|
||||
cfw.addInvoke(ByteCode.INVOKESTATIC,
|
||||
codegen.mainClassName,
|
||||
(type == Token.NEW)
|
||||
? codegen.getDirectCtorName(target)
|
||||
: codegen.getBodyMethodName(target),
|
||||
codegen.getBodyMethodSignature(target));
|
||||
? codegen.getDirectCtorName(target.fnode)
|
||||
: codegen.getBodyMethodName(target.fnode),
|
||||
codegen.getBodyMethodSignature(target.fnode));
|
||||
|
||||
int beyond = cfw.acquireLabel();
|
||||
cfw.add(ByteCode.GOTO, beyond);
|
||||
@ -3887,6 +3881,7 @@ class BodyCodegen
|
||||
|
||||
ClassFileWriter cfw;
|
||||
Codegen codegen;
|
||||
CompilerEnvirons compilerEnv;
|
||||
ScriptOrFnNode scriptOrFn;
|
||||
|
||||
private OptFunctionNode fnCurrent;
|
||||
|
@ -39,81 +39,91 @@ package org.mozilla.javascript.optimizer;
|
||||
import org.mozilla.javascript.*;
|
||||
import java.util.*;
|
||||
|
||||
final class OptFunctionNode extends FunctionNode {
|
||||
|
||||
OptFunctionNode(String name) {
|
||||
super(name);
|
||||
final class OptFunctionNode
|
||||
{
|
||||
OptFunctionNode(FunctionNode fnode)
|
||||
{
|
||||
this.fnode = fnode;
|
||||
int N = fnode.getParamAndVarCount();
|
||||
int parameterCount = fnode.getParamCount();
|
||||
optVars = new OptLocalVariable[N];
|
||||
for (int i = 0; i != N; ++i) {
|
||||
String name = fnode.getParamOrVarName(i);
|
||||
optVars[i] = new OptLocalVariable(name, i < parameterCount);
|
||||
}
|
||||
fnode.setCompilerData(this);
|
||||
}
|
||||
|
||||
static OptFunctionNode get(ScriptOrFnNode scriptOrFn, int i)
|
||||
{
|
||||
return (OptFunctionNode)scriptOrFn.getFunctionNode(i);
|
||||
FunctionNode fnode = scriptOrFn.getFunctionNode(i);
|
||||
return (OptFunctionNode)fnode.getCompilerData();
|
||||
}
|
||||
|
||||
static OptFunctionNode get(ScriptOrFnNode scriptOrFn)
|
||||
{
|
||||
return (OptFunctionNode)scriptOrFn;
|
||||
return (OptFunctionNode)scriptOrFn.getCompilerData();
|
||||
}
|
||||
|
||||
void init()
|
||||
boolean isTargetOfDirectCall()
|
||||
{
|
||||
int N = getParamAndVarCount();
|
||||
int parameterCount = getParamCount();
|
||||
optVars = new OptLocalVariable[N];
|
||||
for (int i = 0; i != N; ++i) {
|
||||
String name = getParamOrVarName(i);
|
||||
optVars[i] = new OptLocalVariable(name, i < parameterCount);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isTargetOfDirectCall() {
|
||||
return directTargetIndex >= 0;
|
||||
}
|
||||
|
||||
int getDirectTargetIndex() {
|
||||
int getDirectTargetIndex()
|
||||
{
|
||||
return directTargetIndex;
|
||||
}
|
||||
|
||||
void setDirectTargetIndex(int directTargetIndex) {
|
||||
void setDirectTargetIndex(int directTargetIndex)
|
||||
{
|
||||
// One time action
|
||||
if (directTargetIndex < 0 || this.directTargetIndex >= 0)
|
||||
Kit.codeBug();
|
||||
this.directTargetIndex = directTargetIndex;
|
||||
}
|
||||
|
||||
void setParameterNumberContext(boolean b) {
|
||||
void setParameterNumberContext(boolean b)
|
||||
{
|
||||
itsParameterNumberContext = b;
|
||||
}
|
||||
|
||||
boolean getParameterNumberContext() {
|
||||
boolean getParameterNumberContext()
|
||||
{
|
||||
return itsParameterNumberContext;
|
||||
}
|
||||
|
||||
int getVarCount() {
|
||||
int getVarCount()
|
||||
{
|
||||
return optVars.length;
|
||||
}
|
||||
|
||||
OptLocalVariable getVar(int index) {
|
||||
OptLocalVariable getVar(int index)
|
||||
{
|
||||
return optVars[index];
|
||||
}
|
||||
|
||||
OptLocalVariable getVar(String name) {
|
||||
int index = getParamOrVarIndex(name);
|
||||
OptLocalVariable getVar(String name)
|
||||
{
|
||||
int index = fnode.getParamOrVarIndex(name);
|
||||
if (index < 0) { return null; }
|
||||
return optVars[index];
|
||||
}
|
||||
|
||||
void establishVarsIndices() {
|
||||
void establishVarsIndices()
|
||||
{
|
||||
int N = optVars.length;
|
||||
for (int i = 0; i != N; i++) {
|
||||
optVars[i].setIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
OptLocalVariable[] getVarsArray() {
|
||||
OptLocalVariable[] getVarsArray()
|
||||
{
|
||||
return optVars;
|
||||
}
|
||||
|
||||
FunctionNode fnode;
|
||||
private OptLocalVariable[] optVars;
|
||||
private int directTargetIndex = -1;
|
||||
private boolean itsParameterNumberContext;
|
||||
|
@ -176,18 +176,20 @@ class OptTransformer extends NodeTransformer {
|
||||
targetName = left.getFirstChild().getNext().getString();
|
||||
}
|
||||
if (targetName != null) {
|
||||
OptFunctionNode fn;
|
||||
fn = (OptFunctionNode)possibleDirectCalls.get(targetName);
|
||||
if (fn != null && argCount == fn.getParamCount()) {
|
||||
OptFunctionNode ofn;
|
||||
ofn = (OptFunctionNode)possibleDirectCalls.get(targetName);
|
||||
if (ofn != null
|
||||
&& argCount == ofn.fnode.getParamCount())
|
||||
{
|
||||
// Refuse to directCall any function with more
|
||||
// than 32 parameters - prevent code explosion
|
||||
// for wacky test cases
|
||||
if (argCount <= 32) {
|
||||
node.putProp(Node.DIRECTCALL_PROP, fn);
|
||||
if (!fn.isTargetOfDirectCall()) {
|
||||
node.putProp(Node.DIRECTCALL_PROP, ofn);
|
||||
if (!ofn.isTargetOfDirectCall()) {
|
||||
int index = directCallTargets.size();
|
||||
directCallTargets.add(fn);
|
||||
fn.setDirectTargetIndex(index);
|
||||
directCallTargets.add(ofn);
|
||||
ofn.setDirectTargetIndex(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,12 +72,12 @@ class Optimizer
|
||||
|
||||
private void optimizeFunction(OptFunctionNode theFunction)
|
||||
{
|
||||
if (theFunction.requiresActivation()) return;
|
||||
if (theFunction.fnode.requiresActivation()) return;
|
||||
|
||||
inDirectCallFunction = theFunction.isTargetOfDirectCall();
|
||||
|
||||
ObjArray statementsArray = new ObjArray();
|
||||
buildStatementList_r(theFunction, statementsArray);
|
||||
buildStatementList_r(theFunction.fnode, statementsArray);
|
||||
Node[] theStatementNodes = new Node[statementsArray.size()];
|
||||
statementsArray.toArray(theStatementNodes);
|
||||
|
||||
@ -101,7 +101,7 @@ class Optimizer
|
||||
typeFlow(theFunction, theBlocks);
|
||||
findSinglyTypedVars(theFunction, theBlocks);
|
||||
localCSE(theBlocks, theFunction);
|
||||
if (!theFunction.requiresActivation()) {
|
||||
if (!theFunction.fnode.requiresActivation()) {
|
||||
/*
|
||||
* Now that we know which local vars are in fact always
|
||||
* Numbers, we re-write the tree to take advantage of
|
||||
@ -634,8 +634,8 @@ class Optimizer
|
||||
}
|
||||
case Token.CALL :
|
||||
{
|
||||
FunctionNode target
|
||||
= (FunctionNode)n.getProp(Node.DIRECTCALL_PROP);
|
||||
OptFunctionNode target
|
||||
= (OptFunctionNode)n.getProp(Node.DIRECTCALL_PROP);
|
||||
if (target != null) {
|
||||
/*
|
||||
we leave each child as a Number if it can be. The codegen will
|
||||
|
Loading…
Reference in New Issue
Block a user