diff --git a/js/rhino/examples/Control.java b/js/rhino/examples/Control.java index eefc62d874b..ebc7ecb92a2 100644 --- a/js/rhino/examples/Control.java +++ b/js/rhino/examples/Control.java @@ -72,36 +72,31 @@ public class Control { // ignore } - FlattenedObject global = new FlattenedObject(scope); - - FlattenedObject f = (FlattenedObject) global.getProperty("obj"); + Scriptable obj = (Scriptable) scope.get("obj", scope); // Should print "obj == result" (Since the result of an assignment // expression is the value that was assigned) - System.out.println("obj " + (f.getObject() == result ? "==" : "!=") + + System.out.println("obj " + (obj == result ? "==" : "!=") + " result"); - // Should print "f.a == 1" - System.out.println("f.a == " + f.getProperty("a")); + // Should print "obj.a == 1" + System.out.println("obj.a == " + obj.get("a", obj)); - FlattenedObject b = (FlattenedObject) f.getProperty("b"); + Scriptable b = (Scriptable) obj.get("b", obj); - // Should print "f.b[0] == x" - System.out.println("f.b[0] == " + b.getProperty(new Integer(0))); + // Should print "obj.b[0] == x" + System.out.println("obj.b[0] == " + b.get(0, b)); - // Should print "f.b[1] == y" - System.out.println("f.b[1] == " + b.getProperty(new Integer(1))); + // Should print "obj.b[1] == y" + System.out.println("obj.b[1] == " + b.get(1, b)); try { // Should print {a:1, b:["x", "y"]} - System.out.println(f.callMethod("toString", new Object[0])); - } catch (PropertyException e) { - // ignore - } catch (NotAFunctionException e) { - // ignore + Function fn = (Function) ScriptableObject.getProperty(obj, "toString"); + System.out.println(fn.call(cx, scope, obj, new Object[0])); } catch (JavaScriptException e) { // ignore - } + } cx.exit(); } diff --git a/js/rhino/org/mozilla/javascript/ClassOutput.java b/js/rhino/org/mozilla/javascript/ClassOutput.java index 1474da17aab..31fa520b231 100644 --- a/js/rhino/org/mozilla/javascript/ClassOutput.java +++ b/js/rhino/org/mozilla/javascript/ClassOutput.java @@ -34,7 +34,7 @@ */ package org.mozilla.javascript; -// API Class +// API class import java.io.*; diff --git a/js/rhino/org/mozilla/javascript/FlattenedObject.java b/js/rhino/org/mozilla/javascript/FlattenedObject.java index c345c6fa408..950f0c9ae9a 100644 --- a/js/rhino/org/mozilla/javascript/FlattenedObject.java +++ b/js/rhino/org/mozilla/javascript/FlattenedObject.java @@ -34,8 +34,6 @@ * file under either the NPL or the GPL. */ -// API class - package org.mozilla.javascript; import java.util.Hashtable; @@ -44,19 +42,13 @@ import java.util.Enumeration; /** * Manipulate a Scriptable object as if its prototype chain were flattened. *

- * Compared to the Scriptable interface, FlattenedObject provides a view of - * Scriptable objects that is easier to use and more closely matches a script - * writer's view of a JavaScript object.

+ * This class has been deprecated in favor of the static methods + * getProperty, putProperty, and + * deleteProperty. Those methods provide the + * same functionality without the confusing and inefficient need to construct + * a new object instance. * - * A FlattenedObject is "flattened" in the sense that multiple objects in a - * prototype chain appear to have their properties all appear in the - * FlattenedObject.

- * - * Another convenience provided by Flattened object is the ability to access - * properties by a single java.lang.Object id. This id is then converted into - * a String or an int before methods of the Scriptable object are called. - * - * @see org.mozilla.javascript.Scriptable + * @see org.mozilla.javascript.ScriptableObject * * @author Norris Boyd */ @@ -67,6 +59,7 @@ 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; @@ -74,6 +67,7 @@ public class FlattenedObject { /** * Get the associated Scriptable object. + * @deprecated */ public Scriptable getObject() { return obj; @@ -93,6 +87,7 @@ public class FlattenedObject { * @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); @@ -119,6 +114,7 @@ public class FlattenedObject { * @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); @@ -149,6 +145,7 @@ public class FlattenedObject { * 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); @@ -179,6 +176,7 @@ public class FlattenedObject { * 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); @@ -208,6 +206,7 @@ public class FlattenedObject { * array will be unique respective to equals().) * * @see org.mozilla.javascript.Scriptable#getIds + * @deprecated */ public Object[] getIds() { Hashtable h = new Hashtable(11); @@ -241,6 +240,7 @@ public class FlattenedObject { * @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, @@ -263,6 +263,7 @@ public class FlattenedObject { * @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, @@ -297,6 +298,7 @@ public class FlattenedObject { * @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, diff --git a/js/rhino/org/mozilla/javascript/JavaAdapter.java b/js/rhino/org/mozilla/javascript/JavaAdapter.java index 7c5c559e235..848e3c2b7be 100644 --- a/js/rhino/org/mozilla/javascript/JavaAdapter.java +++ b/js/rhino/org/mozilla/javascript/JavaAdapter.java @@ -214,7 +214,8 @@ public class JavaAdapter extends ScriptableObject { Scriptable p = (Scriptable) f; if (!(p instanceof Function)) continue; - length = (int) Context.toNumber(getProperty(p, "length")); + length = (int) Context.toNumber( + ScriptableObject.getProperty(p, "length")); } else if (f instanceof FunctionNode) { length = ((FunctionNode) f).getVariableTable().getParameterCount(); } else { @@ -771,24 +772,6 @@ public class JavaAdapter extends ScriptableObject { return sb; } - /** - * Looks up a property of a scriptable object, searching the entire prototype - * chain. Works like FlattenedObject.getProperty() without the overhead. - */ - private static Object getProperty(Scriptable obj, String id) { - Scriptable m = obj; - Object result = null; - for(;;) { - result = m.get(id, obj); - if (result != Scriptable.NOT_FOUND) - break; - m = m.getPrototype(); - if (m == null) - return Undefined.instance; - } - return result; - } - static final class MyClassLoader extends ClassLoader { public Class defineClass(String name, byte data[]) { return super.defineClass(name, data, 0, data.length); diff --git a/js/rhino/org/mozilla/javascript/NativeFunction.java b/js/rhino/org/mozilla/javascript/NativeFunction.java index e2a9e300976..e2fc45ed071 100644 --- a/js/rhino/org/mozilla/javascript/NativeFunction.java +++ b/js/rhino/org/mozilla/javascript/NativeFunction.java @@ -115,13 +115,9 @@ public class NativeFunction extends ScriptableObject implements Function { * */ public boolean hasInstance(Scriptable instance) { - FlattenedObject flat = new FlattenedObject(this); - Object protoProp = flat.getProperty("prototype"); - if (protoProp instanceof FlattenedObject) { - protoProp = ((FlattenedObject)protoProp).getObject(); - if (protoProp != Undefined.instance) - return ScriptRuntime.jsDelegatesTo(instance, - (Scriptable)protoProp); + Object protoProp = ScriptableObject.getProperty(this, "prototype"); + if (protoProp instanceof Scriptable && protoProp != Undefined.instance) { + return ScriptRuntime.jsDelegatesTo(instance, (Scriptable)protoProp); } Object[] args = { names[0] }; String m = ScriptRuntime.getMessage("msg.instanceof.bad.prototype", diff --git a/js/rhino/org/mozilla/javascript/NativeJavaObject.java b/js/rhino/org/mozilla/javascript/NativeJavaObject.java index 4fc3fbe0107..226900183f3 100644 --- a/js/rhino/org/mozilla/javascript/NativeJavaObject.java +++ b/js/rhino/org/mozilla/javascript/NativeJavaObject.java @@ -183,8 +183,6 @@ public class NativeJavaObject implements Scriptable, Wrapper { // Just abandon conversion from JSObject } } - if (cls == ScriptRuntime.ClassClass) - return NativeJavaClass.wrap(scope, (Class) obj); return new NativeJavaObject(scope, obj, staticType); } diff --git a/js/rhino/org/mozilla/javascript/ScriptRuntime.java b/js/rhino/org/mozilla/javascript/ScriptRuntime.java index 9911f87194d..b1b4e30f106 100644 --- a/js/rhino/org/mozilla/javascript/ScriptRuntime.java +++ b/js/rhino/org/mozilla/javascript/ScriptRuntime.java @@ -1059,10 +1059,11 @@ public class ScriptRuntime { * method doesn't return a value. */ public static Object delete(Object obj, Object id) { - if (!(obj instanceof Scriptable)) - return Boolean.TRUE; - FlattenedObject f = new FlattenedObject((Scriptable) obj); - return f.deleteProperty(id) ? Boolean.TRUE : Boolean.FALSE; + String s = getStringId(id); + boolean result = s != null + ? ScriptableObject.deleteProperty((Scriptable) obj, s) + : ScriptableObject.deleteProperty((Scriptable) obj, getIntId(id)); + return result ? Boolean.TRUE : Boolean.FALSE; } /** @@ -1730,9 +1731,11 @@ public class ScriptRuntime { Context.getContext(), "TypeError", ScriptRuntime.getMessage("msg.instanceof.not.object", null), a); } - // OPT do it here rather than making a new FlattenedObject. - FlattenedObject rhs = new FlattenedObject((Scriptable)b); - return rhs.hasProperty(a); + String s = getStringId(a); + Object result = s != null + ? ScriptableObject.getProperty((Scriptable) b, s) + : ScriptableObject.getProperty((Scriptable) b, getIntId(a)); + return result != Scriptable.NOT_FOUND; } public static Boolean cmp_LTB(Object val1, Object val2) { diff --git a/js/rhino/org/mozilla/javascript/Scriptable.java b/js/rhino/org/mozilla/javascript/Scriptable.java index 8dead5ff30d..ff53fb088ee 100644 --- a/js/rhino/org/mozilla/javascript/Scriptable.java +++ b/js/rhino/org/mozilla/javascript/Scriptable.java @@ -45,12 +45,12 @@ package org.mozilla.javascript; * Host system implementors may find it easier to extend the ScriptableObject * class rather than implementing Scriptable when writing host objects. *

- * There are many convenience methods defined in FlattenedObject that make - * accessing objects easier. + * There are many static methods defined in ScriptableObject that perform + * the multiple calls to the Scriptable interface needed in order to + * manipulate properties in prototype chains. *

* * @see org.mozilla.javascript.ScriptableObject - * @see org.mozilla.javascript.FlattenedObject * @author Norris Boyd * @author Nick Thompson * @author Brendan Eich @@ -137,7 +137,7 @@ public interface Scriptable { * @param start the object in which the lookup began * @return true if and only if the named property is found in the object * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#hasProperty + * @see org.mozilla.javascript.ScriptableObject#getProperty */ public boolean has(String name, Scriptable start); @@ -153,7 +153,7 @@ public interface Scriptable { * @param start the object in which the lookup began * @return true if and only if the indexed property is found in the object * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#hasProperty + * @see org.mozilla.javascript.ScriptableObject#getProperty */ public boolean has(int index, Scriptable start); @@ -167,8 +167,8 @@ public interface Scriptable { * get. A class that implements this method may choose * to ignore calls to set certain properties, in which case those * properties are effectively read-only.

- * For a more convenient (and less efficient) form of this method, - * see putProperty in FlattenedObject.

+ * For properties defined in a prototype chain, + * use putProperty in ScriptableObject.

* Note that if a property a is defined in the prototype p * of an object o, then evaluating o.a = 23 will cause * set to be called on the prototype p with @@ -198,7 +198,7 @@ public interface Scriptable { * @param value value to set the property to * @see org.mozilla.javascript.Scriptable#has * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#putProperty + * @see org.mozilla.javascript.ScriptableObject#putProperty */ public void put(String name, Scriptable start, Object value); @@ -217,7 +217,7 @@ public interface Scriptable { * @see org.mozilla.javascript.Scriptable#has * @see org.mozilla.javascript.Scriptable#get * @see org.mozilla.javascript.Scriptable#put(String,Scriptable,Object) - * @see org.mozilla.javascript.FlattenedObject#putProperty + * @see org.mozilla.javascript.ScriptaleObject#putProperty */ public void put(int index, Scriptable start, Object value); @@ -235,11 +235,11 @@ public interface Scriptable { * The property is specified by a String name * as defined for get. *

- * For a more convenient form of this method, - * see deleteProperty in FlattenedObject. + * To delete properties defined in a prototype chain, + * see deleteProperty in ScriptableObject. * @param name the identifier for the property * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#deleteProperty + * @see org.mozilla.javascript.ScriptableObject#deleteProperty */ public void delete(String name); @@ -249,15 +249,15 @@ public interface Scriptable { * The property is specified by an integral index * as defined for get. *

- * For a more convenient form of this method, - * see deleteProperty in FlattenedObject. + * To delete properties defined in a prototype chain, + * see deleteProperty in ScriptableObject. * * Identical to delete(String) except that * an integral index is used to select the property. * * @param index the numeric index for the property * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#deleteProperty + * @see org.mozilla.javascript.ScriptableObject#deleteProperty */ public void delete(int index); diff --git a/js/rhino/org/mozilla/javascript/ScriptableObject.java b/js/rhino/org/mozilla/javascript/ScriptableObject.java index 25863d378f5..0166aadef46 100644 --- a/js/rhino/org/mozilla/javascript/ScriptableObject.java +++ b/js/rhino/org/mozilla/javascript/ScriptableObject.java @@ -524,17 +524,17 @@ public abstract class ScriptableObject implements Scriptable { */ public Object getDefaultValue(Class typeHint) { Object val; - FlattenedObject f = new FlattenedObject(this); Context cx = null; try { for (int i=0; i < 2; i++) { if (typeHint == ScriptRuntime.StringClass ? i == 0 : i == 1) { - Function fun = getFunctionProperty(f, "toString"); - if (fun == null) + Object v = getProperty(this, "toString"); + if (!(v instanceof Function)) continue; + Function fun = (Function) v; if (cx == null) cx = Context.getContext(); - val = fun.call(cx, fun.getParentScope(), f.getObject(), + val = fun.call(cx, fun.getParentScope(), this, ScriptRuntime.emptyArgs); } else { String hint; @@ -566,14 +566,14 @@ public abstract class ScriptableObject implements Scriptable { throw Context.reportRuntimeError( Context.getMessage("msg.invalid.type", args)); } - Function fun = getFunctionProperty(f, "valueOf"); - if (fun == null) + Object v = getProperty(this, "valueOf"); + if (!(v instanceof Function)) continue; + Function fun = (Function) v; Object[] args = { hint }; if (cx == null) cx = Context.getContext(); - val = fun.call(cx, fun.getParentScope(), f.getObject(), - args); + val = fun.call(cx, fun.getParentScope(), this, args); } if (val != null && (val == Undefined.instance || !(val instanceof Scriptable) || @@ -1326,7 +1326,146 @@ public abstract class ScriptableObject implements Scriptable { public boolean isSealed() { return count == -1; } - + + /** + * Gets a named property from an object or any object in its prototype chain. + *

+ * Searches the prototype chain for a property named name. + *

+ * @param obj a JavaScript object + * @param name a property name + * @return the value of a property with name name found in + * obj or any object in its prototype chain, or + * Scriptable.NOT_FOUND if not found + */ + public static Object getProperty(Scriptable obj, String name) { + Scriptable start = obj; + Object result; + do { + result = obj.get(name, start); + if (result != Scriptable.NOT_FOUND) + break; + obj = obj.getPrototype(); + } while (obj != null); + return result; + } + + /** + * Gets an indexed property from an object or any object in its prototype chain. + *

+ * Searches the prototype chain for a property with integral index + * index. Note that if you wish to look for properties with numerical + * but non-integral indicies, you should use getProperty(Scriptable,String) with + * the string value of the index. + *

+ * @param obj a JavaScript object + * @param index an integral index + * @return the value of a property with index index found in + * obj or any object in its prototype chain, or + * Scriptable.NOT_FOUND if not found + */ + public static Object getProperty(Scriptable obj, int index) { + Scriptable start = obj; + Object result; + do { + result = obj.get(index, start); + if (result != Scriptable.NOT_FOUND) + break; + obj = obj.getPrototype(); + } while (obj != null); + return result; + } + + /** + * Puts a named property in an object or in an object in its prototype chain. + *

+ * Seaches for the named property in the prototype chain. If it is found, + * the value of the property is changed. If it is not found, a new + * property is added in obj. + * @param obj a JavaScript object + * @param name a property name + * @param value any JavaScript value accepted by Scriptable.put + */ + public static void putProperty(Scriptable obj, String name, Object value) { + Scriptable base = getBase(obj, name); + if (base == null) + base = obj; + base.put(name, obj, value); + } + + /** + * Puts an indexed property in an object or in an object in its prototype chain. + *

+ * Seaches for the indexed property in the prototype chain. If it is found, + * the value of the property is changed. If it is not found, a new + * property is added in obj. + * @param obj a JavaScript object + * @param index a property index + * @param value any JavaScript value accepted by Scriptable.put + */ + public static void putProperty(Scriptable obj, int index, Object value) { + Scriptable base = getBase(obj, index); + if (base == null) + base = obj; + base.put(index, obj, value); + } + + /** + * Removes the property from an object or its prototype chain. + *

+ * Searches for a property with name in obj or + * its prototype chain. If it is found, the object's delete + * method is called. + * @param obj a JavaScript object + * @param name a property name + * @return true if the property doesn't exist or was successfully removed + */ + public static boolean deleteProperty(Scriptable obj, String name) { + Scriptable base = getBase(obj, name); + if (base == null) + return true; + base.delete(name); + return base.get(name, obj) == NOT_FOUND; + } + + /** + * Removes the property from an object or its prototype chain. + *

+ * Searches for a property with index in obj or + * its prototype chain. If it is found, the object's delete + * method is called. + * @param obj a JavaScript object + * @param index a property index + * @return true if the property doesn't exist or was successfully removed + */ + public static boolean deleteProperty(Scriptable obj, int index) { + Scriptable base = getBase(obj, index); + if (base == null) + return true; + base.delete(index); + return base.get(index, obj) == NOT_FOUND; + } + + 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; + } + /** * Adds a property attribute to all properties. */ @@ -1476,16 +1615,6 @@ public abstract class ScriptableObject implements Scriptable { slots = newSlots; } - private Function getFunctionProperty(FlattenedObject f, String name) { - Object val = f.getProperty(name); - if (val == null || !(val instanceof FlattenedObject)) - return null; - Scriptable s = ((FlattenedObject) val).getObject(); - if (s instanceof Function) - return (Function) s; - return null; - } - private static Hashtable getExclusionList() { if (exclusionList != null) return exclusionList; diff --git a/js/rhino/src/org/mozilla/javascript/ClassOutput.java b/js/rhino/src/org/mozilla/javascript/ClassOutput.java index 1474da17aab..31fa520b231 100644 --- a/js/rhino/src/org/mozilla/javascript/ClassOutput.java +++ b/js/rhino/src/org/mozilla/javascript/ClassOutput.java @@ -34,7 +34,7 @@ */ package org.mozilla.javascript; -// API Class +// API class import java.io.*; diff --git a/js/rhino/src/org/mozilla/javascript/FlattenedObject.java b/js/rhino/src/org/mozilla/javascript/FlattenedObject.java index c345c6fa408..950f0c9ae9a 100644 --- a/js/rhino/src/org/mozilla/javascript/FlattenedObject.java +++ b/js/rhino/src/org/mozilla/javascript/FlattenedObject.java @@ -34,8 +34,6 @@ * file under either the NPL or the GPL. */ -// API class - package org.mozilla.javascript; import java.util.Hashtable; @@ -44,19 +42,13 @@ import java.util.Enumeration; /** * Manipulate a Scriptable object as if its prototype chain were flattened. *

- * Compared to the Scriptable interface, FlattenedObject provides a view of - * Scriptable objects that is easier to use and more closely matches a script - * writer's view of a JavaScript object.

+ * This class has been deprecated in favor of the static methods + * getProperty, putProperty, and + * deleteProperty. Those methods provide the + * same functionality without the confusing and inefficient need to construct + * a new object instance. * - * A FlattenedObject is "flattened" in the sense that multiple objects in a - * prototype chain appear to have their properties all appear in the - * FlattenedObject.

- * - * Another convenience provided by Flattened object is the ability to access - * properties by a single java.lang.Object id. This id is then converted into - * a String or an int before methods of the Scriptable object are called. - * - * @see org.mozilla.javascript.Scriptable + * @see org.mozilla.javascript.ScriptableObject * * @author Norris Boyd */ @@ -67,6 +59,7 @@ 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; @@ -74,6 +67,7 @@ public class FlattenedObject { /** * Get the associated Scriptable object. + * @deprecated */ public Scriptable getObject() { return obj; @@ -93,6 +87,7 @@ public class FlattenedObject { * @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); @@ -119,6 +114,7 @@ public class FlattenedObject { * @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); @@ -149,6 +145,7 @@ public class FlattenedObject { * 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); @@ -179,6 +176,7 @@ public class FlattenedObject { * 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); @@ -208,6 +206,7 @@ public class FlattenedObject { * array will be unique respective to equals().) * * @see org.mozilla.javascript.Scriptable#getIds + * @deprecated */ public Object[] getIds() { Hashtable h = new Hashtable(11); @@ -241,6 +240,7 @@ public class FlattenedObject { * @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, @@ -263,6 +263,7 @@ public class FlattenedObject { * @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, @@ -297,6 +298,7 @@ public class FlattenedObject { * @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, diff --git a/js/rhino/src/org/mozilla/javascript/JavaAdapter.java b/js/rhino/src/org/mozilla/javascript/JavaAdapter.java index 7c5c559e235..848e3c2b7be 100644 --- a/js/rhino/src/org/mozilla/javascript/JavaAdapter.java +++ b/js/rhino/src/org/mozilla/javascript/JavaAdapter.java @@ -214,7 +214,8 @@ public class JavaAdapter extends ScriptableObject { Scriptable p = (Scriptable) f; if (!(p instanceof Function)) continue; - length = (int) Context.toNumber(getProperty(p, "length")); + length = (int) Context.toNumber( + ScriptableObject.getProperty(p, "length")); } else if (f instanceof FunctionNode) { length = ((FunctionNode) f).getVariableTable().getParameterCount(); } else { @@ -771,24 +772,6 @@ public class JavaAdapter extends ScriptableObject { return sb; } - /** - * Looks up a property of a scriptable object, searching the entire prototype - * chain. Works like FlattenedObject.getProperty() without the overhead. - */ - private static Object getProperty(Scriptable obj, String id) { - Scriptable m = obj; - Object result = null; - for(;;) { - result = m.get(id, obj); - if (result != Scriptable.NOT_FOUND) - break; - m = m.getPrototype(); - if (m == null) - return Undefined.instance; - } - return result; - } - static final class MyClassLoader extends ClassLoader { public Class defineClass(String name, byte data[]) { return super.defineClass(name, data, 0, data.length); diff --git a/js/rhino/src/org/mozilla/javascript/NativeFunction.java b/js/rhino/src/org/mozilla/javascript/NativeFunction.java index e2a9e300976..e2fc45ed071 100644 --- a/js/rhino/src/org/mozilla/javascript/NativeFunction.java +++ b/js/rhino/src/org/mozilla/javascript/NativeFunction.java @@ -115,13 +115,9 @@ public class NativeFunction extends ScriptableObject implements Function { * */ public boolean hasInstance(Scriptable instance) { - FlattenedObject flat = new FlattenedObject(this); - Object protoProp = flat.getProperty("prototype"); - if (protoProp instanceof FlattenedObject) { - protoProp = ((FlattenedObject)protoProp).getObject(); - if (protoProp != Undefined.instance) - return ScriptRuntime.jsDelegatesTo(instance, - (Scriptable)protoProp); + Object protoProp = ScriptableObject.getProperty(this, "prototype"); + if (protoProp instanceof Scriptable && protoProp != Undefined.instance) { + return ScriptRuntime.jsDelegatesTo(instance, (Scriptable)protoProp); } Object[] args = { names[0] }; String m = ScriptRuntime.getMessage("msg.instanceof.bad.prototype", diff --git a/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java b/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java index 4fc3fbe0107..226900183f3 100644 --- a/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java +++ b/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java @@ -183,8 +183,6 @@ public class NativeJavaObject implements Scriptable, Wrapper { // Just abandon conversion from JSObject } } - if (cls == ScriptRuntime.ClassClass) - return NativeJavaClass.wrap(scope, (Class) obj); return new NativeJavaObject(scope, obj, staticType); } diff --git a/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java b/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java index 9911f87194d..b1b4e30f106 100644 --- a/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java +++ b/js/rhino/src/org/mozilla/javascript/ScriptRuntime.java @@ -1059,10 +1059,11 @@ public class ScriptRuntime { * method doesn't return a value. */ public static Object delete(Object obj, Object id) { - if (!(obj instanceof Scriptable)) - return Boolean.TRUE; - FlattenedObject f = new FlattenedObject((Scriptable) obj); - return f.deleteProperty(id) ? Boolean.TRUE : Boolean.FALSE; + String s = getStringId(id); + boolean result = s != null + ? ScriptableObject.deleteProperty((Scriptable) obj, s) + : ScriptableObject.deleteProperty((Scriptable) obj, getIntId(id)); + return result ? Boolean.TRUE : Boolean.FALSE; } /** @@ -1730,9 +1731,11 @@ public class ScriptRuntime { Context.getContext(), "TypeError", ScriptRuntime.getMessage("msg.instanceof.not.object", null), a); } - // OPT do it here rather than making a new FlattenedObject. - FlattenedObject rhs = new FlattenedObject((Scriptable)b); - return rhs.hasProperty(a); + String s = getStringId(a); + Object result = s != null + ? ScriptableObject.getProperty((Scriptable) b, s) + : ScriptableObject.getProperty((Scriptable) b, getIntId(a)); + return result != Scriptable.NOT_FOUND; } public static Boolean cmp_LTB(Object val1, Object val2) { diff --git a/js/rhino/src/org/mozilla/javascript/Scriptable.java b/js/rhino/src/org/mozilla/javascript/Scriptable.java index 8dead5ff30d..ff53fb088ee 100644 --- a/js/rhino/src/org/mozilla/javascript/Scriptable.java +++ b/js/rhino/src/org/mozilla/javascript/Scriptable.java @@ -45,12 +45,12 @@ package org.mozilla.javascript; * Host system implementors may find it easier to extend the ScriptableObject * class rather than implementing Scriptable when writing host objects. *

- * There are many convenience methods defined in FlattenedObject that make - * accessing objects easier. + * There are many static methods defined in ScriptableObject that perform + * the multiple calls to the Scriptable interface needed in order to + * manipulate properties in prototype chains. *

* * @see org.mozilla.javascript.ScriptableObject - * @see org.mozilla.javascript.FlattenedObject * @author Norris Boyd * @author Nick Thompson * @author Brendan Eich @@ -137,7 +137,7 @@ public interface Scriptable { * @param start the object in which the lookup began * @return true if and only if the named property is found in the object * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#hasProperty + * @see org.mozilla.javascript.ScriptableObject#getProperty */ public boolean has(String name, Scriptable start); @@ -153,7 +153,7 @@ public interface Scriptable { * @param start the object in which the lookup began * @return true if and only if the indexed property is found in the object * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#hasProperty + * @see org.mozilla.javascript.ScriptableObject#getProperty */ public boolean has(int index, Scriptable start); @@ -167,8 +167,8 @@ public interface Scriptable { * get. A class that implements this method may choose * to ignore calls to set certain properties, in which case those * properties are effectively read-only.

- * For a more convenient (and less efficient) form of this method, - * see putProperty in FlattenedObject.

+ * For properties defined in a prototype chain, + * use putProperty in ScriptableObject.

* Note that if a property a is defined in the prototype p * of an object o, then evaluating o.a = 23 will cause * set to be called on the prototype p with @@ -198,7 +198,7 @@ public interface Scriptable { * @param value value to set the property to * @see org.mozilla.javascript.Scriptable#has * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#putProperty + * @see org.mozilla.javascript.ScriptableObject#putProperty */ public void put(String name, Scriptable start, Object value); @@ -217,7 +217,7 @@ public interface Scriptable { * @see org.mozilla.javascript.Scriptable#has * @see org.mozilla.javascript.Scriptable#get * @see org.mozilla.javascript.Scriptable#put(String,Scriptable,Object) - * @see org.mozilla.javascript.FlattenedObject#putProperty + * @see org.mozilla.javascript.ScriptaleObject#putProperty */ public void put(int index, Scriptable start, Object value); @@ -235,11 +235,11 @@ public interface Scriptable { * The property is specified by a String name * as defined for get. *

- * For a more convenient form of this method, - * see deleteProperty in FlattenedObject. + * To delete properties defined in a prototype chain, + * see deleteProperty in ScriptableObject. * @param name the identifier for the property * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#deleteProperty + * @see org.mozilla.javascript.ScriptableObject#deleteProperty */ public void delete(String name); @@ -249,15 +249,15 @@ public interface Scriptable { * The property is specified by an integral index * as defined for get. *

- * For a more convenient form of this method, - * see deleteProperty in FlattenedObject. + * To delete properties defined in a prototype chain, + * see deleteProperty in ScriptableObject. * * Identical to delete(String) except that * an integral index is used to select the property. * * @param index the numeric index for the property * @see org.mozilla.javascript.Scriptable#get - * @see org.mozilla.javascript.FlattenedObject#deleteProperty + * @see org.mozilla.javascript.ScriptableObject#deleteProperty */ public void delete(int index); diff --git a/js/rhino/src/org/mozilla/javascript/ScriptableObject.java b/js/rhino/src/org/mozilla/javascript/ScriptableObject.java index 25863d378f5..0166aadef46 100644 --- a/js/rhino/src/org/mozilla/javascript/ScriptableObject.java +++ b/js/rhino/src/org/mozilla/javascript/ScriptableObject.java @@ -524,17 +524,17 @@ public abstract class ScriptableObject implements Scriptable { */ public Object getDefaultValue(Class typeHint) { Object val; - FlattenedObject f = new FlattenedObject(this); Context cx = null; try { for (int i=0; i < 2; i++) { if (typeHint == ScriptRuntime.StringClass ? i == 0 : i == 1) { - Function fun = getFunctionProperty(f, "toString"); - if (fun == null) + Object v = getProperty(this, "toString"); + if (!(v instanceof Function)) continue; + Function fun = (Function) v; if (cx == null) cx = Context.getContext(); - val = fun.call(cx, fun.getParentScope(), f.getObject(), + val = fun.call(cx, fun.getParentScope(), this, ScriptRuntime.emptyArgs); } else { String hint; @@ -566,14 +566,14 @@ public abstract class ScriptableObject implements Scriptable { throw Context.reportRuntimeError( Context.getMessage("msg.invalid.type", args)); } - Function fun = getFunctionProperty(f, "valueOf"); - if (fun == null) + Object v = getProperty(this, "valueOf"); + if (!(v instanceof Function)) continue; + Function fun = (Function) v; Object[] args = { hint }; if (cx == null) cx = Context.getContext(); - val = fun.call(cx, fun.getParentScope(), f.getObject(), - args); + val = fun.call(cx, fun.getParentScope(), this, args); } if (val != null && (val == Undefined.instance || !(val instanceof Scriptable) || @@ -1326,7 +1326,146 @@ public abstract class ScriptableObject implements Scriptable { public boolean isSealed() { return count == -1; } - + + /** + * Gets a named property from an object or any object in its prototype chain. + *

+ * Searches the prototype chain for a property named name. + *

+ * @param obj a JavaScript object + * @param name a property name + * @return the value of a property with name name found in + * obj or any object in its prototype chain, or + * Scriptable.NOT_FOUND if not found + */ + public static Object getProperty(Scriptable obj, String name) { + Scriptable start = obj; + Object result; + do { + result = obj.get(name, start); + if (result != Scriptable.NOT_FOUND) + break; + obj = obj.getPrototype(); + } while (obj != null); + return result; + } + + /** + * Gets an indexed property from an object or any object in its prototype chain. + *

+ * Searches the prototype chain for a property with integral index + * index. Note that if you wish to look for properties with numerical + * but non-integral indicies, you should use getProperty(Scriptable,String) with + * the string value of the index. + *

+ * @param obj a JavaScript object + * @param index an integral index + * @return the value of a property with index index found in + * obj or any object in its prototype chain, or + * Scriptable.NOT_FOUND if not found + */ + public static Object getProperty(Scriptable obj, int index) { + Scriptable start = obj; + Object result; + do { + result = obj.get(index, start); + if (result != Scriptable.NOT_FOUND) + break; + obj = obj.getPrototype(); + } while (obj != null); + return result; + } + + /** + * Puts a named property in an object or in an object in its prototype chain. + *

+ * Seaches for the named property in the prototype chain. If it is found, + * the value of the property is changed. If it is not found, a new + * property is added in obj. + * @param obj a JavaScript object + * @param name a property name + * @param value any JavaScript value accepted by Scriptable.put + */ + public static void putProperty(Scriptable obj, String name, Object value) { + Scriptable base = getBase(obj, name); + if (base == null) + base = obj; + base.put(name, obj, value); + } + + /** + * Puts an indexed property in an object or in an object in its prototype chain. + *

+ * Seaches for the indexed property in the prototype chain. If it is found, + * the value of the property is changed. If it is not found, a new + * property is added in obj. + * @param obj a JavaScript object + * @param index a property index + * @param value any JavaScript value accepted by Scriptable.put + */ + public static void putProperty(Scriptable obj, int index, Object value) { + Scriptable base = getBase(obj, index); + if (base == null) + base = obj; + base.put(index, obj, value); + } + + /** + * Removes the property from an object or its prototype chain. + *

+ * Searches for a property with name in obj or + * its prototype chain. If it is found, the object's delete + * method is called. + * @param obj a JavaScript object + * @param name a property name + * @return true if the property doesn't exist or was successfully removed + */ + public static boolean deleteProperty(Scriptable obj, String name) { + Scriptable base = getBase(obj, name); + if (base == null) + return true; + base.delete(name); + return base.get(name, obj) == NOT_FOUND; + } + + /** + * Removes the property from an object or its prototype chain. + *

+ * Searches for a property with index in obj or + * its prototype chain. If it is found, the object's delete + * method is called. + * @param obj a JavaScript object + * @param index a property index + * @return true if the property doesn't exist or was successfully removed + */ + public static boolean deleteProperty(Scriptable obj, int index) { + Scriptable base = getBase(obj, index); + if (base == null) + return true; + base.delete(index); + return base.get(index, obj) == NOT_FOUND; + } + + 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; + } + /** * Adds a property attribute to all properties. */ @@ -1476,16 +1615,6 @@ public abstract class ScriptableObject implements Scriptable { slots = newSlots; } - private Function getFunctionProperty(FlattenedObject f, String name) { - Object val = f.getProperty(name); - if (val == null || !(val instanceof FlattenedObject)) - return null; - Scriptable s = ((FlattenedObject) val).getObject(); - if (s instanceof Function) - return (Function) s; - return null; - } - private static Hashtable getExclusionList() { if (exclusionList != null) return exclusionList;