зеркало из https://github.com/mozilla/pjs.git
Top call scope tracking changes:
Since E4X implementation needs to know the activation scope for tracking of default namespaces, previously an elaborated schema was added to set/restore the activation scope which relied on the fact that scrip and function with activation record should always call special entry/exit functions. But that does not work for functions without activation records since they never call any special entry/exit pairs. So if application call such function directly, the function would not store its top scope anywhere and the E4X subsystem would not be able to get E4X library object. The patch fixes with introduction of 2 functions, hasTopCall and doTopCall to ScriptRuntime and adding the following code prefix to each implementation of Callable.call that can start execution of script code: public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) throws JavaScriptException { // Prefix start if (!ScriptRuntime.hasTopCall(cx)) { return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args); } // Prefix end ... In this way there is always registered top scope during script execution and the previous elaborated schema became unnecessary so I reverted that part to almost pre-E4x state.
This commit is contained in:
Родитель
033645c483
Коммит
caf00e67ee
|
@ -226,10 +226,10 @@ final class Arguments extends IdScriptableObject
|
|||
if (value == UniqueTag.NULL_VALUE) { value = null; }
|
||||
else if (value == null) {
|
||||
NativeCall caller = activation.parentActivationCall;
|
||||
if (caller == null) {
|
||||
value = null;
|
||||
} else {
|
||||
if (caller != null) {
|
||||
value = caller.get("arguments", caller);
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
|
|
@ -2547,11 +2547,8 @@ public class Context
|
|||
private boolean sealed;
|
||||
private Object sealKey;
|
||||
|
||||
Scriptable topActivationScope;
|
||||
Scriptable topCallScope;
|
||||
NativeCall currentActivationCall;
|
||||
Scriptable currentActivationScope;
|
||||
int currentActivationDepth;
|
||||
|
||||
XMLLib cachedXMLLib;
|
||||
|
||||
// for Objects, Arrays to tag themselves as being printed out,
|
||||
|
|
|
@ -54,6 +54,9 @@ final class InterpretedFunction extends NativeFunction
|
|||
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);
|
||||
|
|
|
@ -1,72 +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
|
||||
{
|
||||
return Interpreter.interpret(cx, scope, thisObj,
|
||||
args, null, 0, args.length,
|
||||
this, itsData);
|
||||
}
|
||||
|
||||
public String getEncodedSource()
|
||||
{
|
||||
return Interpreter.getEncodedSource(itsData);
|
||||
}
|
||||
|
||||
InterpreterData itsData;
|
||||
}
|
||||
|
|
@ -2041,8 +2041,18 @@ public class Interpreter
|
|||
}
|
||||
|
||||
DebugFrame debuggerFrame = null;
|
||||
boolean useActivationVars = false;
|
||||
if (cx.debugger != null) {
|
||||
debuggerFrame = cx.debugger.getFrame(cx, idata);
|
||||
useActivationVars = (debuggerFrame != null);
|
||||
}
|
||||
|
||||
if (idata.itsNeedsActivation || useActivationVars) {
|
||||
if (argsDbl != null) {
|
||||
args = getArgsArray(args, argsDbl, argShift, argCount);
|
||||
argShift = 0;
|
||||
argsDbl = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (idata.itsFunctionType != 0) {
|
||||
|
@ -2055,19 +2065,14 @@ public class Interpreter
|
|||
thisObj = ScriptRuntime.getThis(thisObj);
|
||||
}
|
||||
|
||||
if (idata.itsNeedsActivation) {
|
||||
if (argsDbl != null) {
|
||||
args = getArgsArray(args, argsDbl, argShift, argCount);
|
||||
argShift = 0;
|
||||
argsDbl = null;
|
||||
}
|
||||
if (idata.itsNeedsActivation || useActivationVars) {
|
||||
scope = ScriptRuntime.enterActivationFunction(cx, scope,
|
||||
fnOrScript,
|
||||
thisObj, args);
|
||||
}
|
||||
|
||||
} else {
|
||||
scope = ScriptRuntime.enterScript(cx, scope, fnOrScript, thisObj);
|
||||
ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope,
|
||||
idata.itsFromEvalCode);
|
||||
}
|
||||
|
||||
if (idata.itsNestedFunctions != null) {
|
||||
|
@ -2086,19 +2091,7 @@ public class Interpreter
|
|||
// the regexps re-wrapped during each script execution
|
||||
Scriptable[] scriptRegExps = null;
|
||||
|
||||
boolean useActivationVars = false;
|
||||
if (debuggerFrame != null) {
|
||||
if (argsDbl != null) {
|
||||
args = getArgsArray(args, argsDbl, argShift, argCount);
|
||||
argShift = 0;
|
||||
argsDbl = null;
|
||||
}
|
||||
if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation) {
|
||||
useActivationVars = true;
|
||||
scope = ScriptRuntime.enterActivationFunction(cx, scope,
|
||||
fnOrScript,
|
||||
thisObj, args);
|
||||
}
|
||||
debuggerFrame.onEnter(cx, scope, thisObj, args);
|
||||
}
|
||||
|
||||
|
@ -3119,11 +3112,9 @@ switch (op) {
|
|||
}
|
||||
|
||||
if (idata.itsFunctionType != 0) {
|
||||
if (idata.itsNeedsActivation || debuggerFrame != null) {
|
||||
if (idata.itsNeedsActivation || useActivationVars) {
|
||||
ScriptRuntime.exitActivationFunction(cx);
|
||||
}
|
||||
} else {
|
||||
ScriptRuntime.exitScript(cx);
|
||||
}
|
||||
|
||||
if (javaException != null) {
|
||||
|
|
|
@ -157,6 +157,5 @@ public final class NativeCall extends IdScriptableObject
|
|||
private Object[] originalArgs;
|
||||
|
||||
NativeCall parentActivationCall;
|
||||
Scriptable parentActivationScope;
|
||||
}
|
||||
|
||||
|
|
|
@ -1085,9 +1085,12 @@ public class ScriptRuntime {
|
|||
|
||||
public static Object setDefaultNamespace(Object namespace, Context cx)
|
||||
{
|
||||
Scriptable scope = cx.currentActivationScope;
|
||||
Scriptable scope = cx.currentActivationCall;
|
||||
if (scope == null) {
|
||||
scope = cx.topCallScope;
|
||||
if (scope == null)
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
XMLLib xmlLib = currentXMLLib(cx);
|
||||
Object ns = xmlLib.toDefaultXmlNamespace(cx, namespace);
|
||||
|
@ -1107,9 +1110,11 @@ public class ScriptRuntime {
|
|||
|
||||
public static Object searchDefaultNamespace(Context cx)
|
||||
{
|
||||
Scriptable scope = cx.currentActivationScope;
|
||||
Scriptable scope = cx.currentActivationCall;
|
||||
if (scope == null) {
|
||||
return null;
|
||||
scope = cx.topCallScope;
|
||||
if (scope == null)
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Object nsObject;
|
||||
for (;;) {
|
||||
|
@ -1751,8 +1756,7 @@ public class ScriptRuntime {
|
|||
// been defined, creates a new property in the
|
||||
// global object. Find the global object by
|
||||
// walking up the scope chain.
|
||||
Scriptable scope = cx.currentActivationScope;
|
||||
bound = ScriptableObject.getTopLevelScope(scope);
|
||||
bound = cx.topCallScope;
|
||||
bound.put(id, bound, value);
|
||||
/*
|
||||
This code is causing immense performance problems in
|
||||
|
@ -2749,27 +2753,64 @@ public class ScriptRuntime {
|
|||
return new ImporterTopLevel(cx);
|
||||
}
|
||||
|
||||
public static Scriptable enterScript(Context cx, Scriptable scope,
|
||||
NativeFunction funObj,
|
||||
Scriptable thisObj)
|
||||
public static boolean hasTopCall(Context cx)
|
||||
{
|
||||
boolean topLevel = (cx.currentActivationDepth == 0);
|
||||
return (cx.topCallScope != null);
|
||||
}
|
||||
|
||||
public static Object doTopCall(Callable callable,
|
||||
Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
if (cx.topCallScope != null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
Object result;
|
||||
cx.topCallScope = ScriptableObject.getTopLevelScope(scope);
|
||||
try {
|
||||
result = callable.call(cx, scope, thisObj, args);
|
||||
} finally {
|
||||
releaseTopCall(cx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void releaseTopCall(Context cx)
|
||||
{
|
||||
cx.topCallScope = null;
|
||||
// Cleanup cached references
|
||||
cx.cachedXMLLib = null;
|
||||
|
||||
if (cx.currentActivationCall != null) {
|
||||
// Function should always call exitActivationFunction
|
||||
// if it creates activation record
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void initScript(NativeFunction funObj, Scriptable thisObj,
|
||||
Context cx, Scriptable scope,
|
||||
boolean evalScript)
|
||||
{
|
||||
if (cx.topCallScope == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
String[] argNames = funObj.argNames;
|
||||
if (argNames != null) {
|
||||
|
||||
Scriptable varScope = scope;
|
||||
// Never define any variables from var statements inside with object.
|
||||
// See bug 38590.
|
||||
// Never define any variables from var statements inside with
|
||||
// object. See bug 38590.
|
||||
while (varScope instanceof NativeWith) {
|
||||
varScope = varScope.getParentScope();
|
||||
}
|
||||
|
||||
String[] argNames = funObj.argNames;
|
||||
if (argNames != null) {
|
||||
for (int i = argNames.length; i-- != 0;) {
|
||||
String name = argNames[i];
|
||||
// Don't overwrite existing def if already defined in object
|
||||
// or prototypes of object.
|
||||
if (!hasProp(scope, name)) {
|
||||
if (topLevel) {
|
||||
if (!evalScript) {
|
||||
// Global var definitions are supposed to be DONTDELETE
|
||||
ScriptableObject.defineProperty(
|
||||
varScope, name, Undefined.instance,
|
||||
|
@ -2780,29 +2821,6 @@ public class ScriptRuntime {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (topLevel) {
|
||||
if (cx.currentActivationScope != null)
|
||||
throw new IllegalStateException();
|
||||
cx.currentActivationScope = varScope;
|
||||
}
|
||||
|
||||
increaseActivationDepth(cx);
|
||||
|
||||
return scope;
|
||||
}
|
||||
|
||||
public static void exitScript(Context cx)
|
||||
{
|
||||
if (cx.currentActivationDepth == 0)
|
||||
throw new IllegalStateException();
|
||||
if (cx.currentActivationScope == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
if (cx.currentActivationDepth == 1) {
|
||||
cx.currentActivationScope = null;
|
||||
}
|
||||
decreaseActivationDepth(cx);
|
||||
}
|
||||
|
||||
public static Scriptable enterActivationFunction(Context cx,
|
||||
|
@ -2811,64 +2829,21 @@ public class ScriptRuntime {
|
|||
Scriptable thisObj,
|
||||
Object[] args)
|
||||
{
|
||||
if (cx.topCallScope == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
NativeCall call = new NativeCall(scope, funObj, thisObj, args);
|
||||
call.parentActivationCall = cx.currentActivationCall;
|
||||
call.parentActivationScope = cx.currentActivationScope;
|
||||
|
||||
cx.currentActivationCall = call;
|
||||
cx.currentActivationScope = call;
|
||||
|
||||
increaseActivationDepth(cx);
|
||||
|
||||
return call;
|
||||
}
|
||||
|
||||
public static void exitActivationFunction(Context cx)
|
||||
{
|
||||
if (cx.currentActivationDepth == 0)
|
||||
throw new IllegalStateException();
|
||||
if (cx.currentActivationScope == null)
|
||||
throw new IllegalStateException();
|
||||
if (cx.currentActivationCall != cx.currentActivationScope)
|
||||
throw new IllegalStateException();
|
||||
|
||||
NativeCall call = cx.currentActivationCall;
|
||||
cx.currentActivationCall = call.parentActivationCall;
|
||||
cx.currentActivationScope = call.parentActivationScope;
|
||||
|
||||
call.parentActivationCall = null;
|
||||
call.parentActivationScope = null;
|
||||
|
||||
decreaseActivationDepth(cx);
|
||||
}
|
||||
|
||||
private static void increaseActivationDepth(Context cx)
|
||||
{
|
||||
// The caller should initialize this already
|
||||
if (cx.currentActivationScope == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
if (cx.currentActivationDepth == 0) {
|
||||
cx.topActivationScope = cx.currentActivationScope;
|
||||
}
|
||||
++cx.currentActivationDepth;
|
||||
}
|
||||
|
||||
private static void decreaseActivationDepth(Context cx)
|
||||
{
|
||||
--cx.currentActivationDepth;
|
||||
|
||||
if (cx.currentActivationDepth == 0) {
|
||||
// The caller should do proper cleanup
|
||||
if (cx.currentActivationScope != null)
|
||||
throw new IllegalStateException();
|
||||
if (cx.currentActivationCall != null)
|
||||
throw new IllegalStateException();
|
||||
cx.topActivationScope = null;
|
||||
|
||||
// Cleanup references
|
||||
cx.cachedXMLLib = null;
|
||||
}
|
||||
}
|
||||
|
||||
static NativeCall findFunctionActivation(Context cx, Function f)
|
||||
|
@ -3185,12 +3160,12 @@ public class ScriptRuntime {
|
|||
private static XMLLib currentXMLLib(Context cx)
|
||||
{
|
||||
// Scripts should be running to access this
|
||||
if (cx.topActivationScope == null)
|
||||
if (cx.topCallScope == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
XMLLib xmlLib = cx.cachedXMLLib;
|
||||
if (xmlLib == null) {
|
||||
xmlLib = XMLLib.extractFromScope(cx.topActivationScope);
|
||||
xmlLib = XMLLib.extractFromScope(cx.topCallScope);
|
||||
if (xmlLib == null)
|
||||
throw new IllegalStateException();
|
||||
cx.cachedXMLLib = xmlLib;
|
||||
|
|
|
@ -374,6 +374,38 @@ public class Codegen extends Interpreter
|
|||
(short)(ClassFileWriter.ACC_PUBLIC
|
||||
| ClassFileWriter.ACC_FINAL));
|
||||
|
||||
// Generate code for:
|
||||
// if (!ScriptRuntime.hasTopCall(cx)) {
|
||||
// return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
|
||||
// }
|
||||
|
||||
int nonTopCallLabel = cfw.acquireLabel();
|
||||
cfw.addALoad(1); //cx
|
||||
cfw.addInvoke(ByteCode.INVOKESTATIC,
|
||||
"org/mozilla/javascript/ScriptRuntime",
|
||||
"hasTopCall",
|
||||
"(Lorg/mozilla/javascript/Context;"
|
||||
+")Z");
|
||||
cfw.add(ByteCode.IFNE, nonTopCallLabel);
|
||||
cfw.addALoad(0);
|
||||
cfw.addALoad(1);
|
||||
cfw.addALoad(2);
|
||||
cfw.addALoad(3);
|
||||
cfw.addALoad(4);
|
||||
cfw.addInvoke(ByteCode.INVOKESTATIC,
|
||||
"org/mozilla/javascript/ScriptRuntime",
|
||||
"doTopCall",
|
||||
"(Lorg/mozilla/javascript/Callable;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"[Ljava/lang/Object;"
|
||||
+")Ljava/lang/Object;");
|
||||
cfw.add(ByteCode.ARETURN);
|
||||
cfw.markLabel(nonTopCallLabel);
|
||||
|
||||
// No generate switch to call the real methods
|
||||
|
||||
cfw.addALoad(0);
|
||||
cfw.addALoad(1);
|
||||
cfw.addALoad(2);
|
||||
|
@ -1261,20 +1293,22 @@ class BodyCodegen
|
|||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"[Ljava/lang/Object;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
cfw.addAStore(variableObjectLocal);
|
||||
} else {
|
||||
debugVariableName = "global";
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
cfw.addALoad(funObjLocal);
|
||||
cfw.addALoad(thisObjLocal);
|
||||
addScriptRuntimeInvoke("enterScript",
|
||||
"(Lorg/mozilla/javascript/Context;"
|
||||
cfw.addALoad(contextLocal);
|
||||
cfw.addALoad(variableObjectLocal);
|
||||
cfw.addPush(0); // false to indicate it is not eval script
|
||||
addScriptRuntimeInvoke("initScript",
|
||||
"(Lorg/mozilla/javascript/NativeFunction;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+"Lorg/mozilla/javascript/NativeFunction;"
|
||||
+"Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
+")Lorg/mozilla/javascript/Scriptable;");
|
||||
+"Z"
|
||||
+")V");
|
||||
}
|
||||
cfw.addAStore(variableObjectLocal);
|
||||
|
||||
enterAreaStartLabel = cfw.acquireLabel();
|
||||
epilogueLabel = cfw.acquireLabel();
|
||||
|
@ -1334,10 +1368,11 @@ class BodyCodegen
|
|||
}
|
||||
|
||||
cfw.markLabel(epilogueLabel);
|
||||
generateExitCode();
|
||||
if (fnCurrent == null) {
|
||||
cfw.addALoad(popvLocal);
|
||||
}
|
||||
cfw.add(ByteCode.ARETURN);
|
||||
} else {
|
||||
generateActivationExit();
|
||||
cfw.add(ByteCode.ARETURN);
|
||||
|
||||
// Generate catch block to catch all and rethrow to call exit code
|
||||
|
@ -1348,9 +1383,9 @@ class BodyCodegen
|
|||
short exceptionObject = getNewWordLocal();
|
||||
cfw.addAStore(exceptionObject);
|
||||
|
||||
// Duplicate generateExitCode() in the catch block since it takes
|
||||
// less space then full-fetured ByteCode.JSR/ByteCode.RET
|
||||
generateExitCode();
|
||||
// Duplicate generateActivationExit() in the catch block since it
|
||||
// takes less space then full-fetured ByteCode.JSR/ByteCode.RET
|
||||
generateActivationExit();
|
||||
|
||||
cfw.addALoad(exceptionObject);
|
||||
releaseWordLocal(exceptionObject);
|
||||
|
@ -1361,17 +1396,14 @@ class BodyCodegen
|
|||
cfw.addExceptionHandler(enterAreaStartLabel, epilogueLabel,
|
||||
finallyHandler, null); // catch any
|
||||
}
|
||||
}
|
||||
|
||||
private void generateExitCode()
|
||||
private void generateActivationExit()
|
||||
{
|
||||
if (fnCurrent == null || hasVarsInRegs) throw Kit.codeBug();
|
||||
cfw.addALoad(contextLocal);
|
||||
if (fnCurrent != null) {
|
||||
addScriptRuntimeInvoke("exitActivationFunction",
|
||||
"(Lorg/mozilla/javascript/Context;)V");
|
||||
} else {
|
||||
addScriptRuntimeInvoke("exitScript",
|
||||
"(Lorg/mozilla/javascript/Context;)V");
|
||||
}
|
||||
}
|
||||
|
||||
private void generateStatement(Node node, Node parent)
|
||||
|
|
|
@ -532,7 +532,8 @@ msg.invalid.escape =\
|
|||
invalid Unicode escape sequence
|
||||
|
||||
msg.bad.namespace =\
|
||||
not a valid namespace. Syntax is: namespace variableName as "URI";
|
||||
not a valid default namespace statement. \
|
||||
Syntax is: default xml namespace = EXPRESSION;
|
||||
|
||||
# TokensStream warnings
|
||||
msg.bad.octal.literal =\
|
||||
|
|
Загрузка…
Ссылка в новой задаче