1. Separating compilation into bytecode and wrapping it into Script and Function instances both for the interpreter and class compiler. It is possible now to serialize the compiled interpreter bytecode and then wrap it in proper security context.

The change required to move security domain information form InterpreterData to its Scriptable wrappers. To simplify it and to make the interpreted functions to behave exactly as class compiled I merged InterpretedScript into InterpretedFunction which allowed to remove many casts and discrepancies when handling script and function instances.

2. Explicitly passing Interpreter instances to Context.compile... functions to avoid changing optimization level even temporarily.

3. Uniform initialization of class compiled and interpreted functions and scripts to avoid code duplication.
This commit is contained in:
igor%mir2.org 2004-08-10 16:06:56 +00:00
Родитель 8b7a521e30
Коммит e4d1c4896b
10 изменённых файлов: 329 добавлений и 323 удалений

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

@ -487,26 +487,18 @@ public class BaseFunction extends IdScriptableObject implements Function
linep[0] = 1;
}
String sourceName = ScriptRuntime.
String sourceURI = ScriptRuntime.
makeUrlForGeneratedScript(false, filename, linep[0]);
Scriptable global = ScriptableObject.getTopLevelScope(scope);
// Compile the function with opt level of -1 to force interpreter
ErrorReporter reporter;
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
// Compile with explicit interpreter instance to force interpreter
// mode.
int savedLevel = cx.optimizationLevel;
cx.optimizationLevel = -1;
NativeFunction fn;
try {
fn = (NativeFunction) cx.compileFunction(global, source,
sourceName, 1,
null);
}
finally { cx.optimizationLevel = savedLevel; }
ScriptRuntime.setFunctionProtoAndParent(global, fn);
return fn;
return cx.compileFunction(global, source, new Interpreter(), reporter,
sourceURI, 1, null);
}
protected int findPrototypeId(String s)

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

