Remove deprecated FlattenedObject.

Patch from Igor:
The 2 attached patches allow to avoid wrapping of array indexes to Double object
when Interpreter knows that the index is an integer number. It speed up array
benchmark by 5-10%

array_access.diff adds to ScriptRuntime getStrIdElem and setStrIdElem to get/set
properties which known to be strings plus it modifies NativeArray to use these methods.

interpreter.diff contains the Interpreter modifications to call get/setElem for
integer or string properties when the property type is known for sure.
This commit is contained in:
nboyd%atg.com 2001-10-17 12:59:02 +00:00
Родитель 1bc0630719
Коммит 250051383e
4 изменённых файлов: 121 добавлений и 417 удалений

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

@ -1,341 +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 oqr
* 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):
* Norris Boyd
* 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.Hashtable;
import java.util.Enumeration;
/**
* Manipulate a Scriptable object as if its prototype chain were flattened.
* <p>
* This class has been deprecated in favor of the static methods
* <code>getProperty</code>, <code>putProperty</code>, and
* <code>deleteProperty</code> of ScripableObject. Those methods provide the
* same functionality without the confusing and inefficient need to construct
* a new object instance.
*
* @see org.mozilla.javascript.ScriptableObject
* @deprecated
* @author Norris Boyd
*/
public class FlattenedObject {
/**
* Construct a new FlattenedObject.
*
* @param object the object to be viewed with flattened properties
* @deprecated
*/
public FlattenedObject(Scriptable object) {
this.obj = object;
}
/**
* Get the associated Scriptable object.
* @deprecated
*/
public Scriptable getObject() {
return obj;
}
/**
* Determine if a property exists in an object.
*
* This is a more convenient (and less efficient) form than
* <code>Scriptable.has()</code>.
* It returns true if and only if the property
* exists in this object or any of the objects in its prototype
* chain.
*
* @param id the property index, which may be either a String or a
* Number
* @return true if and only if the property exists in the prototype
* chain
* @see org.mozilla.javascript.Scriptable#has
* @deprecated As of 1.5R2, replaced by ScriptableObject.getProperty
*/
public boolean hasProperty(Object id) {
String stringId = ScriptRuntime.toString(id);
String s = ScriptRuntime.getStringId(stringId);
if (s == null)
return getBase(obj, ScriptRuntime.getIntId(stringId)) != null;
return getBase(obj, s) != null;
}
/**
* Get a property of an object.
* <p>
* This is a more convenient (and less efficient) form than
* <code>Scriptable.get()</code>. It corresponds exactly to the
* expression <code>obj[id]</code> in JavaScript. This method
* will traverse the prototype chain of an object to find the
* property.<p>
*
* If the property does not exist in the object or its prototype
* chain, the undefined value will be returned.
*
* @param id the property index; can be a String or a Number; the
* String may contain characters representing a number
* @return the value of the property or the undefined value
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.Context#getUndefinedValue
* @deprecated As of 1.5R2, replaced by ScriptableObject.getProperty
*/
public Object getProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
int index = s == null ? ScriptRuntime.getIntId(id) : 0;
Scriptable m = obj;
Object result;
for(;;) {
result = s == null ? m.get(index, obj) : m.get(s, obj);
if (result != Scriptable.NOT_FOUND)
break;
m = m.getPrototype();
if (m == null)
return Undefined.instance;
}
if (result instanceof Scriptable)
return new FlattenedObject((Scriptable) result);
return result;
}
/**
* Set a property of an object.
*
* This is a more convenient (and less efficient) form than that
* provided in Scriptable. It corresponds exactly to the
* expression <code>obj[id] = val</code> in JavaScript.<p>
*
* @param id the property index, which may be either a String or
* a Number
* @param value the value of the property
* @see org.mozilla.javascript.Scriptable#put
* @deprecated As of 1.5R2, replaced by ScriptableObject.putProperty
*/
public void putProperty(Object id, Object value) {
String s = ScriptRuntime.getStringId(id);
if (value instanceof FlattenedObject)
value = ((FlattenedObject) value).getObject();
Scriptable x;
if (s == null) {
int index = ScriptRuntime.getIntId(id);
x = getBase(obj, index);
if (x == null)
x = obj;
x.put(index, obj, value);
return;
}
x = getBase(obj, s);
if (x == null)
x = obj;
x.put(s, obj, value);
}
/**
* Remove a property.
*
* This method provides the functionality of the <code>delete</code>
* operator in JavaScript.
*
* @param id the property index, which may be either a String or
* a Number
* @return true if the property didn't exist, or existed and was removed
* @see org.mozilla.javascript.Scriptable#delete
* @deprecated as of 1.5R2, replaced by ScriptableObject.deleteProperty
*/
public boolean deleteProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
if (s == null) {
int index = ScriptRuntime.getIntId(id);
Scriptable base = getBase(obj, index);
if (base == null)
return true;
base.delete(index);
return !base.has(index, base);
}
Scriptable base = getBase(obj, s);
if (base == null)
return true;
base.delete(s);
return !base.has(s, base);
}
/**
* Return an array that contains the ids of the properties.
*
* <p>This method will walk the prototype chain and collect the
* ids of all objects in the prototype chain.<p>
*
* If an id appears in more than one object in the prototype chain,
* it will only be in the array once. (So all the entries in the
* array will be unique respective to equals().)
*
* @see org.mozilla.javascript.Scriptable#getIds
* @deprecated
*/
public Object[] getIds() {
Hashtable h = new Hashtable(11);
Scriptable m = obj;
while (m != null) {
Object[] e = m.getIds();
for (int i=0; i < e.length; i++) {
h.put(e[i], Boolean.TRUE);
}
m = m.getPrototype();
}
Enumeration keys = h.keys();
Object elem;
Object[] result = new Object[h.size()];
int index = 0;
while (keys.hasMoreElements()) {
elem = keys.nextElement();
result[index++] = elem;
}
return result;
}
/**
* Consider this object to be a function, and call it.
*
* @param cx the current Context for this thread
* @param thisObj the JavaScript 'this' for the call
* @param args the arguments for the call
* @return the result of the JavaScript function call
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the function
* @see org.mozilla.javascript.Function#call
* @deprecated
*/
public Object call(Context cx, Scriptable thisObj, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.call(cx, obj, thisObj, args, (Function) obj);
}
/**
* Consider this object to be a function, and invoke it as a
* constructor call.
*
* @param cx the current Context for this thread
* @param args the arguments for the constructor call
* @return the allocated object
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the constructor
* @see org.mozilla.javascript.Function#construct
* @deprecated
*/
public Scriptable construct(Context cx, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.newObject(cx, obj, args, null);
}
/**
* Get the property indicated by the id, and invoke it with the
* specified arguments.
* <p>
* For example, for a FlattenedObject <code>obj</code>,
* and a Java array <code>a</code> consisting of a single string
* <code>"hi"</code>, the call <pre>
* obj.callMethod("m", a)</pre>
* is equivalent to the JavaScript code <code>obj.m("hi")</code>.<p>
*
* If the property is not found or is not a function, an
* exception will be thrown.
*
* @param id the Number or String to use to find the function property
* to call
* @param args the arguments for the constructor call
* @return the result of the call
* @exception PropertyException if the designated property
* was not found
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the method
* @see org.mozilla.javascript.Function#call
* @deprecated
*/
public Object callMethod(Object id, Object[] args)
throws PropertyException,
NotAFunctionException,
JavaScriptException
{
if (!hasProperty(id)) {
throw PropertyException.withMessage0("msg.prop.not.found");
}
Object o = getProperty(id);
if (o instanceof FlattenedObject)
return ((FlattenedObject) o).call(Context.getContext(), obj, args);
throw new NotAFunctionException();
}
/****** End of API *******/
private static Scriptable getBase(Scriptable obj, String s) {
Scriptable m = obj;
while (m != null) {
if (m.has(s, obj))
return m;
m = m.getPrototype();
}
return null;
}
private static Scriptable getBase(Scriptable obj, int index) {
Scriptable m = obj;
while (m != null) {
if (m.has(index, obj))
return m;
m = m.getPrototype();
}
return null;
}
private Scriptable obj;
}

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

