diff --git a/js/rhino/org/mozilla/javascript/IdFunction.java b/js/rhino/org/mozilla/javascript/IdFunction.java index 92f40d7d026..e69de29bb2d 100644 --- a/js/rhino/org/mozilla/javascript/IdFunction.java +++ b/js/rhino/org/mozilla/javascript/IdFunction.java @@ -1,286 +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): - * Igor Bukanov - * - * 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. - */ - -// API class - -package org.mozilla.javascript; - -public class IdFunction extends ScriptableObject implements Function -{ - /** Indicates that native implementation was overwritten by script */ - public static final - IdFunction WAS_OVERWRITTEN = new IdFunction(null, "", 0); - - public static final int FUNCTION_ONLY = 0; - - public static final int CONSTRUCTOR_ONLY = 1; - - public static final int FUNCTION_AND_CONSTRUCTOR = 2; - - public static interface Master { - /** 'thisObj' will be null if invoked as constructor, in which case - ** instance of Scriptable should be returned */ - public Object execMethod(int methodId, IdFunction function, - Context cx, Scriptable scope, - Scriptable thisObj, Object[] args) - throws JavaScriptException; - - public int methodArity(int methodId, IdFunction function); - - public Scriptable getParentScope(); - } - - public IdFunction(Master master, String name, int id) { - this.master = master; - this.methodName = name; - this.methodId = id; - } - - /** - ** Primary goal of idTag is to allow to use the same method id in class - ** and its descendants. - */ - public final Object idTag() { - return idTag; - } - - public void setIdTag(Object tag) { - idTag = tag; - } - - public final int functionType() { - return functionType; - } - - public void setFunctionType(int type) { - functionType = type; - } - - public String getClassName() { return "Function"; } - - public boolean has(String name, Scriptable start) { - return nameToId(name) != 0 || super.has(name, start); - } - - public Object get(String name, Scriptable start) { - int id = nameToId(name); - return (0 != id) ? getField(id) : super.get(name, start); - } - - public void put(String name, Scriptable start, Object value) { - if (nameToId(name) == 0) { - super.put(name, start, value); - } - } - - public void delete(String name) { - if (nameToId(name) == 0) { - super.delete(name); - } - } - - /** - * Implements the instanceof operator for JavaScript Function objects. - *