@ -1253,8 +1253,8 @@ public class Context
throw new IllegalArgumentException(
"Line number can not be negative:"+lineno);
}
return (Script) compile(null, in, null, sourceName, lineno,
securityDomain, false, null);
return (Script) compileImpl(null, in, null, sourceName, lineno,
securityDomain, false, null, null);
}
/**
@ -1280,18 +1280,20 @@ public class Context
throw new IllegalArgumentException(
"Line number can not be negative:"+lineno);
}
return compileString(source, null, sourceName, lineno, securityDomain);
return compileString(source, null, null, sourceName, lineno,
securityDomain);
}
final Script compileString(String source,
Interpreter compiler,
ErrorReporter compilationErrorReporter,
String sourceName, int lineno,
Object securityDomain)
{
try {
return (Script) compile(null, null, source, sourceName, lineno,
return (Script) compileImpl(null, null, source, sourceName, lineno,
securityDomain, false,
compilationErrorReporter);
compiler, compilationErrorReporter);
} catch (IOException ex) {
// Should not happen when dealing with source as string
throw new RuntimeException();
@ -1318,10 +1320,21 @@ public class Context
public final Function compileFunction(Scriptable scope, String source,
String sourceName, int lineno,
Object securityDomain)
{
return compileFunction(scope, source, null, null, sourceName, lineno,
securityDomain);
}
final Function compileFunction(Scriptable scope, String source,
Interpreter compiler,
ErrorReporter compilationErrorReporter,
String sourceName, int lineno,
Object securityDomain)
{
try {
return (Function) compile(scope, null, source, sourceName, lineno,
securityDomain, true, null);
return (Function) compileImpl(scope, null, source, sourceName,
lineno, securityDomain, true,
compiler, compilationErrorReporter);
}
catch (IOException ioe) {
// Should never happen because we just made the reader
@ -2287,10 +2300,11 @@ public class Context
return formatter.format(arguments);
}
private Object compile(Scriptable scope,
private Object compileImpl(Scriptable scope,
Reader sourceReader, String sourceString,
String sourceName, int lineno,
Object securityDomain, boolean returnFunction,
Interpreter compiler,
ErrorReporter compilationErrorReporter)
throws IOException
{
@ -2337,22 +2351,46 @@ public class Context
}
}
Interpreter compiler = createCompiler();
if (compiler == null) {
compiler = createCompiler();
}
String encodedSource = p.getEncodedSource();
Object result = compiler.compile(scope, compilerEnv,
Object bytecode = compiler.compile(compilerEnv,
tree, encodedSource,
returnFunction,
securityDomain);
returnFunction);
if (debugger != null) {
if (sourceString == null) Kit.codeBug();
compiler.notifyDebuggerCompilationDone(this, result,
sourceString);
if (bytecode instanceof DebuggableScript) {
DebuggableScript dscript = (DebuggableScript)bytecode;
notifyDebugger_r(this, dscript, sourceString);
} else {
throw new RuntimeException("NOT SUPPORTED");
}
}
Object result;
if (returnFunction) {
result = compiler.createFunctionObject(this, scope, bytecode,
securityDomain);
} else {
result = compiler.createScriptObject(bytecode, securityDomain);
}
return result;
}
private static void notifyDebugger_r(Context cx, DebuggableScript dscript,
String debugSource)
{
cx.debugger.handleCompilationDone(cx, dscript, debugSource);
for (int i = 0; i != dscript.getFunctionCount(); ++i) {
notifyDebugger_r(cx, dscript.getFunction(i), debugSource);
}
}
private static Class codegenClass = Kit.classOrNull(
"org.mozilla.javascript.optimizer.Codegen");
@ -2562,7 +2600,7 @@ public class Context
private boolean generatingDebugChanged;
private boolean generatingSource=true;
private boolean compileFunctionsWithDynamicScopeFlag;
int optimizationLevel;
private int optimizationLevel;
private WrapFactory wrapFactory;
Debugger debugger;
private Object debuggerData;

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

@ -19,6 +19,7 @@
* Rights Reserved.
*
* Contributor(s):
* Igor Bukanov
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
@ -35,40 +36,126 @@
package org.mozilla.javascript;
import java.io.Serializable;
final class InterpretedFunction extends NativeFunction
implements Serializable
final class InterpretedFunction extends NativeFunction implements Script
{
InterpreterData idata;
SecurityController securityController;
Object securityDomain;
Scriptable[] functionRegExps;
boolean evalScriptFlag; // true if script corresponds to eval() code
static final long serialVersionUID = -6235150451107527319L;
InterpretedFunction(InterpreterData theData)
private InterpretedFunction(InterpreterData idata,
Object staticSecurityDomain)
{
itsData = theData;
initScriptFunction(itsData.languageVersion, itsData.itsName,
itsData.argNames, itsData.argCount);
this.idata = idata;
// Always get Context from the current thread to
// avoid security breaches via passing mangled Context instances
// with bogus SecurityController
Context cx = Context.getContext();
SecurityController sc = cx.getSecurityController();
Object dynamicDomain;
if (sc != null) {
dynamicDomain = sc.getDynamicSecurityDomain(staticSecurityDomain);
} else {
if (staticSecurityDomain != null) {
throw new IllegalArgumentException();
}
dynamicDomain = null;
}
this.securityController = sc;
this.securityDomain = dynamicDomain;
}
private InterpretedFunction(InterpretedFunction parent, int index)
{
this.idata = parent.idata.itsNestedFunctions[index];
this.securityController = parent.securityController;
this.securityDomain = parent.securityDomain;
}
/**
* Create script from compiled bytecode.
*/
static InterpretedFunction createScript(InterpreterData idata,
Object staticSecurityDomain)
{
InterpretedFunction f;
f = new InterpretedFunction(idata, staticSecurityDomain);
f.initScriptObject(idata.languageVersion, idata.argNames);
return f;
}
/**
* Create function compiled from Function(...) constructor.
*/
static InterpretedFunction createFunction(Context cx,Scriptable scope,
InterpreterData idata,
Object staticSecurityDomain)
{
InterpretedFunction f;
f = new InterpretedFunction(idata, staticSecurityDomain);
f.initInterpretedFunction(cx, scope);
return f;
}
/**
* Create function embedded in script or another function.
*/
static InterpretedFunction createFunction(Context cx, Scriptable scope,
InterpretedFunction parent,
int index)
{
InterpretedFunction f = new InterpretedFunction(parent, index);
f.initInterpretedFunction(cx, scope);
return f;
}
Scriptable[] createRegExpWraps(Context cx, Scriptable scope)
{
if (idata.itsRegExpLiterals == null) Kit.codeBug();
RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx);
int N = idata.itsRegExpLiterals.length;
Scriptable[] array = new Scriptable[N];
for (int i = 0; i != N; ++i) {
array[i] = rep.wrapRegExp(cx, scope, idata.itsRegExpLiterals[i]);
}
return array;
}
private void initInterpretedFunction(Context cx, Scriptable scope)
{
initScriptFunction(cx, scope, idata.languageVersion, idata.itsName,
idata.argNames, idata.argCount);
if (idata.itsRegExpLiterals != null) {
functionRegExps = createRegExpWraps(cx, scope);
}
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (!ScriptRuntime.hasTopCall(cx)) {
return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
}
return Interpreter.interpret(cx, scope, thisObj,
args, null, 0, args.length,
this, itsData);
return Interpreter.interpret(cx, scope, thisObj, args, null,
0, args.length, this);
}
public Object exec(Context cx, Scriptable scope)
{
if (idata.itsFunctionType != 0) {
// Can only be applied to scripts
throw new IllegalStateException();
}
return call(cx, scope, scope, ScriptRuntime.emptyArgs);
}
public String getEncodedSource()
{
return Interpreter.getEncodedSource(itsData);
return Interpreter.getEncodedSource(idata);
}
InterpreterData itsData;
boolean itsUseDynamicScope;
Scriptable[] itsRegExps;
}

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