@ -1139,7 +1139,7 @@ public class Interpreter extends LabelTable {
} }
private static int getShort(byte[] iCode, int pc) { private static int getShort(byte[] iCode, int pc) {
return (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF); return (iCode[pc] << 8) | (iCode[pc + 1] & 0xFF);
} }
private static int getInt(byte[] iCode, int pc) { private static int getInt(byte[] iCode, int pc) {
@ -1821,25 +1821,12 @@ public class Interpreter extends LabelTable {
= ScriptRuntime.setProp(lhs, name, rhs, scope); = ScriptRuntime.setProp(lhs, name, rhs, scope);
break; break;
case TokenStream.GETELEM : case TokenStream.GETELEM :
id = stack[stackTop]; do_getElem(stack, sDbl, stackTop, scope);
if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);
--stackTop; --stackTop;
lhs = stack[stackTop];
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
stack[stackTop]
= ScriptRuntime.getElem(lhs, id, scope);
break; break;
case TokenStream.SETELEM : case TokenStream.SETELEM :
rhs = stack[stackTop]; do_setElem(stack, sDbl, stackTop, scope);
if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]); stackTop -= 2;
--stackTop;
id = stack[stackTop];
if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);
--stackTop;
lhs = stack[stackTop];
if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);
stack[stackTop]
= ScriptRuntime.setElem(lhs, id, rhs, scope);
break; break;
case TokenStream.PROPINC : case TokenStream.PROPINC :
name = (String)stack[stackTop]; name = (String)stack[stackTop];
@ -2376,8 +2363,6 @@ public class Interpreter extends LabelTable {
} }
} }
private static boolean do_eq(Object[] stack, double[] stackDbl, private static boolean do_eq(Object[] stack, double[] stackDbl,
int stackTop) int stackTop)
{ {
@ -2460,6 +2445,64 @@ public class Interpreter extends LabelTable {
return result; return result;
} }
private static void do_getElem(Object[] stack, double[] stackDbl,
int stackTop, Scriptable scope)
{
Object lhs = stack[stackTop - 1];
if (lhs == DBL_MRK) lhs = doubleWrap(stackDbl[stackTop - 1]);
Object result;
Object id = stack[stackTop];
if (id != DBL_MRK) {
result = ScriptRuntime.getElem(lhs, id, scope);
}
else {
Scriptable obj = (lhs instanceof Scriptable)
? (Scriptable)lhs
: ScriptRuntime.toObject(scope, lhs);
double val = stackDbl[stackTop];
int index = (int)val;
if (index == val) {
result = ScriptRuntime.getElem(obj, index);
}
else {
String s = ScriptRuntime.toString(val);
result = ScriptRuntime.getStrIdElem(obj, s);
}
}
stack[stackTop - 1] = result;
}
private static void do_setElem(Object[] stack, double[] stackDbl,
int stackTop, Scriptable scope)
{
Object rhs = stack[stackTop];
if (rhs == DBL_MRK) rhs = doubleWrap(stackDbl[stackTop]);
Object lhs = stack[stackTop - 2];
if (lhs == DBL_MRK) lhs = doubleWrap(stackDbl[stackTop - 2]);
Object result;
Object id = stack[stackTop - 1];
if (id != DBL_MRK) {
result = ScriptRuntime.setElem(lhs, id, rhs, scope);
}
else {
Scriptable obj = (lhs instanceof Scriptable)
? (Scriptable)lhs
: ScriptRuntime.toObject(scope, lhs);
double val = stackDbl[stackTop - 1];
int index = (int)val;
if (index == val) {
result = ScriptRuntime.setElem(obj, index, rhs);
}
else {
String s = ScriptRuntime.toString(val);
result = ScriptRuntime.setStrIdElem(obj, s, rhs, scope);
}
}
stack[stackTop - 2] = result;
}
private static Object[] getArgsArray(Object[] stack, double[] sDbl, private static Object[] getArgsArray(Object[] stack, double[] sDbl,
int stackTop, int count) int stackTop, int count)
{ {

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

@ -419,7 +419,7 @@ public class NativeArray extends IdScriptable {
private static Object getElem(Scriptable target, long index) { private static Object getElem(Scriptable target, long index) {
if (index > Integer.MAX_VALUE) { if (index > Integer.MAX_VALUE) {
String id = Long.toString(index); String id = Long.toString(index);
return ScriptRuntime.getElem(target, id, target); return ScriptRuntime.getStrIdElem(target, id);
} else { } else {
return ScriptRuntime.getElem(target, (int)index); return ScriptRuntime.getElem(target, (int)index);
} }
@ -428,7 +428,7 @@ public class NativeArray extends IdScriptable {
private static void setElem(Scriptable target, long index, Object value) { private static void setElem(Scriptable target, long index, Object value) {
if (index > Integer.MAX_VALUE) { if (index > Integer.MAX_VALUE) {
String id = Long.toString(index); String id = Long.toString(index);
ScriptRuntime.setElem(target, id, value, target); ScriptRuntime.setStrIdElem(target, id, value, target);
} else { } else {
ScriptRuntime.setElem(target, (int)index, value); ScriptRuntime.setElem(target, (int)index, value);
} }
@ -482,8 +482,7 @@ public class NativeArray extends IdScriptable {
if (!iterating) { if (!iterating) {
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
if (i > 0) if (i > 0) result.append(separator);
result.append(separator);
Object elem = getElem(thisObj, i); Object elem = getElem(thisObj, i);
if (elem == null || elem == Undefined.instance) { if (elem == null || elem == Undefined.instance) {
haslast = false; haslast = false;
@ -492,13 +491,13 @@ public class NativeArray extends IdScriptable {
haslast = true; haslast = true;
if (elem instanceof String) { if (elem instanceof String) {
String s = (String)elem;
if (toSource) { if (toSource) {
result.append('\"'); result.append('\"');
result.append(ScriptRuntime.escapeString result.append(ScriptRuntime.escapeString(s));
(ScriptRuntime.toString(elem)));
result.append('\"'); result.append('\"');
} else { } else {
result.append(ScriptRuntime.toString(elem)); result.append(s);
} }
} else { } else {
/* wrap changes to cx.iterating in a try/finally /* wrap changes to cx.iterating in a try/finally

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

@ -932,7 +932,7 @@ public class ScriptRuntime {
index = (int) d; index = (int) d;
s = ((double) index) == d ? null : toString(id); s = ((double) index) == d ? null : toString(id);
} else { } else {
s = toString(id); s = (id instanceof String) ? (String)id : toString(id);
long indexTest = indexFromString(s); long indexTest = indexFromString(s);
if (indexTest >= 0) { if (indexTest >= 0) {
index = (int)indexTest; index = (int)indexTest;
@ -941,30 +941,16 @@ public class ScriptRuntime {
index = 0; index = 0;
} }
} }
Scriptable start = obj instanceof Scriptable Scriptable start = obj instanceof Scriptable
? (Scriptable) obj ? (Scriptable) obj
: toObject(scope, obj); : toObject(scope, obj);
Scriptable m = start;
if (s != null) { if (s != null) {
if (s.equals("__proto__")) return getStrIdElem(start, s);
return start.getPrototype();
if (s.equals("__parent__"))
return start.getParentScope();
while (m != null) {
Object result = m.get(s, start);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
}
return Undefined.instance;
} }
while (m != null) { else {
Object result = m.get(index, start); return getElem(start, index);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
} }
return Undefined.instance;
} }
@ -972,8 +958,7 @@ public class ScriptRuntime {
* A cheaper and less general version of the above for well-known argument * A cheaper and less general version of the above for well-known argument
* types. * types.
*/ */
public static Object getElem(Scriptable obj, int index) public static Object getElem(Scriptable obj, int index) {
{
Scriptable m = obj; Scriptable m = obj;
while (m != null) { while (m != null) {
Object result = m.get(index, obj); Object result = m.get(index, obj);
@ -984,6 +969,24 @@ public class ScriptRuntime {
return Undefined.instance; return Undefined.instance;
} }
static Object getStrIdElem(Scriptable obj, String id) {
int l = id.length();
if (l == 9) {
if (id.equals("__proto__")) { return obj.getPrototype(); }
}
else if (l == 10) {
if (id.equals("__parent__")) { return obj.getParentScope(); }
}
Scriptable m = obj;
while (m != null) {
Object result = m.get(id, obj);
if (result != Scriptable.NOT_FOUND)
return result;
m = m.getPrototype();
}
return Undefined.instance;
}
public static Object setElem(Object obj, Object id, Object value, public static Object setElem(Object obj, Object id, Object value,
Scriptable scope) Scriptable scope)
{ {
@ -994,7 +997,7 @@ public class ScriptRuntime {
index = (int) d; index = (int) d;
s = ((double) index) == d ? null : toString(id); s = ((double) index) == d ? null : toString(id);
} else { } else {
s = toString(id); s = (id instanceof String) ? (String)id : toString(id);
long indexTest = indexFromString(s); long indexTest = indexFromString(s);
if (indexTest >= 0) { if (indexTest >= 0) {
index = (int)indexTest; index = (int)indexTest;
@ -1007,41 +1010,19 @@ public class ScriptRuntime {
Scriptable start = obj instanceof Scriptable Scriptable start = obj instanceof Scriptable
? (Scriptable) obj ? (Scriptable) obj
: toObject(scope, obj); : toObject(scope, obj);
Scriptable m = start;
if (s != null) { if (s != null) {
if (s.equals("__proto__")) return setStrIdElem(start, s, value, scope);
return setProto(obj, value, scope); }
if (s.equals("__parent__")) else {
return setParent(obj, value, scope); return setElem(start, index, value);
}
do {
if (m.has(s, start)) {
m.put(s, start, value);
return value;
}
m = m.getPrototype();
} while (m != null);
start.put(s, start, value);
return value;
}
do {
if (m.has(index, start)) {
m.put(index, start, value);
return value;
}
m = m.getPrototype();
} while (m != null);
start.put(index, start, value);
return value;
} }
/* /*
* A cheaper and less general version of the above for well-known argument * A cheaper and less general version of the above for well-known argument
* types. * types.
*/ */
public static Object setElem(Scriptable obj, int index, Object value) public static Object setElem(Scriptable obj, int index, Object value) {
{
Scriptable m = obj; Scriptable m = obj;
do { do {
if (m.has(index, obj)) { if (m.has(index, obj)) {
@ -1054,6 +1035,28 @@ public class ScriptRuntime {
return value; return value;
} }
static Object setStrIdElem(Scriptable obj, String id, Object value,
Scriptable scope)
{
int l = id.length();
if (l == 9) {
if (id.equals("__proto__")) return setProto(obj, value, scope);
}
else if (l == 10) {
if (id.equals("__parent__")) return setParent(obj, value, scope);
}
Scriptable m = obj;
do {
if (m.has(id, obj)) {
m.put(id, obj, value);
return value;
}
m = m.getPrototype();
} while (m != null);
obj.put(id, obj, value);
return value;
}
/** /**
* The delete operator * The delete operator
* *