- * - * foo = new Foo();
- * foo instanceof Foo; // true
- *
- * - * @param instance The value that appeared on the LHS of the instanceof - * operator - * @return true if the "prototype" property of "this" appears in - * value's prototype chain - * - */ - public boolean hasInstance(Scriptable instance) { - Object protoProp = ScriptableObject.getProperty(this, "prototype"); - if (protoProp instanceof Scriptable && protoProp != Undefined.instance) - { - return ScriptRuntime.jsDelegatesTo(instance, (Scriptable)protoProp); - } - throw NativeGlobal.typeError1 - ("msg.instanceof.bad.prototype", this.methodName, instance); - } - - public Object call(Context cx, Scriptable scope, Scriptable thisObj, - Object[] args) - throws JavaScriptException - { - if (functionType != CONSTRUCTOR_ONLY) { - return master.execMethod(methodId, this, cx, scope, thisObj, args); - } - else { - return Undefined.instance; - } - } - - public Scriptable construct(Context cx, Scriptable scope, Object[] args) - throws JavaScriptException - { - if (functionType != FUNCTION_ONLY) { - // It is program error not to return Scriptable from constructor - Scriptable result = (Scriptable)master.execMethod(methodId, this, - cx, scope, - null, args); - postConstruction(result); - return result; - } - else { - return Undefined.instance; - } - } - - public Scriptable getPrototype() { - // For native functions this is not called often so it is better - // to run this expensive operation here and not in constructor - return getFunctionPrototype(getParentScope()); - } - - public Scriptable getParentScope() { - Scriptable result = super.getParentScope(); - if (result == null) { - result = master.getParentScope(); - } - return result; - } - - // Copied from NativeFunction - protected Scriptable getClassPrototype() { - Object protoVal = immunePrototypeProperty; - if (protoVal == NOT_FOUND) { - protoVal = super.get("prototype", this); - } - if (!(protoVal instanceof Scriptable) - || protoVal == Undefined.instance) - { - protoVal = getClassPrototype(this, "Object"); - } - return (Scriptable) protoVal; - } - - protected Object toStringForScript(Context cx) { - StringBuffer sb = new StringBuffer(); - sb.append("function "); - sb.append(methodName); - sb.append("() { [native code for "); - if (master instanceof Scriptable) { - Scriptable smaster = (Scriptable)master; - sb.append(smaster.getClassName()); - sb.append('.'); - } - sb.append(methodName); - sb.append(", arity="); - sb.append(getArity()); - sb.append("] }"); - return sb.toString(); - } - - /** Make value as DontEnum, DontDelete, ReadOnly - ** prototype property of this native Function object - ** if not already set - */ - protected void setImmunePrototypeProperty(Object value) { - if (immunePrototypeProperty == NOT_FOUND) { - immunePrototypeProperty = value; - } - } - - private int getArity() { - return master.methodArity(methodId, this); - } - - // Copied from NativeFunction.construct - private void postConstruction(Scriptable newObj) { - if (newObj.getPrototype() == null) { - newObj.setPrototype(getClassPrototype()); - } - if (newObj.getParentScope() == null) { - Scriptable parent = getParentScope(); - if (newObj != parent) { - newObj.setParentScope(parent); - } - } - } - - private Object getField(int fieldId) { - switch (fieldId) { - case ID_ARITY: case ID_LENGTH: - return new Integer(getArity()); - case ID_NAME: - return methodName; - case ID_PROTOTYPE: - return immunePrototypeProperty; - } - return null; - } - - private int nameToId(String s) { - int id = 0; - String guess = null; - switch (s.length()) { - case 4: guess = "name"; id = ID_NAME; break; - case 5: guess = "arity"; id = ID_ARITY; break; - case 6: guess = "length"; id = ID_LENGTH; break; - case 9: - if (immunePrototypeProperty != NOT_FOUND) { - // Try to guess only if immunePrototypeProperty is defined, - // delegate to ScriptableObject otherwise - guess = "prototype"; id = ID_PROTOTYPE; - } - break; - - } - return (guess != null && guess.equals(s)) ? id : 0; - } - - private static final int - ID_ARITY = 1, - ID_LENGTH = 2, - ID_NAME = 3, - ID_PROTOTYPE = 4; - - protected final Master master; - protected final int methodId; - - protected String methodName; - - protected Object idTag; - - protected int functionType = FUNCTION_ONLY; - - // If != NOT_FOUND, represent script-immune prototype property - private Object immunePrototypeProperty = NOT_FOUND; -} diff --git a/js/rhino/org/mozilla/javascript/NativeMath.java b/js/rhino/org/mozilla/javascript/NativeMath.java index 3c732cb5dc6..a56a6d031d9 100644 --- a/js/rhino/org/mozilla/javascript/NativeMath.java +++ b/js/rhino/org/mozilla/javascript/NativeMath.java @@ -46,6 +46,7 @@ public class NativeMath extends ScriptableObject implements IdFunction.Master, ScopeInitializer { public void scopeInit(Context cx, Scriptable scope, boolean sealed) { + sealFunctions = sealed; setPrototype(getObjectPrototype(scope)); setParentScope(scope); if (sealed) { @@ -97,36 +98,29 @@ public class NativeMath extends ScriptableObject } public void put(String name, Scriptable start, Object value) { - if (doOverwrite(name)) { + if (doOverwrite(name, start)) { super.put(name, start, value); } } public void delete(String name) { - if (doOverwrite(name)) { + // Let the super class to throw exceptions for sealed objects + if (isSealed() || doOverwrite(name, this)) { super.delete(name); } } // Return true to invoke put/delete in super class - private boolean doOverwrite(String name) { - if (isSealed()) { - // Let the super class to throw exceptions for sealed objects - return true; - } + private boolean doOverwrite(String name, Scriptable start) { int id = nameToId(name); - if (id > LAST_METHOD_ID) { - // Ignore modifications of read-only Math constants - return false; - } - - if (0 != id) { - if (functionPool[id] != IdFunction.WAS_OVERWRITTEN) { - synchronized (this) { - // Forget default implementation - // Must be synchronized to avoid clearance of overwritten - // mark by another thread running in wrapMethod - functionPool[id] = IdFunction.WAS_OVERWRITTEN; + if (id != 0) { + if (id > LAST_METHOD_ID) { + // Ignore modifications of read-only Math constants + return false; + } + else { + if (this == start) { + overwriteMethod(id); } } } @@ -137,11 +131,23 @@ public class NativeMath extends ScriptableObject synchronized (this) { IdFunction f = functionPool[id]; if (f == null) { - f = functionPool[id] = new IdFunction(this, name, id); + f = new IdFunction(this, name, id); + if (sealFunctions) { f.sealObject(); } + functionPool[id] = f; } return f; } } + + private void overwriteMethod(int id) { + if (functionPool[id] != IdFunction.WAS_OVERWRITTEN) { + // Must be synchronized to avoid clearance of overwritten mark + // by another thread running in wrapMethod + synchronized (this) { + functionPool[id] = IdFunction.WAS_OVERWRITTEN; + } + } + } private Double getField(int fieldId) { switch (fieldId) { @@ -176,39 +182,66 @@ public class NativeMath extends ScriptableObject throws JavaScriptException { switch (methodId) { - case Id_abs: return wrap_dbl(js_abs(to_dbl(args, 0))); - case Id_acos: return wrap_dbl(js_acos(to_dbl(args, 0))); - case Id_asin: return wrap_dbl(js_asin(to_dbl(args, 0))); - case Id_atan: return wrap_dbl(js_atan(to_dbl(args, 0))); - case Id_atan2: return wrap_dbl - (js_atan2(to_dbl(args, 0), to_dbl(args, 1))); - case Id_ceil: return wrap_dbl(js_ceil(to_dbl(args, 0))); - case Id_cos: return wrap_dbl(js_cos(to_dbl(args, 0))); - case Id_exp: return wrap_dbl(js_exp(to_dbl(args, 0))); - case Id_floor: return wrap_dbl(js_floor(to_dbl(args, 0))); - case Id_log: return wrap_dbl(js_log(to_dbl(args, 0))); - case Id_max: return wrap_dbl(js_max(args)); - case Id_min: return wrap_dbl(js_min(args)); - case Id_pow: return wrap_dbl - (js_pow(to_dbl(args, 0), to_dbl(args, 1))); - case Id_random: return wrap_dbl(js_random()); - case Id_round: return wrap_dbl(js_round(to_dbl(args, 0))); - case Id_sin: return wrap_dbl(js_sin(to_dbl(args, 0))); - case Id_sqrt: return wrap_dbl(js_sqrt(to_dbl(args, 0))); - case Id_tan: return wrap_dbl(js_tan(to_dbl(args, 0))); + case Id_abs: return wrap_double + (js_abs(ScriptRuntime.toNumber(args, 0))); + + case Id_acos: return wrap_double + (js_acos(ScriptRuntime.toNumber(args, 0))); + + case Id_asin: return wrap_double + (js_asin(ScriptRuntime.toNumber(args, 0))); + + case Id_atan: return wrap_double + (js_atan(ScriptRuntime.toNumber(args, 0))); + + case Id_atan2: return wrap_double + (js_atan2(ScriptRuntime.toNumber(args, 0), + ScriptRuntime.toNumber(args, 1))); + + case Id_ceil: return wrap_double + (js_ceil(ScriptRuntime.toNumber(args, 0))); + + case Id_cos: return wrap_double + (js_cos(ScriptRuntime.toNumber(args, 0))); + + case Id_exp: return wrap_double + (js_exp(ScriptRuntime.toNumber(args, 0))); + + case Id_floor: return wrap_double + (js_floor(ScriptRuntime.toNumber(args, 0))); + + case Id_log: return wrap_double + (js_log(ScriptRuntime.toNumber(args, 0))); + + case Id_max: return wrap_double + (js_max(args)); + + case Id_min: return wrap_double + (js_min(args)); + + case Id_pow: return wrap_double + (js_pow(ScriptRuntime.toNumber(args, 0), + ScriptRuntime.toNumber(args, 1))); + + case Id_random: return wrap_double + (js_random()); + + case Id_round: return wrap_double + (js_round(ScriptRuntime.toNumber(args, 0))); + + case Id_sin: return wrap_double + (js_sin(ScriptRuntime.toNumber(args, 0))); + + case Id_sqrt: return wrap_double + (js_sqrt(ScriptRuntime.toNumber(args, 0))); + + case Id_tan: return wrap_double + (js_tan(ScriptRuntime.toNumber(args, 0))); } return null; } - private double to_dbl(Object[] args, int index) { - return ScriptRuntime.toNumber(args, index); - } - - private double to_dbl(Object arg) { - return ScriptRuntime.toNumber(arg); - } - - private Double wrap_dbl(double x) { + private Double wrap_double(double x) { return (x == x) ? new Double(x) : ScriptRuntime.NaNobj; } @@ -410,5 +443,7 @@ public class NativeMath extends ScriptableObject // Last accessed function cache private IdFunction lastFunction = IdFunction.WAS_OVERWRITTEN; + + private boolean sealFunctions; } diff --git a/js/rhino/src/org/mozilla/javascript/IdFunction.java b/js/rhino/src/org/mozilla/javascript/IdFunction.java index 92f40d7d026..bcb4736aa89 100644 --- a/js/rhino/src/org/mozilla/javascript/IdFunction.java +++ b/js/rhino/src/org/mozilla/javascript/IdFunction.java @@ -106,7 +106,8 @@ public class IdFunction extends ScriptableObject implements Function } public void delete(String name) { - if (nameToId(name) == 0) { + // Let the super class throw exceptions for sealed objects + if (isSealed() || nameToId(name) == 0) { super.delete(name); } } diff --git a/js/rhino/src/org/mozilla/javascript/NativeMath.java b/js/rhino/src/org/mozilla/javascript/NativeMath.java index 3c732cb5dc6..a56a6d031d9 100644 --- a/js/rhino/src/org/mozilla/javascript/NativeMath.java +++ b/js/rhino/src/org/mozilla/javascript/NativeMath.java @@ -46,6 +46,7 @@ public class NativeMath extends ScriptableObject implements IdFunction.Master, ScopeInitializer { public void scopeInit(Context cx, Scriptable scope, boolean sealed) { + sealFunctions = sealed; setPrototype(getObjectPrototype(scope)); setParentScope(scope); if (sealed) { @@ -97,36 +98,29 @@ public class NativeMath extends ScriptableObject } public void put(String name, Scriptable start, Object value) { - if (doOverwrite(name)) { + if (doOverwrite(name, start)) { super.put(name, start, value); } } public void delete(String name) { - if (doOverwrite(name)) { + // Let the super class to throw exceptions for sealed objects + if (isSealed() || doOverwrite(name, this)) { super.delete(name); } } // Return true to invoke put/delete in super class - private boolean doOverwrite(String name) { - if (isSealed()) { - // Let the super class to throw exceptions for sealed objects - return true; - } + private boolean doOverwrite(String name, Scriptable start) { int id = nameToId(name); - if (id > LAST_METHOD_ID) { - // Ignore modifications of read-only Math constants - return false; - } - - if (0 != id) { - if (functionPool[id] != IdFunction.WAS_OVERWRITTEN) { - synchronized (this) { - // Forget default implementation - // Must be synchronized to avoid clearance of overwritten - // mark by another thread running in wrapMethod - functionPool[id] = IdFunction.WAS_OVERWRITTEN; + if (id != 0) { + if (id > LAST_METHOD_ID) { + // Ignore modifications of read-only Math constants + return false; + } + else { + if (this == start) { + overwriteMethod(id); } } } @@ -137,11 +131,23 @@ public class NativeMath extends ScriptableObject synchronized (this) { IdFunction f = functionPool[id]; if (f == null) { - f = functionPool[id] = new IdFunction(this, name, id); + f = new IdFunction(this, name, id); + if (sealFunctions) { f.sealObject(); } + functionPool[id] = f; } return f; } } + + private void overwriteMethod(int id) { + if (functionPool[id] != IdFunction.WAS_OVERWRITTEN) { + // Must be synchronized to avoid clearance of overwritten mark + // by another thread running in wrapMethod + synchronized (this) { + functionPool[id] = IdFunction.WAS_OVERWRITTEN; + } + } + } private Double getField(int fieldId) { switch (fieldId) { @@ -176,39 +182,66 @@ public class NativeMath extends ScriptableObject throws JavaScriptException { switch (methodId) { - case Id_abs: return wrap_dbl(js_abs(to_dbl(args, 0))); - case Id_acos: return wrap_dbl(js_acos(to_dbl(args, 0))); - case Id_asin: return wrap_dbl(js_asin(to_dbl(args, 0))); - case Id_atan: return wrap_dbl(js_atan(to_dbl(args, 0))); - case Id_atan2: return wrap_dbl - (js_atan2(to_dbl(args, 0), to_dbl(args, 1))); - case Id_ceil: return wrap_dbl(js_ceil(to_dbl(args, 0))); - case Id_cos: return wrap_dbl(js_cos(to_dbl(args, 0))); - case Id_exp: return wrap_dbl(js_exp(to_dbl(args, 0))); - case Id_floor: return wrap_dbl(js_floor(to_dbl(args, 0))); - case Id_log: return wrap_dbl(js_log(to_dbl(args, 0))); - case Id_max: return wrap_dbl(js_max(args)); - case Id_min: return wrap_dbl(js_min(args)); - case Id_pow: return wrap_dbl - (js_pow(to_dbl(args, 0), to_dbl(args, 1))); - case Id_random: return wrap_dbl(js_random()); - case Id_round: return wrap_dbl(js_round(to_dbl(args, 0))); - case Id_sin: return wrap_dbl(js_sin(to_dbl(args, 0))); - case Id_sqrt: return wrap_dbl(js_sqrt(to_dbl(args, 0))); - case Id_tan: return wrap_dbl(js_tan(to_dbl(args, 0))); + case Id_abs: return wrap_double + (js_abs(ScriptRuntime.toNumber(args, 0))); + + case Id_acos: return wrap_double + (js_acos(ScriptRuntime.toNumber(args, 0))); + + case Id_asin: return wrap_double + (js_asin(ScriptRuntime.toNumber(args, 0))); + + case Id_atan: return wrap_double + (js_atan(ScriptRuntime.toNumber(args, 0))); + + case Id_atan2: return wrap_double + (js_atan2(ScriptRuntime.toNumber(args, 0), + ScriptRuntime.toNumber(args, 1))); + + case Id_ceil: return wrap_double + (js_ceil(ScriptRuntime.toNumber(args, 0))); + + case Id_cos: return wrap_double + (js_cos(ScriptRuntime.toNumber(args, 0))); + + case Id_exp: return wrap_double + (js_exp(ScriptRuntime.toNumber(args, 0))); + + case Id_floor: return wrap_double + (js_floor(ScriptRuntime.toNumber(args, 0))); + + case Id_log: return wrap_double + (js_log(ScriptRuntime.toNumber(args, 0))); + + case Id_max: return wrap_double + (js_max(args)); + + case Id_min: return wrap_double + (js_min(args)); + + case Id_pow: return wrap_double + (js_pow(ScriptRuntime.toNumber(args, 0), + ScriptRuntime.toNumber(args, 1))); + + case Id_random: return wrap_double + (js_random()); + + case Id_round: return wrap_double + (js_round(ScriptRuntime.toNumber(args, 0))); + + case Id_sin: return wrap_double + (js_sin(ScriptRuntime.toNumber(args, 0))); + + case Id_sqrt: return wrap_double + (js_sqrt(ScriptRuntime.toNumber(args, 0))); + + case Id_tan: return wrap_double + (js_tan(ScriptRuntime.toNumber(args, 0))); } return null; } - private double to_dbl(Object[] args, int index) { - return ScriptRuntime.toNumber(args, index); - } - - private double to_dbl(Object arg) { - return ScriptRuntime.toNumber(arg); - } - - private Double wrap_dbl(double x) { + private Double wrap_double(double x) { return (x == x) ? new Double(x) : ScriptRuntime.NaNobj; } @@ -410,5 +443,7 @@ public class NativeMath extends ScriptableObject // Last accessed function cache private IdFunction lastFunction = IdFunction.WAS_OVERWRITTEN; + + private boolean sealFunctions; }