@ -1,75 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express 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):
* 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.*;
final class InterpretedScript extends NativeFunction implements Script
{
InterpretedScript(InterpreterData theData)
{
itsData = theData;
initScriptFunction(itsData.languageVersion, "",
itsData.argNames, itsData.argCount);
}
public Object exec(Context cx, Scriptable scope)
throws JavaScriptException
{
return call(cx, scope, scope, ScriptRuntime.emptyArgs);
}
public Object call(Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
throws JavaScriptException
{
if (!ScriptRuntime.hasTopCall(cx)) {
return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
}
return Interpreter.interpret(cx, scope, thisObj,
args, null, 0, args.length,
this, itsData);
}
public String getEncodedSource()
{
return Interpreter.getEncodedSource(itsData);
}
InterpreterData itsData;
}

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

@ -257,12 +257,10 @@ public class Interpreter
return validIcode(bytecode) || validTokenCode(bytecode);
}
public Object compile(Scriptable scope,
CompilerEnvirons compilerEnv,
public Object compile(CompilerEnvirons compilerEnv,
ScriptOrFnNode tree,
String encodedSource,
boolean returnFunction,
Object staticSecurityDomain)
boolean returnFunction)
{
this.compilerEnv = compilerEnv;
new NodeTransformer().transform(tree);
@ -275,56 +273,36 @@ public class Interpreter
tree = tree.getFunctionNode(0);
}
Context cx = Context.getContext();
SecurityController sc = cx.getSecurityController();
Object dynamicDomain;
if (sc != null) {
dynamicDomain = sc.getDynamicSecurityDomain(staticSecurityDomain);
} else {
if (staticSecurityDomain != null) {
throw new IllegalArgumentException();
}
dynamicDomain = null;
}
scriptOrFn = tree;
itsData = new InterpreterData(sc, dynamicDomain,
compilerEnv.getLanguageVersion(),
itsData = new InterpreterData(compilerEnv.getLanguageVersion(),
scriptOrFn.getSourceName(),
encodedSource);
itsData.topLevel = true;
if (returnFunction) {
generateFunctionICode();
return createFunction(cx, scope, itsData, false);
} else {
generateICodeFromTree(scriptOrFn);
return new InterpretedScript(itsData);
}
}
public void notifyDebuggerCompilationDone(Context cx,
Object scriptOrFunction,
String debugSource)
{
InterpreterData idata;
if (scriptOrFunction instanceof InterpretedScript) {
idata = ((InterpretedScript)scriptOrFunction).itsData;
} else {
idata = ((InterpretedFunction)scriptOrFunction).itsData;
}
notifyDebugger_r(cx, idata, debugSource);
return itsData;
}
private static void notifyDebugger_r(Context cx, InterpreterData idata,
String debugSource)
public Script createScriptObject(Object bytecode,
Object staticSecurityDomain)
{
cx.debugger.handleCompilationDone(cx, idata, debugSource);
if (idata.itsNestedFunctions != null) {
for (int i = 0; i != idata.itsNestedFunctions.length; ++i) {
notifyDebugger_r(cx, idata.itsNestedFunctions[i], debugSource);
}
InterpreterData idata = (InterpreterData)bytecode;
return InterpretedFunction.createScript(itsData,
staticSecurityDomain);
}
public Function createFunctionObject(Context cx, Scriptable scope,
Object bytecode,
Object staticSecurityDomain)
{
InterpreterData idata = (InterpreterData)bytecode;
return InterpretedFunction.createFunction(cx, scope, itsData,
staticSecurityDomain);
}
private void generateFunctionICode()
@ -1953,56 +1931,38 @@ public class Interpreter
idata.encodedSourceEnd);
}
private static Scriptable[] wrapRegExps(Context cx, Scriptable scope,
InterpreterData idata)
private static void initFunction(Context cx, Scriptable scope,
InterpretedFunction parent, int index)
{
if (idata.itsRegExpLiterals == null) Kit.codeBug();
RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx);
int N = idata.itsRegExpLiterals.length;
Scriptable[] array = new Scriptable[N];
for (int i = 0; i != N; ++i) {
array[i] = rep.wrapRegExp(cx, scope, idata.itsRegExpLiterals[i]);
}
return array;
}
private static InterpretedFunction createFunction(Context cx,
Scriptable scope,
InterpreterData idata,
boolean fromEvalCode)
{
InterpretedFunction fn = new InterpretedFunction(idata);
if (idata.itsRegExpLiterals != null) {
fn.itsRegExps = wrapRegExps(cx, scope, idata);
}
ScriptRuntime.initFunction(cx, scope, fn, idata.itsFunctionType,
fromEvalCode);
return fn;
InterpretedFunction fn;
fn = InterpretedFunction.createFunction(cx, scope, parent, index);
ScriptRuntime.initFunction(cx, scope, fn, fn.idata.itsFunctionType,
parent.evalScriptFlag);
}
static Object interpret(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args, double[] argsDbl,
int argShift, int argCount,
NativeFunction fnOrScript,
InterpreterData idata)
throws JavaScriptException
InterpretedFunction fnOrScript)
{
if (cx.interpreterSecurityDomain != idata.securityDomain) {
if (cx.interpreterSecurityDomain != fnOrScript.securityDomain) {
if (argsDbl != null) {
args = getArgsArray(args, argsDbl, argShift, argCount);
}
SecurityController sc = idata.securityController;
SecurityController sc = fnOrScript.securityController;
Object savedDomain = cx.interpreterSecurityDomain;
cx.interpreterSecurityDomain = idata.securityDomain;
cx.interpreterSecurityDomain = fnOrScript.securityDomain;
try {
return sc.callWithDomain(idata.securityDomain, cx, fnOrScript,
scope, thisObj, args);
return fnOrScript.securityController.callWithDomain(
fnOrScript.securityDomain, cx, fnOrScript, scope,
thisObj, args);
} finally {
cx.interpreterSecurityDomain = savedDomain;
}
}
InterpreterData idata = fnOrScript.idata;
final Object DBL_MRK = Interpreter.DBL_MRK;
final Scriptable undefined = Undefined.instance;
@ -2055,7 +2015,6 @@ public class Interpreter
}
if (idata.itsFunctionType != 0) {
InterpretedFunction f = (InterpretedFunction)fnOrScript;
if (!idata.useDynamicScope) {
scope = fnOrScript.getParentScope();
}
@ -2071,7 +2030,7 @@ public class Interpreter
}
} else {
ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope,
idata.itsFromEvalCode);
fnOrScript.evalScriptFlag);
}
if (idata.itsNestedFunctions != null) {
@ -2080,21 +2039,29 @@ public class Interpreter
for (int i = 0; i < idata.itsNestedFunctions.length; i++) {
InterpreterData fdata = idata.itsNestedFunctions[i];
if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) {
createFunction(cx, scope, fdata, idata.itsFromEvalCode);
initFunction(cx, scope, fnOrScript, i);
}
}
}
Scriptable[] scriptRegExps = null;
if (idata.itsRegExpLiterals != null) {
// Wrapped regexps for functions are stored in InterpretedFunction
// but for script which should not contain references to scope
// the regexps re-wrapped during each script execution
Scriptable[] scriptRegExps = null;
if (idata.itsFunctionType != 0) {
scriptRegExps = fnOrScript.functionRegExps;
} else {
scriptRegExps = fnOrScript.createRegExpWraps(cx, scope);
}
}
if (debuggerFrame != null) {
debuggerFrame.onEnter(cx, scope, thisObj, args);
}
InterpreterData savedData = cx.interpreterData;
int savedLineIndex = cx.interpreterLineIndex;
cx.interpreterData = idata;
cx.interpreterLineIndex = idata.firstLinePC;
@ -2638,9 +2605,8 @@ switch (op) {
// Inlining of InterpretedFunction.call not to create
// argument array
InterpretedFunction ifun = (InterpretedFunction)fun;
stack[stackTop] = interpret(cx, funScope, funThisObj,
stack, sDbl, calleeArgShft, indexReg,
ifun, ifun.itsData);
stack[stackTop] = interpret(cx, funScope, funThisObj, stack, sDbl,
calleeArgShft, indexReg, ifun);
} else {
Object[] outArgs = getArgsArray(stack, sDbl, calleeArgShft,
indexReg);
@ -2685,9 +2651,8 @@ switch (op) {
// argument array
InterpretedFunction f = (InterpretedFunction)lhs;
Scriptable newInstance = f.createObject(cx, scope);
Object callResult = interpret(cx, scope, newInstance,
stack, sDbl, calleeArgShft, indexReg,
f, f.itsData);
Object callResult = interpret(cx, scope, newInstance, stack, sDbl,
calleeArgShft, indexReg, f);
if (callResult instanceof Scriptable && callResult != undefined) {
stack[stackTop] = callResult;
} else {
@ -2883,30 +2848,17 @@ switch (op) {
case Icode_SCOPE :
stack[++stackTop] = scope;
continue Loop;
case Icode_CLOSURE_EXPR : {
InterpreterData closureData = idata.itsNestedFunctions[indexReg];
stack[++stackTop] = createFunction(cx, scope, closureData,
idata.itsFromEvalCode);
case Icode_CLOSURE_EXPR :
stack[++stackTop] = InterpretedFunction.createFunction(cx, scope,
fnOrScript,
indexReg);
continue Loop;
}
case Icode_CLOSURE_STMT : {
InterpreterData closureData = idata.itsNestedFunctions[indexReg];
createFunction(cx, scope, closureData, idata.itsFromEvalCode);
case Icode_CLOSURE_STMT :
initFunction(cx, scope, fnOrScript, indexReg);
continue Loop;
}
case Token.REGEXP : {
Scriptable regexp;
if (idata.itsFunctionType != 0) {
regexp = ((InterpretedFunction)fnOrScript).itsRegExps[indexReg];
} else {
if (scriptRegExps == null) {
scriptRegExps = wrapRegExps(cx, scope, idata);
}
regexp = scriptRegExps[indexReg];
}
stack[++stackTop] = regexp;
case Token.REGEXP :
stack[++stackTop] = scriptRegExps[indexReg];
continue Loop;
}
case Icode_LITERAL_NEW :
// indexReg: number of values in the literal
++stackTop;
@ -3101,6 +3053,7 @@ switch (op) {
} // end of interpreter loop
cx.interpreterData = savedData;
cx.interpreterLineIndex = savedLineIndex;
if (debuggerFrame != null) {
if (javaException != null) {

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

@ -49,13 +49,9 @@ final class InterpreterData implements Serializable, DebuggableScript
static final int INITIAL_STRINGTABLE_SIZE = 64;
static final int INITIAL_NUMBERTABLE_SIZE = 64;
InterpreterData(SecurityController securityController,
Object securityDomain,
int languageVersion,
InterpreterData(int languageVersion,
String sourceFile, String encodedSource)
{
this.securityController = securityController;
this.securityDomain = securityDomain;
this.languageVersion = languageVersion;
this.itsSourceFile = sourceFile;
this.encodedSource = encodedSource;
@ -66,8 +62,6 @@ final class InterpreterData implements Serializable, DebuggableScript
InterpreterData(InterpreterData parent)
{
this.parentData = parent;
this.securityController = parent.securityController;
this.securityDomain = parent.securityDomain;
this.languageVersion = parent.languageVersion;
this.itsSourceFile = parent.itsSourceFile;
this.encodedSource = parent.encodedSource;
@ -81,13 +75,9 @@ final class InterpreterData implements Serializable, DebuggableScript
itsStringTable = new String[INITIAL_STRINGTABLE_SIZE];
}
SecurityController securityController;
Object securityDomain;
String itsName;
String itsSourceFile;
boolean itsNeedsActivation;
boolean itsFromEvalCode;
boolean itsCheckThis;
int itsFunctionType;

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

@ -46,7 +46,8 @@ package org.mozilla.javascript;
public class NativeFunction extends BaseFunction
{
public final void initScriptFunction(int version, String functionName,
public final void initScriptFunction(Context cx, Scriptable scope,
int version, String functionName,
String[] argNames, int argCount)
{
if (!(argNames != null
@ -64,6 +65,25 @@ public class NativeFunction extends BaseFunction
this.argNames = argNames;
this.argCount = argCount;
this.version = version;
ScriptRuntime.setFunctionProtoAndParent(scope, this);
}
public final void initScriptObject(int version, String[] varNames)
{
if (varNames == null) {
throw new IllegalArgumentException();
}
if (!(this.argNames == null)) {
// Initialization can only be done once
throw new IllegalStateException();
}
this.functionName = "";
this.argNames = varNames;
this.argCount = 0;
this.version = version;
}
/**

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

@ -198,7 +198,8 @@ class NativeScript extends NativeFunction implements Script
}
ErrorReporter reporter;
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
return cx.compileString(source, reporter, filename, linep[0], null);
return cx.compileString(source, null, reporter, filename,
linep[0], null);
}
// #string_id_map#

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

@ -2203,17 +2203,11 @@ public class ScriptRuntime {
ErrorReporter reporter;
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter());
// Compile the reader with opt level of -1 to force interpreter
// Compile with explicit interpreter instance to force interpreter
// mode.
int savedLevel = cx.optimizationLevel;
cx.optimizationLevel = -1;
Script script;
try {
script = cx.compileString((String)x, reporter, sourceName, 1, null);
} finally {
cx.optimizationLevel = savedLevel;
}
((InterpretedScript)script).itsData.itsFromEvalCode = true;
Script script = cx.compileString((String)x, new Interpreter(),
reporter, sourceName, 1, null);
((InterpretedFunction)script).evalScriptFlag = true;
// if the compile fails, an error has been reported by the
// compiler, but we need to stop execution to avoid
@ -2910,7 +2904,7 @@ public class ScriptRuntime {
}
public static void setFunctionProtoAndParent(Scriptable scope,
Function fn)
BaseFunction fn)
{
fn.setPrototype(ScriptableObject.getFunctionPrototype(scope));
fn.setParentScope(scope);
@ -2920,7 +2914,6 @@ public class ScriptRuntime {
NativeFunction function, int type,
boolean fromEvalCode)
{
setFunctionProtoAndParent(scope, function);
if (type == FunctionNode.FUNCTION_STATEMENT) {
String name = function.functionName;
if (name != null && name.length() != 0) {
@ -2944,6 +2937,8 @@ public class ScriptRuntime {
}
scope.put(name, scope, function);
}
} else {
throw Kit.codeBug();
}
}

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

@ -54,12 +54,10 @@ import java.lang.reflect.Constructor;
public class Codegen extends Interpreter
{
public Object compile(Scriptable scope,
CompilerEnvirons compilerEnv,
ScriptOrFnNode scriptOrFn,
public Object compile(CompilerEnvirons compilerEnv,
ScriptOrFnNode tree,
String encodedSource,
boolean returnFunction,
Object securityDomain)
boolean returnFunction)
{
int serial;
synchronized (globalLock) {
@ -68,56 +66,66 @@ public class Codegen extends Interpreter
String mainClassName = "org.mozilla.javascript.gen.c"+serial;
byte[] mainClassBytes = compileToClassFile(compilerEnv, mainClassName,
scriptOrFn, encodedSource,
tree, encodedSource,
returnFunction);
Exception e = null;
Class result = null;
GeneratedClassLoader
loader = SecurityController.createLoader(null, securityDomain);
try {
result = loader.defineClass(mainClassName, mainClassBytes);
loader.linkClass(result);
} catch (SecurityException x) {
e = x;
} catch (IllegalArgumentException x) {
e = x;
return new Object[] { mainClassName, mainClassBytes };
}
if (e != null)
throw new RuntimeException("Malformed optimizer package " + e);
if (returnFunction) {
Context cx = Context.getCurrentContext();
NativeFunction f;
try {
Constructor ctor = result.getConstructors()[0];
Object[] initArgs = { scope, cx, new Integer(0) };
f = (NativeFunction)ctor.newInstance(initArgs);
} catch (Exception ex) {
throw new RuntimeException
("Unable to instantiate compiled class:"+ex.toString());
}
OptRuntime.initFunction(
f, FunctionNode.FUNCTION_STATEMENT, scope, cx);
return f;
} else {
public Script createScriptObject(Object bytecode,
Object staticSecurityDomain)
{
Class cl = defineClass(bytecode, staticSecurityDomain);
Script script;
try {
script = (Script) result.newInstance();
script = (Script)cl.newInstance();
} catch (Exception ex) {
throw new RuntimeException
("Unable to instantiate compiled class:"+ex.toString());
}
return script;
}
public Function createFunctionObject(Context cx, Scriptable scope,
Object bytecode,
Object staticSecurityDomain)
{
Class cl = defineClass(bytecode, staticSecurityDomain);
NativeFunction f;
try {
Constructor ctor = cl.getConstructors()[0];
Object[] initArgs = { scope, cx, new Integer(0) };
f = (NativeFunction)ctor.newInstance(initArgs);
} catch (Exception ex) {
throw new RuntimeException
("Unable to instantiate compiled class:"+ex.toString());
}
return f;
}
public void notifyDebuggerCompilationDone(Context cx,
ScriptOrFnNode scriptOrFn,
String debugSource)
private static Class defineClass(Object bytecode,
Object staticSecurityDomain)
{
throw new RuntimeException("NOT SUPPORTED");
Object[] nameBytesPair = (Object[])bytecode;
String className = (String)nameBytesPair[0];
byte[] classBytes = (byte[])nameBytesPair[1];
GeneratedClassLoader loader;
loader = SecurityController.createLoader(null, staticSecurityDomain);
Exception e;
try {
Class cl = loader.defineClass(className, classBytes);
loader.linkClass(cl);
return cl;
} catch (SecurityException x) {
e = x;
} catch (IllegalArgumentException x) {
e = x;
}
throw new RuntimeException("Malformed optimizer package " + e);
}
byte[] compileToClassFile(CompilerEnvirons compilerEnv,
@ -543,17 +551,13 @@ public class Codegen extends Interpreter
cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME, "I");
// Call
// NativeFunction.initScriptFunction(version, "", varNamesArray, 0)
// NativeFunction.initScriptObject(version, varNamesArray)
cfw.addLoadThis();
cfw.addPush(compilerEnv.getLanguageVersion());
cfw.addPush(""); // Function name
pushParamNamesArray(cfw, script);
cfw.addPush(0); // No parameters, only varnames
cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
"org/mozilla/javascript/NativeFunction",
"initScriptFunction",
"(ILjava/lang/String;[Ljava/lang/String;I)V");
"initScriptObject", "(I[Ljava/lang/String;)V");
cfw.add(ByteCode.RETURN);
// 1 parameter = this
@ -628,6 +632,8 @@ public class Codegen extends Interpreter
// Call NativeFunction.initScriptFunction
cfw.addLoadThis();
cfw.addALoad(CONTEXT_ARG);
cfw.addALoad(SCOPE_ARG);
cfw.addPush(compilerEnv.getLanguageVersion());
cfw.addPush(ofn.fnode.getFunctionName());
pushParamNamesArray(cfw, ofn.fnode);
@ -635,14 +641,13 @@ public class Codegen extends Interpreter
cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
"org/mozilla/javascript/NativeFunction",
"initScriptFunction",
"(ILjava/lang/String;[Ljava/lang/String;I)V");
cfw.addLoadThis();
cfw.addALoad(SCOPE_ARG);
cfw.addInvoke(ByteCode.INVOKEVIRTUAL,
"org/mozilla/javascript/ScriptableObject",
"setParentScope",
"(Lorg/mozilla/javascript/Scriptable;)V");
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"I"
+"Ljava/lang/String;"
+"[Ljava/lang/String;"
+"I"
+")V");
// precompile all regexp literals
int regexpCount = ofn.fnode.getRegexpCount();
@ -2123,10 +2128,10 @@ class BodyCodegen
codegen.mainClassSignature);
}
// Dup function reference for function expressions to have it
// on top of the stack when initFunction returns
if (functionType == FunctionNode.FUNCTION_EXPRESSION) {
cfw.add(ByteCode.DUP);
// Leave closure object on stack and do not pass it to
// initFunction which suppose to connect statements to scope
return;
}
cfw.addPush(functionType);
cfw.addALoad(variableObjectLocal);