зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
8b7a521e30
Коммит
e4d1c4896b
|
@ -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,
|
||||
securityDomain, false,
|
||||
compilationErrorReporter);
|
||||
return (Script) compileImpl(null, null, source, sourceName, lineno,
|
||||
securityDomain, false,
|
||||
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,11 +2300,12 @@ public class Context
|
|||
return formatter.format(arguments);
|
||||
}
|
||||
|
||||
private Object compile(Scriptable scope,
|
||||
Reader sourceReader, String sourceString,
|
||||
String sourceName, int lineno,
|
||||
Object securityDomain, boolean returnFunction,
|
||||
ErrorReporter compilationErrorReporter)
|
||||
private Object compileImpl(Scriptable scope,
|
||||
Reader sourceReader, String sourceString,
|
||||
String sourceName, int lineno,
|
||||
Object securityDomain, boolean returnFunction,
|
||||
Interpreter compiler,
|
||||
ErrorReporter compilationErrorReporter)
|
||||
throws IOException
|
||||
{
|
||||
if (securityDomain != null && securityController == null) {
|
||||
|
@ -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,
|
||||
tree, encodedSource,
|
||||
returnFunction,
|
||||
securityDomain);
|
||||
Object bytecode = compiler.compile(compilerEnv,
|
||||
tree, encodedSource,
|
||||
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);
|
||||
}
|
||||
|
||||
return itsData;
|
||||
}
|
||||
|
||||
public void notifyDebuggerCompilationDone(Context cx,
|
||||
Object scriptOrFunction,
|
||||
String debugSource)
|
||||
public Script createScriptObject(Object bytecode,
|
||||
Object staticSecurityDomain)
|
||||
{
|
||||
InterpreterData idata;
|
||||
if (scriptOrFunction instanceof InterpretedScript) {
|
||||
idata = ((InterpretedScript)scriptOrFunction).itsData;
|
||||
} else {
|
||||
idata = ((InterpretedFunction)scriptOrFunction).itsData;
|
||||
}
|
||||
notifyDebugger_r(cx, idata, debugSource);
|
||||
InterpreterData idata = (InterpreterData)bytecode;
|
||||
return InterpretedFunction.createScript(itsData,
|
||||
staticSecurityDomain);
|
||||
}
|
||||
|
||||
private static void notifyDebugger_r(Context cx, InterpreterData idata,
|
||||
String debugSource)
|
||||
public Function createFunctionObject(Context cx, Scriptable scope,
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.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
|
||||
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);
|
||||
return new Object[] { mainClassName, mainClassBytes };
|
||||
}
|
||||
|
||||
public Script createScriptObject(Object bytecode,
|
||||
Object staticSecurityDomain)
|
||||
{
|
||||
Class cl = defineClass(bytecode, staticSecurityDomain);
|
||||
|
||||
Script script;
|
||||
try {
|
||||
result = loader.defineClass(mainClassName, mainClassBytes);
|
||||
loader.linkClass(result);
|
||||
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;
|
||||
}
|
||||
|
||||
private static Class defineClass(Object bytecode,
|
||||
Object staticSecurityDomain)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
Script script;
|
||||
try {
|
||||
script = (Script) result.newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException
|
||||
("Unable to instantiate compiled class:"+ex.toString());
|
||||
}
|
||||
return script;
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyDebuggerCompilationDone(Context cx,
|
||||
ScriptOrFnNode scriptOrFn,
|
||||
String debugSource)
|
||||
{
|
||||
throw new RuntimeException("NOT SUPPORTED");
|
||||
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");
|
||||
"org/mozilla/javascript/NativeFunction",
|
||||
"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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче