зеркало из https://github.com/mozilla/gecko-dev.git
Optimizing name access: since top scope can not be NativeWith or NativeCall, it is possible to avoid thisObj checks for name-as-function access and "with" statement and XML object checks.
This commit is contained in:
Родитель
ddcaeb0996
Коммит
835abeb4b1
|
@ -1662,71 +1662,109 @@ public class ScriptRuntime {
|
||||||
/**
|
/**
|
||||||
* Looks up a name in the scope chain and returns its value.
|
* Looks up a name in the scope chain and returns its value.
|
||||||
*/
|
*/
|
||||||
public static Object name(Context cx, Scriptable scopeChain, String id)
|
public static Object name(Context cx, Scriptable scope, String name)
|
||||||
{
|
{
|
||||||
return name(cx, scopeChain, id, false);
|
Scriptable parent = scope.getParentScope();
|
||||||
|
if (parent == null) {
|
||||||
|
Object result = topScopeName(cx, scope, name);
|
||||||
|
if (result == Scriptable.NOT_FOUND) {
|
||||||
|
throw notFoundError(scope, name);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object name(Context cx, Scriptable scopeChain, String id,
|
return nameOrFunction(cx, scope, parent, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object nameOrFunction(Context cx, Scriptable scope,
|
||||||
|
Scriptable parentScope, String name,
|
||||||
boolean asFunctionCall)
|
boolean asFunctionCall)
|
||||||
{
|
{
|
||||||
Scriptable scope = scopeChain;
|
|
||||||
XMLObject firstXMLObject = null;
|
|
||||||
Object result;
|
Object result;
|
||||||
|
Scriptable thisObj = scope; // It is used only if asFunctionCall==true.
|
||||||
|
|
||||||
|
XMLObject firstXMLObject = null;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (scope instanceof NativeWith) {
|
if (scope instanceof NativeWith) {
|
||||||
Scriptable withObj = scope.getPrototype();
|
Scriptable withObj = scope.getPrototype();
|
||||||
if (withObj instanceof XMLObject) {
|
if (withObj instanceof XMLObject) {
|
||||||
XMLObject xmlObj = (XMLObject)withObj;
|
XMLObject xmlObj = (XMLObject)withObj;
|
||||||
if (xmlObj.ecmaHas(cx, id)) {
|
if (xmlObj.ecmaHas(cx, name)) {
|
||||||
result = xmlObj.ecmaGet(cx, id);
|
// function this should be the target object of with
|
||||||
|
thisObj = xmlObj;
|
||||||
|
result = xmlObj.ecmaGet(cx, name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (firstXMLObject == null) {
|
if (firstXMLObject == null) {
|
||||||
firstXMLObject = xmlObj;
|
firstXMLObject = xmlObj;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = ScriptableObject.getProperty(withObj, id);
|
result = ScriptableObject.getProperty(withObj, name);
|
||||||
if (result != Scriptable.NOT_FOUND) {
|
if (result != Scriptable.NOT_FOUND) {
|
||||||
|
// function this should be the target object of with
|
||||||
|
thisObj = withObj;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (scope instanceof NativeCall) {
|
||||||
|
// NativeCall does not prototype chain and Scriptable.get
|
||||||
|
// can be called directly.
|
||||||
|
result = scope.get(name, scope);
|
||||||
|
if (result != Scriptable.NOT_FOUND) {
|
||||||
|
if (asFunctionCall) {
|
||||||
|
// ECMA 262 requires that this for nested funtions
|
||||||
|
// should be top scope
|
||||||
|
thisObj = ScriptableObject.
|
||||||
|
getTopLevelScope(parentScope);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result = ScriptableObject.getProperty(scope, id);
|
// Can happen if Rhino embedding decided that nested
|
||||||
|
// scopes are useful for what ever reasons.
|
||||||
|
result = ScriptableObject.getProperty(scope, name);
|
||||||
if (result != Scriptable.NOT_FOUND) {
|
if (result != Scriptable.NOT_FOUND) {
|
||||||
|
thisObj = scope;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scope = scope.getParentScope();
|
scope = parentScope;
|
||||||
if (scope == null) {
|
parentScope = parentScope.getParentScope();
|
||||||
if (firstXMLObject != null) {
|
if (parentScope == null) {
|
||||||
// The name was not found, but we did find an XML object in
|
result = topScopeName(cx, scope, name);
|
||||||
//the scope chain. The result should be an empty XMLList
|
if (result == Scriptable.NOT_FOUND) {
|
||||||
result = firstXMLObject.ecmaGet(cx, id);
|
if (firstXMLObject == null || asFunctionCall) {
|
||||||
|
throw notFoundError(scope, name);
|
||||||
|
}
|
||||||
|
// The name was not found, but we did find an XML
|
||||||
|
// object in the scope chain and we are looking for name,
|
||||||
|
// not function. The result should be an empty XMLList
|
||||||
|
// in name context.
|
||||||
|
result = firstXMLObject.ecmaGet(cx, name);
|
||||||
|
}
|
||||||
|
// For top scope thisObj for functions is always scope itself.
|
||||||
|
thisObj = scope;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
throw notFoundError(scopeChain, id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (asFunctionCall) {
|
if (asFunctionCall) {
|
||||||
if (!(result instanceof Function)) {
|
if (!(result instanceof Function)) {
|
||||||
throw notFunctionError(result, id);
|
throw notFunctionError(result, name);
|
||||||
}
|
|
||||||
Scriptable thisObj = scope;
|
|
||||||
if (thisObj.getParentScope() != null) {
|
|
||||||
// Check for with and activation:
|
|
||||||
while (thisObj instanceof NativeWith) {
|
|
||||||
thisObj = thisObj.getPrototype();
|
|
||||||
}
|
|
||||||
if (thisObj instanceof NativeCall) {
|
|
||||||
thisObj = ScriptableObject.getTopLevelScope(thisObj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
storeScriptable(cx, thisObj);
|
storeScriptable(cx, thisObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Object topScopeName(Context cx, Scriptable scope,
|
||||||
|
String name)
|
||||||
|
{
|
||||||
|
return ScriptableObject.getProperty(scope, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the object in the scope chain that has a given property.
|
* Returns the object in the scope chain that has a given property.
|
||||||
*
|
*
|
||||||
|
@ -1743,8 +1781,10 @@ public class ScriptRuntime {
|
||||||
public static Scriptable bind(Context cx, Scriptable scope, String id)
|
public static Scriptable bind(Context cx, Scriptable scope, String id)
|
||||||
{
|
{
|
||||||
Scriptable firstXMLObject = null;
|
Scriptable firstXMLObject = null;
|
||||||
do {
|
Scriptable parent = scope.getParentScope();
|
||||||
if (scope instanceof NativeWith) {
|
childScopesChecks: if (parent != null) {
|
||||||
|
// Check for possibly nested "with" scopes first
|
||||||
|
while (scope instanceof NativeWith) {
|
||||||
Scriptable withObj = scope.getPrototype();
|
Scriptable withObj = scope.getPrototype();
|
||||||
if (withObj instanceof XMLObject) {
|
if (withObj instanceof XMLObject) {
|
||||||
XMLObject xmlObject = (XMLObject)withObj;
|
XMLObject xmlObject = (XMLObject)withObj;
|
||||||
|
@ -1759,21 +1799,30 @@ public class ScriptRuntime {
|
||||||
return withObj;
|
return withObj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
scope = parent;
|
||||||
|
parent = parent.getParentScope();
|
||||||
|
if (parent == null) {
|
||||||
|
break childScopesChecks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
if (ScriptableObject.hasProperty(scope, id)) {
|
if (ScriptableObject.hasProperty(scope, id)) {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
scope = parent;
|
||||||
|
parent = parent.getParentScope();
|
||||||
|
if (parent == null) {
|
||||||
|
break childScopesChecks;
|
||||||
}
|
}
|
||||||
scope = scope.getParentScope();
|
}
|
||||||
} while (scope != null);
|
}
|
||||||
|
if (ScriptableObject.hasProperty(scope, id)) {
|
||||||
// Nothing was found
|
return scope;
|
||||||
if (firstXMLObject != null) {
|
}
|
||||||
// XML objects always bind so return it if it was found
|
// Nothing was found, but since XML objects always bind
|
||||||
|
// return one if found
|
||||||
return firstXMLObject;
|
return firstXMLObject;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Scriptable getThis(Scriptable base) {
|
public static Scriptable getThis(Scriptable base) {
|
||||||
while (base instanceof NativeWith)
|
while (base instanceof NativeWith)
|
||||||
|
@ -1945,8 +1994,24 @@ public class ScriptRuntime {
|
||||||
Context cx,
|
Context cx,
|
||||||
Scriptable scope)
|
Scriptable scope)
|
||||||
{
|
{
|
||||||
|
Scriptable parent = scope.getParentScope();
|
||||||
|
if (parent == null) {
|
||||||
|
Object result = topScopeName(cx, scope, name);
|
||||||
|
if (!(result instanceof Function)) {
|
||||||
|
if (result == Scriptable.NOT_FOUND) {
|
||||||
|
throw notFoundError(scope, name);
|
||||||
|
} else {
|
||||||
|
throw notFunctionError(result, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Top scope is not NativeWith or NativeCall => thisObj == scope
|
||||||
|
Scriptable thisObj = scope;
|
||||||
|
storeScriptable(cx, thisObj);
|
||||||
|
return (Function)result;
|
||||||
|
}
|
||||||
|
|
||||||
// name will call storeScriptable(cx, thisObj);
|
// name will call storeScriptable(cx, thisObj);
|
||||||
return (Function)name(cx, scope, name, true);
|
return (Function)nameOrFunction(cx, scope, parent, name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче