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; linep[0] = 1;
} }
String sourceName = ScriptRuntime. String sourceURI = ScriptRuntime.
makeUrlForGeneratedScript(false, filename, linep[0]); makeUrlForGeneratedScript(false, filename, linep[0]);
Scriptable global = ScriptableObject.getTopLevelScope(scope); 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. // mode.
int savedLevel = cx.optimizationLevel; return cx.compileFunction(global, source, new Interpreter(), reporter,
cx.optimizationLevel = -1; sourceURI, 1, null);
NativeFunction fn;
try {
fn = (NativeFunction) cx.compileFunction(global, source,
sourceName, 1,
null);
}
finally { cx.optimizationLevel = savedLevel; }
ScriptRuntime.setFunctionProtoAndParent(global, fn);
return fn;
} }
protected int findPrototypeId(String s) protected int findPrototypeId(String s)

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

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

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

@ -19,6 +19,7 @@
* Rights Reserved. * Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Igor Bukanov
* Roger Lawrence * Roger Lawrence
* *
* Alternatively, the contents of this file may be used under the * Alternatively, the contents of this file may be used under the
@ -35,40 +36,126 @@
package org.mozilla.javascript; package org.mozilla.javascript;
import java.io.Serializable; final class InterpretedFunction extends NativeFunction implements Script
final class InterpretedFunction extends NativeFunction
implements Serializable
{ {
InterpreterData idata;
SecurityController securityController;
Object securityDomain;
Scriptable[] functionRegExps;
boolean evalScriptFlag; // true if script corresponds to eval() code
static final long serialVersionUID = -6235150451107527319L; private InterpretedFunction(InterpreterData idata,
Object staticSecurityDomain)
InterpretedFunction(InterpreterData theData)
{ {
itsData = theData; this.idata = idata;
initScriptFunction(itsData.languageVersion, itsData.itsName,
itsData.argNames, itsData.argCount); // 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, public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args) Object[] args)
throws JavaScriptException
{ {
if (!ScriptRuntime.hasTopCall(cx)) { if (!ScriptRuntime.hasTopCall(cx)) {
return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args); return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
} }
return Interpreter.interpret(cx, scope, thisObj, return Interpreter.interpret(cx, scope, thisObj, args, null,
args, null, 0, args.length, 0, args.length, this);
this, itsData); }
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() 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); return validIcode(bytecode) || validTokenCode(bytecode);
} }
public Object compile(Scriptable scope, public Object compile(CompilerEnvirons compilerEnv,
CompilerEnvirons compilerEnv,
ScriptOrFnNode tree, ScriptOrFnNode tree,
String encodedSource, String encodedSource,
boolean returnFunction, boolean returnFunction)
Object staticSecurityDomain)
{ {
this.compilerEnv = compilerEnv; this.compilerEnv = compilerEnv;
new NodeTransformer().transform(tree); new NodeTransformer().transform(tree);
@ -275,56 +273,36 @@ public class Interpreter
tree = tree.getFunctionNode(0); 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; scriptOrFn = tree;
itsData = new InterpreterData(sc, dynamicDomain, itsData = new InterpreterData(compilerEnv.getLanguageVersion(),
compilerEnv.getLanguageVersion(),
scriptOrFn.getSourceName(), scriptOrFn.getSourceName(),
encodedSource); encodedSource);
itsData.topLevel = true; itsData.topLevel = true;
if (returnFunction) { if (returnFunction) {
generateFunctionICode(); generateFunctionICode();
return createFunction(cx, scope, itsData, false);
} else { } else {
generateICodeFromTree(scriptOrFn); generateICodeFromTree(scriptOrFn);
return new InterpretedScript(itsData);
}
} }
public void notifyDebuggerCompilationDone(Context cx, return itsData;
Object scriptOrFunction,
String debugSource)
{
InterpreterData idata;
if (scriptOrFunction instanceof InterpretedScript) {
idata = ((InterpretedScript)scriptOrFunction).itsData;
} else {
idata = ((InterpretedFunction)scriptOrFunction).itsData;
}
notifyDebugger_r(cx, idata, debugSource);
} }
private static void notifyDebugger_r(Context cx, InterpreterData idata, public Script createScriptObject(Object bytecode,
String debugSource) Object staticSecurityDomain)
{ {
cx.debugger.handleCompilationDone(cx, idata, debugSource); InterpreterData idata = (InterpreterData)bytecode;
if (idata.itsNestedFunctions != null) { return InterpretedFunction.createScript(itsData,
for (int i = 0; i != idata.itsNestedFunctions.length; ++i) { staticSecurityDomain);
notifyDebugger_r(cx, idata.itsNestedFunctions[i], debugSource);
}
} }
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() private void generateFunctionICode()
@ -1953,56 +1931,38 @@ public class Interpreter
idata.encodedSourceEnd); idata.encodedSourceEnd);
} }
private static Scriptable[] wrapRegExps(Context cx, Scriptable scope, private static void initFunction(Context cx, Scriptable scope,
InterpreterData idata) InterpretedFunction parent, int index)
{ {
if (idata.itsRegExpLiterals == null) Kit.codeBug(); InterpretedFunction fn;
fn = InterpretedFunction.createFunction(cx, scope, parent, index);
RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx); ScriptRuntime.initFunction(cx, scope, fn, fn.idata.itsFunctionType,
int N = idata.itsRegExpLiterals.length; parent.evalScriptFlag);
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;
} }
static Object interpret(Context cx, Scriptable scope, Scriptable thisObj, static Object interpret(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args, double[] argsDbl, Object[] args, double[] argsDbl,
int argShift, int argCount, int argShift, int argCount,
NativeFunction fnOrScript, InterpretedFunction fnOrScript)
InterpreterData idata)
throws JavaScriptException
{ {
if (cx.interpreterSecurityDomain != idata.securityDomain) { if (cx.interpreterSecurityDomain != fnOrScript.securityDomain) {
if (argsDbl != null) { if (argsDbl != null) {
args = getArgsArray(args, argsDbl, argShift, argCount); args = getArgsArray(args, argsDbl, argShift, argCount);
} }
SecurityController sc = idata.securityController; SecurityController sc = fnOrScript.securityController;
Object savedDomain = cx.interpreterSecurityDomain; Object savedDomain = cx.interpreterSecurityDomain;
cx.interpreterSecurityDomain = idata.securityDomain; cx.interpreterSecurityDomain = fnOrScript.securityDomain;
try { try {
return sc.callWithDomain(idata.securityDomain, cx, fnOrScript, return fnOrScript.securityController.callWithDomain(
scope, thisObj, args); fnOrScript.securityDomain, cx, fnOrScript, scope,
thisObj, args);
} finally { } finally {
cx.interpreterSecurityDomain = savedDomain; cx.interpreterSecurityDomain = savedDomain;
} }
} }
InterpreterData idata = fnOrScript.idata;
final Object DBL_MRK = Interpreter.DBL_MRK; final Object DBL_MRK = Interpreter.DBL_MRK;
final Scriptable undefined = Undefined.instance; final Scriptable undefined = Undefined.instance;
@ -2055,7 +2015,6 @@ public class Interpreter
} }
if (idata.itsFunctionType != 0) { if (idata.itsFunctionType != 0) {
InterpretedFunction f = (InterpretedFunction)fnOrScript;
if (!idata.useDynamicScope) { if (!idata.useDynamicScope) {
scope = fnOrScript.getParentScope(); scope = fnOrScript.getParentScope();
} }
@ -2071,7 +2030,7 @@ public class Interpreter
} }
} else { } else {
ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope, ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope,
idata.itsFromEvalCode); fnOrScript.evalScriptFlag);
} }
if (idata.itsNestedFunctions != null) { if (idata.itsNestedFunctions != null) {
@ -2080,21 +2039,29 @@ public class Interpreter
for (int i = 0; i < idata.itsNestedFunctions.length; i++) { for (int i = 0; i < idata.itsNestedFunctions.length; i++) {
InterpreterData fdata = idata.itsNestedFunctions[i]; InterpreterData fdata = idata.itsNestedFunctions[i];
if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) { 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 // Wrapped regexps for functions are stored in InterpretedFunction
// but for script which should not contain references to scope // but for script which should not contain references to scope
// the regexps re-wrapped during each script execution // 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) { if (debuggerFrame != null) {
debuggerFrame.onEnter(cx, scope, thisObj, args); debuggerFrame.onEnter(cx, scope, thisObj, args);
} }
InterpreterData savedData = cx.interpreterData; InterpreterData savedData = cx.interpreterData;
int savedLineIndex = cx.interpreterLineIndex;
cx.interpreterData = idata; cx.interpreterData = idata;
cx.interpreterLineIndex = idata.firstLinePC; cx.interpreterLineIndex = idata.firstLinePC;
@ -2638,9 +2605,8 @@ switch (op) {
// Inlining of InterpretedFunction.call not to create // Inlining of InterpretedFunction.call not to create
// argument array // argument array
InterpretedFunction ifun = (InterpretedFunction)fun; InterpretedFunction ifun = (InterpretedFunction)fun;
stack[stackTop] = interpret(cx, funScope, funThisObj, stack[stackTop] = interpret(cx, funScope, funThisObj, stack, sDbl,
stack, sDbl, calleeArgShft, indexReg, calleeArgShft, indexReg, ifun);
ifun, ifun.itsData);
} else { } else {
Object[] outArgs = getArgsArray(stack, sDbl, calleeArgShft, Object[] outArgs = getArgsArray(stack, sDbl, calleeArgShft,
indexReg); indexReg);
@ -2685,9 +2651,8 @@ switch (op) {
// argument array // argument array
InterpretedFunction f = (InterpretedFunction)lhs; InterpretedFunction f = (InterpretedFunction)lhs;
Scriptable newInstance = f.createObject(cx, scope); Scriptable newInstance = f.createObject(cx, scope);
Object callResult = interpret(cx, scope, newInstance, Object callResult = interpret(cx, scope, newInstance, stack, sDbl,
stack, sDbl, calleeArgShft, indexReg, calleeArgShft, indexReg, f);
f, f.itsData);
if (callResult instanceof Scriptable && callResult != undefined) { if (callResult instanceof Scriptable && callResult != undefined) {
stack[stackTop] = callResult; stack[stackTop] = callResult;
} else { } else {
@ -2883,30 +2848,17 @@ switch (op) {
case Icode_SCOPE : case Icode_SCOPE :
stack[++stackTop] = scope; stack[++stackTop] = scope;
continue Loop; continue Loop;
case Icode_CLOSURE_EXPR : { case Icode_CLOSURE_EXPR :
InterpreterData closureData = idata.itsNestedFunctions[indexReg]; stack[++stackTop] = InterpretedFunction.createFunction(cx, scope,
stack[++stackTop] = createFunction(cx, scope, closureData, fnOrScript,
idata.itsFromEvalCode); indexReg);
continue Loop; continue Loop;
} case Icode_CLOSURE_STMT :
case Icode_CLOSURE_STMT : { initFunction(cx, scope, fnOrScript, indexReg);
InterpreterData closureData = idata.itsNestedFunctions[indexReg];
createFunction(cx, scope, closureData, idata.itsFromEvalCode);
continue Loop; continue Loop;
} case Token.REGEXP :
case Token.REGEXP : { stack[++stackTop] = scriptRegExps[indexReg];
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;
continue Loop; continue Loop;
}
case Icode_LITERAL_NEW : case Icode_LITERAL_NEW :
// indexReg: number of values in the literal // indexReg: number of values in the literal
++stackTop; ++stackTop;
@ -3101,6 +3053,7 @@ switch (op) {
} // end of interpreter loop } // end of interpreter loop
cx.interpreterData = savedData; cx.interpreterData = savedData;
cx.interpreterLineIndex = savedLineIndex;
if (debuggerFrame != null) { if (debuggerFrame != null) {
if (javaException != 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_STRINGTABLE_SIZE = 64;
static final int INITIAL_NUMBERTABLE_SIZE = 64; static final int INITIAL_NUMBERTABLE_SIZE = 64;
InterpreterData(SecurityController securityController, InterpreterData(int languageVersion,
Object securityDomain,
int languageVersion,
String sourceFile, String encodedSource) String sourceFile, String encodedSource)
{ {
this.securityController = securityController;
this.securityDomain = securityDomain;
this.languageVersion = languageVersion; this.languageVersion = languageVersion;
this.itsSourceFile = sourceFile; this.itsSourceFile = sourceFile;
this.encodedSource = encodedSource; this.encodedSource = encodedSource;
@ -66,8 +62,6 @@ final class InterpreterData implements Serializable, DebuggableScript
InterpreterData(InterpreterData parent) InterpreterData(InterpreterData parent)
{ {
this.parentData = parent; this.parentData = parent;
this.securityController = parent.securityController;
this.securityDomain = parent.securityDomain;
this.languageVersion = parent.languageVersion; this.languageVersion = parent.languageVersion;
this.itsSourceFile = parent.itsSourceFile; this.itsSourceFile = parent.itsSourceFile;
this.encodedSource = parent.encodedSource; this.encodedSource = parent.encodedSource;
@ -81,13 +75,9 @@ final class InterpreterData implements Serializable, DebuggableScript
itsStringTable = new String[INITIAL_STRINGTABLE_SIZE]; itsStringTable = new String[INITIAL_STRINGTABLE_SIZE];
} }
SecurityController securityController;
Object securityDomain;
String itsName; String itsName;
String itsSourceFile; String itsSourceFile;
boolean itsNeedsActivation; boolean itsNeedsActivation;
boolean itsFromEvalCode;
boolean itsCheckThis; boolean itsCheckThis;
int itsFunctionType; int itsFunctionType;

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

@ -46,7 +46,8 @@ package org.mozilla.javascript;
public class NativeFunction extends BaseFunction 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) String[] argNames, int argCount)
{ {
if (!(argNames != null if (!(argNames != null
@ -64,6 +65,25 @@ public class NativeFunction extends BaseFunction
this.argNames = argNames; this.argNames = argNames;
this.argCount = argCount; this.argCount = argCount;
this.version = version; 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; ErrorReporter reporter;
reporter = DefaultErrorReporter.forEval(cx.getErrorReporter()); 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# // #string_id_map#

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

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

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

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