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:
igor%mir2.org 2004-08-25 09:50:32 +00:00
Родитель ddcaeb0996
Коммит 835abeb4b1
1 изменённых файлов: 107 добавлений и 42 удалений

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

@ -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);
} }
/** /**