зеркало из https://github.com/mozilla/gecko-dev.git
Updates from Igor.
This commit is contained in:
Родитель
e073d5090b
Коммит
c83b74d6be
|
@ -39,10 +39,10 @@ package org.mozilla.javascript;
|
|||
Base class for native object implementation that uses IdFunction to export its methods to script via <class-name>.prototype object.
|
||||
|
||||
Any descendant should implement at least the following methods:
|
||||
getMaxPrototypeMethodId
|
||||
mapNameToMethodId
|
||||
execMethod
|
||||
methodArity
|
||||
getMaxPrototypeMethodId
|
||||
mapNameToMethodId
|
||||
execMethod
|
||||
methodArity
|
||||
|
||||
Any implementation of execMethod and methodArity should assume that if
|
||||
methodId is 0 (CONSTRUCTOR_ID), it denotes EcmaScript constructor for
|
||||
|
@ -51,18 +51,18 @@ methodId is 0 (CONSTRUCTOR_ID), it denotes EcmaScript constructor for
|
|||
To customize initializition of constructor and protype objects, descendant
|
||||
may override initForGlobal or fillConstructorProperties methods.
|
||||
|
||||
To be less verbose with wrapping/unwrapping of script objects, descaendant
|
||||
should use to_/wrap_ set of methods.
|
||||
To wrap primitive java types to script objects, descaendant
|
||||
should use wrap_<primitive-type> set of methods.
|
||||
|
||||
*/
|
||||
public abstract class IdScriptable extends ScriptableObject
|
||||
implements IdFunction.Master, ScopeInitializer
|
||||
{
|
||||
public static final int CONSTRUCTOR_ID = 0;
|
||||
public static final int CONSTRUCTOR_ID = 0;
|
||||
|
||||
/** 'thisObj' will be null if invoked as constructor, in which case
|
||||
** instance of Scriptable should be returned.
|
||||
*/
|
||||
*/
|
||||
public abstract Object execMethod(int methodId, IdFunction function,
|
||||
Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
|
@ -70,77 +70,77 @@ public abstract class IdScriptable extends ScriptableObject
|
|||
|
||||
public abstract int methodArity(int methodId, IdFunction function);
|
||||
|
||||
/** Return maximum method id for prototype function */
|
||||
protected abstract int getMaxPrototypeMethodId();
|
||||
|
||||
/** Map name into id for prototypr method.
|
||||
** Should return 0 if not name is not prototype method
|
||||
** or value between 1 and getMaxPrototypeMethodId()
|
||||
*/
|
||||
protected abstract int mapNameToMethodId(String name);
|
||||
/** Return maximum method id for prototype function */
|
||||
protected abstract int getMaxPrototypeMethodId();
|
||||
|
||||
/** Map name into id for prototypr method.
|
||||
** Should return 0 if not name is not prototype method
|
||||
** or value between 1 and getMaxPrototypeMethodId()
|
||||
*/
|
||||
protected abstract int mapNameToMethodId(String name);
|
||||
|
||||
public boolean has(String name, Scriptable start) {
|
||||
if (prototypeFunctionPool != null) {
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f != IdFunction.WAS_OVERWRITTEN) { return true; }
|
||||
}
|
||||
else {
|
||||
if (null != checkConstructor(name)) { return true; }
|
||||
}
|
||||
}
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f != IdFunction.WAS_OVERWRITTEN) { return true; }
|
||||
}
|
||||
else {
|
||||
if (null != checkConstructor(name)) { return true; }
|
||||
}
|
||||
}
|
||||
return super.has(name, start);
|
||||
}
|
||||
|
||||
public Object get(String name, Scriptable start) {
|
||||
L: if (prototypeFunctionPool != null) {
|
||||
IdFunction f = lastFunction;
|
||||
if (f.methodName == name) {
|
||||
if (prototypeFunctionPool[f.methodId] == f) {
|
||||
return f;
|
||||
}
|
||||
lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
f = prototypeFunctionPool[id];
|
||||
if (f == null) { f = wrapMethod(name, id); }
|
||||
if (f == IdFunction.WAS_OVERWRITTEN) { break L; }
|
||||
}
|
||||
else {
|
||||
f = checkConstructor(name);
|
||||
if (f == null) { break L; }
|
||||
}
|
||||
// Update cache
|
||||
f.methodName = name;
|
||||
lastFunction = f;
|
||||
return f;
|
||||
}
|
||||
IdFunction f = lastFunction;
|
||||
if (f.methodName == name) {
|
||||
if (prototypeFunctionPool[f.methodId] == f) {
|
||||
return f;
|
||||
}
|
||||
lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
f = prototypeFunctionPool[id];
|
||||
if (f == null) { f = wrapMethod(name, id); }
|
||||
if (f == IdFunction.WAS_OVERWRITTEN) { break L; }
|
||||
}
|
||||
else {
|
||||
f = checkConstructor(name);
|
||||
if (f == null) { break L; }
|
||||
}
|
||||
// Update cache
|
||||
f.methodName = name;
|
||||
lastFunction = f;
|
||||
return f;
|
||||
}
|
||||
return super.get(name, start);
|
||||
}
|
||||
|
||||
public void put(String name, Scriptable start, Object value) {
|
||||
if (doOverwrite(name, start)) {
|
||||
super.put(name, start, value);
|
||||
}
|
||||
if (doOverwrite(name, start)) {
|
||||
super.put(name, start, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String name) {
|
||||
if (doOverwrite(name, this)) {
|
||||
super.delete(name);
|
||||
}
|
||||
super.delete(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void scopeInit(Context cx, Scriptable scope, boolean sealed) {
|
||||
useDynamicScope = cx.hasCompileFunctionsWithDynamicScope();
|
||||
|
||||
prototypeFunctionPool = new IdFunction[getMaxPrototypeMethodId() + 1];
|
||||
prototypeFunctionPool = new IdFunction[getMaxPrototypeMethodId() + 1];
|
||||
|
||||
seal_functions = sealed;
|
||||
|
||||
setPrototype(getObjectPrototype(scope));
|
||||
|
||||
seal_functions = sealed;
|
||||
|
||||
setPrototype(getObjectPrototype(scope));
|
||||
|
||||
String name = getClassName();
|
||||
|
||||
IdFunction ctor = newIdFunction(name, CONSTRUCTOR_ID);
|
||||
|
@ -151,165 +151,139 @@ public abstract class IdScriptable extends ScriptableObject
|
|||
|
||||
ctor.setImmunePrototypeProperty(this);
|
||||
|
||||
fillConstructorProperties(cx, ctor, sealed);
|
||||
fillConstructorProperties(cx, ctor, sealed);
|
||||
|
||||
if (!name.equals("With")) {
|
||||
// A "With" object would delegate these calls to the prototype:
|
||||
// not the right thing to do here!
|
||||
prototypeFunctionPool[CONSTRUCTOR_ID] = ctor;
|
||||
prototypeFunctionPool[CONSTRUCTOR_ID] = ctor;
|
||||
}
|
||||
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
ctor.addPropertyAttribute(READONLY);
|
||||
sealObject();
|
||||
}
|
||||
}
|
||||
|
||||
defineProperty(scope, name, ctor, ScriptableObject.DONTENUM);
|
||||
}
|
||||
defineProperty(scope, name, ctor, ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
protected void fillConstructorProperties
|
||||
(Context cx, IdFunction ctor, boolean sealed)
|
||||
{
|
||||
}
|
||||
protected void fillConstructorProperties
|
||||
(Context cx, IdFunction ctor, boolean sealed)
|
||||
{
|
||||
}
|
||||
|
||||
protected void addIdFunctionProperty
|
||||
(Scriptable obj, String name, int id, boolean sealed)
|
||||
{
|
||||
IdFunction f = newIdFunction(name, id);
|
||||
if (sealed) { f.sealObject(); }
|
||||
defineProperty(obj, name, f, DONTENUM);
|
||||
}
|
||||
|
||||
protected void addIdFunctionProperty
|
||||
(Scriptable obj, String name, int id, boolean sealed)
|
||||
{
|
||||
IdFunction f = newIdFunction(name, id);
|
||||
if (sealed) { f.sealObject(); }
|
||||
defineProperty(obj, name, f, DONTENUM);
|
||||
}
|
||||
|
||||
/** Utility method for converting target object into native this.
|
||||
Possible usage would be to have a private function like realThis:
|
||||
|
||||
private NativeSomething realThis(Scriptable thisObj,
|
||||
IdFunction f, boolean searchPrototype)
|
||||
{
|
||||
while (!(thisObj instanceof NativeSomething)) {
|
||||
thisObj = nextInstanceCheck(thisObj, f, searchPrototype);
|
||||
}
|
||||
return (NativeSomething)thisObj;
|
||||
}
|
||||
|
||||
Note that although such function can be implemented universally via
|
||||
java.lang.Class.isInstance(), it would be much more slower
|
||||
Possible usage would be to have a private function like realThis:
|
||||
|
||||
private NativeSomething realThis(Scriptable thisObj,
|
||||
IdFunction f, boolean searchPrototype)
|
||||
{
|
||||
while (!(thisObj instanceof NativeSomething)) {
|
||||
thisObj = nextInstanceCheck(thisObj, f, searchPrototype);
|
||||
}
|
||||
return (NativeSomething)thisObj;
|
||||
}
|
||||
|
||||
Note that although such function can be implemented universally via
|
||||
java.lang.Class.isInstance(), it would be much more slower
|
||||
*/
|
||||
protected Scriptable nextInstanceCheck(Scriptable thisObj,
|
||||
IdFunction f,
|
||||
boolean searchPrototype)
|
||||
{
|
||||
if (searchPrototype && useDynamicScope) {
|
||||
thisObj = thisObj.getPrototype();
|
||||
if (thisObj != null) { return thisObj; }
|
||||
}
|
||||
throw NativeGlobal.typeError1("msg.incompat.call", f.methodName, f);
|
||||
}
|
||||
|
||||
protected IdFunction newIdFunction(String name, int id) {
|
||||
return new IdFunction(this, name, id);
|
||||
}
|
||||
IdFunction f,
|
||||
boolean searchPrototype)
|
||||
{
|
||||
if (searchPrototype && useDynamicScope) {
|
||||
thisObj = thisObj.getPrototype();
|
||||
if (thisObj != null) { return thisObj; }
|
||||
}
|
||||
throw NativeGlobal.typeError1("msg.incompat.call", f.methodName, f);
|
||||
}
|
||||
|
||||
protected IdFunction newIdFunction(String name, int id) {
|
||||
return new IdFunction(this, name, id);
|
||||
}
|
||||
|
||||
protected final Object wrap_dbl(double x) {
|
||||
protected final Object wrap_double(double x) {
|
||||
return (x == x) ? new Double(x) : ScriptRuntime.NaNobj;
|
||||
}
|
||||
}
|
||||
|
||||
protected final Object wrap_int(int x) {
|
||||
byte b = (byte)x;
|
||||
protected final Object wrap_int(int x) {
|
||||
byte b = (byte)x;
|
||||
if (b == x) { return new Byte(b); }
|
||||
return new Integer(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_boolean(boolean x) {
|
||||
return x ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
protected final double to_dbl(Object arg) {
|
||||
return ScriptRuntime.toNumber(arg);
|
||||
}
|
||||
|
||||
protected final double to_int(Object arg) {
|
||||
return ScriptRuntime.toInt32(arg);
|
||||
}
|
||||
|
||||
protected final boolean to_boolean(Object arg) {
|
||||
return ScriptRuntime.toBoolean(arg);
|
||||
}
|
||||
|
||||
protected final String to_str(Object arg) {
|
||||
return ScriptRuntime.toString(arg);
|
||||
}
|
||||
|
||||
protected final double to_dbl(Object[] args, int index) {
|
||||
return ScriptRuntime.toNumber(args, index);
|
||||
}
|
||||
|
||||
protected final double to_int(Object[] args, int index) {
|
||||
return ScriptRuntime.toInt32(args, index);
|
||||
}
|
||||
|
||||
protected final boolean to_boolean(Object[] args, int index) {
|
||||
return (index < args.length) ? to_boolean(args[index]) : false;
|
||||
}
|
||||
|
||||
protected final String to_str(Object[] args, int index) {
|
||||
return ScriptRuntime.toString(args, index);
|
||||
}
|
||||
|
||||
return new Integer(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_long(long x) {
|
||||
int i = (int)x;
|
||||
if (i == x) { return wrap_int(i); }
|
||||
return new Long(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_boolean(boolean x) {
|
||||
return x ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
// Return true to invoke put/delete in super class
|
||||
private boolean doOverwrite(String name, Scriptable start) {
|
||||
// Let the super class to throw exceptions for sealed objects
|
||||
if (!isSealed() && prototypeFunctionPool != null) {
|
||||
if (null != checkConstructor(name)) {
|
||||
// If constructor is present, it is read-only
|
||||
return false;
|
||||
}
|
||||
if (this == start) {
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
overwriteMethod(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private IdFunction wrapMethod(String name, int id) {
|
||||
synchronized (this) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f == null) {
|
||||
f = newIdFunction(name, id);
|
||||
if (seal_functions) { f.sealObject(); }
|
||||
prototypeFunctionPool[id] = f;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
private void overwriteMethod(int id) {
|
||||
if (prototypeFunctionPool[id] != IdFunction.WAS_OVERWRITTEN) {
|
||||
// Must be synchronized to avoid clearance of overwritten mark
|
||||
// by another thread running in wrapMethod
|
||||
synchronized (this) {
|
||||
prototypeFunctionPool[id] = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdFunction checkConstructor(String name) {
|
||||
return name.equals("constructor")
|
||||
? prototypeFunctionPool[CONSTRUCTOR_ID]
|
||||
: null;
|
||||
}
|
||||
if (!isSealed() && prototypeFunctionPool != null) {
|
||||
if (null != checkConstructor(name)) {
|
||||
// If constructor is present, it is read-only
|
||||
return false;
|
||||
}
|
||||
if (this == start) {
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
overwriteMethod(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private IdFunction wrapMethod(String name, int id) {
|
||||
synchronized (this) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f == null) {
|
||||
f = newIdFunction(name, id);
|
||||
if (seal_functions) { f.sealObject(); }
|
||||
prototypeFunctionPool[id] = f;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
private void overwriteMethod(int id) {
|
||||
if (prototypeFunctionPool[id] != IdFunction.WAS_OVERWRITTEN) {
|
||||
// Must be synchronized to avoid clearance of overwritten mark
|
||||
// by another thread running in wrapMethod
|
||||
synchronized (this) {
|
||||
prototypeFunctionPool[id] = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdFunction checkConstructor(String name) {
|
||||
return name.equals("constructor")
|
||||
? prototypeFunctionPool[CONSTRUCTOR_ID]
|
||||
: null;
|
||||
}
|
||||
|
||||
private IdFunction[] prototypeFunctionPool;
|
||||
|
||||
|
||||
// Not null to simplify logic
|
||||
private IdFunction lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
|
||||
private boolean seal_functions;
|
||||
private IdFunction lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
|
||||
private boolean seal_functions;
|
||||
|
||||
private boolean useDynamicScope;
|
||||
}
|
||||
|
|
|
@ -121,11 +121,11 @@ public class NativeDate extends IdScriptable {
|
|||
throws JavaScriptException
|
||||
{
|
||||
switch (methodId) {
|
||||
case ConstructorId_UTC: return wrap_dbl
|
||||
case ConstructorId_UTC: return wrap_double
|
||||
(jsStaticFunction_UTC(cx, thisObj, args, f));
|
||||
|
||||
case ConstructorId_parse: return wrap_dbl
|
||||
(jsStaticFunction_parse(to_str(args, 0)));
|
||||
case ConstructorId_parse: return wrap_double
|
||||
(jsStaticFunction_parse(ScriptRuntime.toString(args, 0)));
|
||||
|
||||
case CONSTRUCTOR_ID:
|
||||
return jsConstructor(cx, args, f, thisObj == null);
|
||||
|
@ -139,125 +139,127 @@ public class NativeDate extends IdScriptable {
|
|||
case Id_toDateString: return realThis(thisObj, f, true).
|
||||
jsFunction_toDateString();
|
||||
|
||||
case Id_toLocaleString: return realThis(thisObj, f, true).
|
||||
case Id_toLocaleString: return realThis(thisObj, f, true).
|
||||
jsFunction_toLocaleString();
|
||||
|
||||
case Id_toLocaleTimeString: return realThis(thisObj, f, true).
|
||||
case Id_toLocaleTimeString: return realThis(thisObj, f, true).
|
||||
jsFunction_toLocaleTimeString();
|
||||
|
||||
case Id_toLocaleDateString: return realThis(thisObj, f, true).
|
||||
case Id_toLocaleDateString: return realThis(thisObj, f, true).
|
||||
jsFunction_toLocaleDateString();
|
||||
|
||||
case Id_toUTCString: return realThis(thisObj, f, true).
|
||||
jsFunction_toUTCString();
|
||||
|
||||
case Id_valueOf: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_valueOf: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_valueOf());
|
||||
|
||||
case Id_getTime: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getTime: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getTime());
|
||||
|
||||
case Id_getYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getYear());
|
||||
|
||||
case Id_getFullYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getFullYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getFullYear());
|
||||
|
||||
case Id_getUTCFullYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCFullYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCFullYear());
|
||||
|
||||
case Id_getMonth: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getMonth: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getMonth());
|
||||
|
||||
case Id_getUTCMonth: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCMonth: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMonth());
|
||||
|
||||
case Id_getDate: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getDate: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getDate());
|
||||
|
||||
case Id_getUTCDate: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCDate: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCDate());
|
||||
|
||||
case Id_getDay: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getDay: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getDay());
|
||||
|
||||
case Id_getUTCDay: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCDay: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCDay());
|
||||
|
||||
case Id_getHours: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getHours: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getHours());
|
||||
|
||||
case Id_getUTCHours: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCHours: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCHours());
|
||||
|
||||
case Id_getMinutes: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getMinutes: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getMinutes());
|
||||
|
||||
case Id_getUTCMinutes: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCMinutes: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMinutes());
|
||||
|
||||
case Id_getSeconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getSeconds: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getSeconds());
|
||||
|
||||
case Id_getUTCSeconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCSeconds: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCSeconds());
|
||||
|
||||
case Id_getMilliseconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getMilliseconds: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getMilliseconds());
|
||||
|
||||
case Id_getUTCMilliseconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMilliseconds());
|
||||
case Id_getUTCMilliseconds:
|
||||
return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMilliseconds());
|
||||
|
||||
case Id_getTimezoneOffset: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_getTimezoneOffset());
|
||||
case Id_getTimezoneOffset:
|
||||
return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getTimezoneOffset());
|
||||
|
||||
case Id_setTime: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_setTime(to_dbl(args, 0)));
|
||||
case Id_setTime: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_setTime(ScriptRuntime.toNumber(args, 0)));
|
||||
|
||||
case Id_setMilliseconds: return wrap_dbl
|
||||
case Id_setMilliseconds: return wrap_double
|
||||
(jsFunction_setMilliseconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCMilliseconds: return wrap_dbl(
|
||||
case Id_setUTCMilliseconds: return wrap_double(
|
||||
jsFunction_setUTCMilliseconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setSeconds: return wrap_dbl(
|
||||
case Id_setSeconds: return wrap_double(
|
||||
jsFunction_setSeconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCSeconds:return wrap_dbl(
|
||||
case Id_setUTCSeconds: return wrap_double(
|
||||
jsFunction_setUTCSeconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setMinutes: return wrap_dbl(
|
||||
case Id_setMinutes: return wrap_double(
|
||||
jsFunction_setMinutes(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCMinutes: return wrap_dbl(
|
||||
case Id_setUTCMinutes: return wrap_double(
|
||||
jsFunction_setUTCMinutes(cx, thisObj, args, f));
|
||||
|
||||
case Id_setHours: return wrap_dbl(
|
||||
case Id_setHours: return wrap_double(
|
||||
jsFunction_setHours(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCHours: return wrap_dbl(
|
||||
case Id_setUTCHours: return wrap_double(
|
||||
jsFunction_setUTCHours(cx, thisObj, args, f));
|
||||
|
||||
case Id_setDate: return wrap_dbl(
|
||||
case Id_setDate: return wrap_double(
|
||||
jsFunction_setDate(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCDate: return wrap_dbl(
|
||||
case Id_setUTCDate: return wrap_double(
|
||||
jsFunction_setUTCDate(cx, thisObj, args, f));
|
||||
|
||||
case Id_setMonth: return wrap_dbl(
|
||||
case Id_setMonth: return wrap_double(
|
||||
jsFunction_setMonth(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCMonth: return wrap_dbl(
|
||||
case Id_setUTCMonth: return wrap_double(
|
||||
jsFunction_setUTCMonth(cx, thisObj, args, f));
|
||||
|
||||
case Id_setFullYear: return wrap_dbl(
|
||||
case Id_setFullYear: return wrap_double(
|
||||
jsFunction_setFullYear(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCFullYear: return wrap_dbl(
|
||||
case Id_setUTCFullYear: return wrap_double(
|
||||
jsFunction_setUTCFullYear(cx, thisObj, args, f));
|
||||
|
||||
case Id_setYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_setYear(to_dbl(args, 0)));
|
||||
case Id_setYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_setYear(ScriptRuntime.toNumber(args, 0)));
|
||||
}
|
||||
|
||||
return Scriptable.NOT_FOUND;
|
||||
|
|
|
@ -50,18 +50,62 @@ import java.lang.reflect.Method;
|
|||
* @author Mike Shaver
|
||||
*/
|
||||
|
||||
public class NativeGlobal implements IdFunction.Master {
|
||||
public class NativeGlobal implements ScopeInitializer, IdFunction.Master {
|
||||
|
||||
public static void init(Scriptable scope)
|
||||
throws PropertyException,
|
||||
NotAFunctionException,
|
||||
JavaScriptException
|
||||
{
|
||||
NativeGlobal instance = new NativeGlobal();
|
||||
Context cx = Context.getContext();
|
||||
// We can downcast here because Context.initStandardObjects
|
||||
// takes a ScriptableObject scope.
|
||||
instance.initForGlobal(cx, (ScriptableObject) scope, false);
|
||||
public void scopeInit(Context cx, Scriptable scope, boolean sealed) {
|
||||
|
||||
for (int id = 1; id <= LAST_METHOD_ID; ++id) {
|
||||
String name = getMethodName(id);
|
||||
IdFunction f = new IdFunction(this, name, id);
|
||||
f.setParentScope(scope);
|
||||
if (sealed) { f.sealObject(); }
|
||||
ScriptableObject.defineProperty(scope, name, f,
|
||||
ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
ScriptableObject.defineProperty(scope, "NaN",
|
||||
ScriptRuntime.NaNobj,
|
||||
ScriptableObject.DONTENUM);
|
||||
ScriptableObject.defineProperty(scope, "Infinity",
|
||||
new Double(Double.POSITIVE_INFINITY),
|
||||
ScriptableObject.DONTENUM);
|
||||
ScriptableObject.defineProperty(scope, "undefined",
|
||||
Undefined.instance,
|
||||
ScriptableObject.DONTENUM);
|
||||
|
||||
String[] errorMethods = { "ConversionError",
|
||||
"EvalError",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"URIError"
|
||||
};
|
||||
|
||||
/*
|
||||
Each error constructor gets its own Error object as a prototype,
|
||||
with the 'name' property set to the name of the error.
|
||||
*/
|
||||
for (int i = 0; i < errorMethods.length; i++) {
|
||||
String name = errorMethods[i];
|
||||
IdFunction ctor = new IdFunction(this, name, Id_new_CommonError);
|
||||
ctor.setFunctionType(IdFunction.FUNCTION_AND_CONSTRUCTOR);
|
||||
ctor.setParentScope(scope);
|
||||
ScriptableObject.defineProperty(scope, name, ctor,
|
||||
ScriptableObject.DONTENUM);
|
||||
|
||||
Scriptable errorProto = ScriptRuntime.newObject
|
||||
(cx, scope, "Error", ScriptRuntime.emptyArgs);
|
||||
|
||||
errorProto.put("name", errorProto, name);
|
||||
ctor.put("prototype", ctor, errorProto);
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
if (errorProto instanceof ScriptableObject) {
|
||||
((ScriptableObject)errorProto).sealObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object execMethod(int methodId, IdFunction function, Context cx,
|
||||
|
@ -112,60 +156,6 @@ public class NativeGlobal implements IdFunction.Master {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void initForGlobal(Context cx, ScriptableObject global,
|
||||
boolean sealed)
|
||||
throws PropertyException,
|
||||
NotAFunctionException,
|
||||
JavaScriptException
|
||||
{
|
||||
for (int id = 1; id <= LAST_METHOD_ID; ++id) {
|
||||
String name = getMethodName(id);
|
||||
IdFunction f = new IdFunction(this, name, id);
|
||||
f.setParentScope(global);
|
||||
if (sealed) { f.sealObject(); }
|
||||
global.defineProperty(name, f, ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
global.defineProperty("NaN", ScriptRuntime.NaNobj,
|
||||
ScriptableObject.DONTENUM);
|
||||
global.defineProperty("Infinity", new Double(Double.POSITIVE_INFINITY),
|
||||
ScriptableObject.DONTENUM);
|
||||
global.defineProperty("undefined", Undefined.instance,
|
||||
ScriptableObject.DONTENUM);
|
||||
|
||||
String[] errorMethods = { "ConversionError",
|
||||
"EvalError",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"URIError"
|
||||
};
|
||||
|
||||
/*
|
||||
Each error constructor gets its own Error object as a prototype,
|
||||
with the 'name' property set to the name of the error.
|
||||
*/
|
||||
for (int i = 0; i < errorMethods.length; i++) {
|
||||
String name = errorMethods[i];
|
||||
IdFunction ctor = new IdFunction(this, name, Id_new_CommonError);
|
||||
ctor.setFunctionType(IdFunction.FUNCTION_AND_CONSTRUCTOR);
|
||||
ctor.setParentScope(global);
|
||||
global.defineProperty(name, ctor, ScriptableObject.DONTENUM);
|
||||
|
||||
Scriptable errorProto = cx.newObject(global, "Error");
|
||||
errorProto.put("name", errorProto, name);
|
||||
ctor.put("prototype", ctor, errorProto);
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
if (errorProto instanceof ScriptableObject) {
|
||||
((ScriptableObject)errorProto).sealObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The global method parseInt, as per ECMA-262 15.1.2.2.
|
||||
*/
|
||||
|
|
|
@ -39,10 +39,10 @@ package org.mozilla.javascript;
|
|||
Base class for native object implementation that uses IdFunction to export its methods to script via <class-name>.prototype object.
|
||||
|
||||
Any descendant should implement at least the following methods:
|
||||
getMaxPrototypeMethodId
|
||||
mapNameToMethodId
|
||||
execMethod
|
||||
methodArity
|
||||
getMaxPrototypeMethodId
|
||||
mapNameToMethodId
|
||||
execMethod
|
||||
methodArity
|
||||
|
||||
Any implementation of execMethod and methodArity should assume that if
|
||||
methodId is 0 (CONSTRUCTOR_ID), it denotes EcmaScript constructor for
|
||||
|
@ -51,18 +51,18 @@ methodId is 0 (CONSTRUCTOR_ID), it denotes EcmaScript constructor for
|
|||
To customize initializition of constructor and protype objects, descendant
|
||||
may override initForGlobal or fillConstructorProperties methods.
|
||||
|
||||
To be less verbose with wrapping/unwrapping of script objects, descaendant
|
||||
should use to_/wrap_ set of methods.
|
||||
To wrap primitive java types to script objects, descaendant
|
||||
should use wrap_<primitive-type> set of methods.
|
||||
|
||||
*/
|
||||
public abstract class IdScriptable extends ScriptableObject
|
||||
implements IdFunction.Master, ScopeInitializer
|
||||
{
|
||||
public static final int CONSTRUCTOR_ID = 0;
|
||||
public static final int CONSTRUCTOR_ID = 0;
|
||||
|
||||
/** 'thisObj' will be null if invoked as constructor, in which case
|
||||
** instance of Scriptable should be returned.
|
||||
*/
|
||||
*/
|
||||
public abstract Object execMethod(int methodId, IdFunction function,
|
||||
Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
|
@ -70,77 +70,77 @@ public abstract class IdScriptable extends ScriptableObject
|
|||
|
||||
public abstract int methodArity(int methodId, IdFunction function);
|
||||
|
||||
/** Return maximum method id for prototype function */
|
||||
protected abstract int getMaxPrototypeMethodId();
|
||||
|
||||
/** Map name into id for prototypr method.
|
||||
** Should return 0 if not name is not prototype method
|
||||
** or value between 1 and getMaxPrototypeMethodId()
|
||||
*/
|
||||
protected abstract int mapNameToMethodId(String name);
|
||||
/** Return maximum method id for prototype function */
|
||||
protected abstract int getMaxPrototypeMethodId();
|
||||
|
||||
/** Map name into id for prototypr method.
|
||||
** Should return 0 if not name is not prototype method
|
||||
** or value between 1 and getMaxPrototypeMethodId()
|
||||
*/
|
||||
protected abstract int mapNameToMethodId(String name);
|
||||
|
||||
public boolean has(String name, Scriptable start) {
|
||||
if (prototypeFunctionPool != null) {
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f != IdFunction.WAS_OVERWRITTEN) { return true; }
|
||||
}
|
||||
else {
|
||||
if (null != checkConstructor(name)) { return true; }
|
||||
}
|
||||
}
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f != IdFunction.WAS_OVERWRITTEN) { return true; }
|
||||
}
|
||||
else {
|
||||
if (null != checkConstructor(name)) { return true; }
|
||||
}
|
||||
}
|
||||
return super.has(name, start);
|
||||
}
|
||||
|
||||
public Object get(String name, Scriptable start) {
|
||||
L: if (prototypeFunctionPool != null) {
|
||||
IdFunction f = lastFunction;
|
||||
if (f.methodName == name) {
|
||||
if (prototypeFunctionPool[f.methodId] == f) {
|
||||
return f;
|
||||
}
|
||||
lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
f = prototypeFunctionPool[id];
|
||||
if (f == null) { f = wrapMethod(name, id); }
|
||||
if (f == IdFunction.WAS_OVERWRITTEN) { break L; }
|
||||
}
|
||||
else {
|
||||
f = checkConstructor(name);
|
||||
if (f == null) { break L; }
|
||||
}
|
||||
// Update cache
|
||||
f.methodName = name;
|
||||
lastFunction = f;
|
||||
return f;
|
||||
}
|
||||
IdFunction f = lastFunction;
|
||||
if (f.methodName == name) {
|
||||
if (prototypeFunctionPool[f.methodId] == f) {
|
||||
return f;
|
||||
}
|
||||
lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
f = prototypeFunctionPool[id];
|
||||
if (f == null) { f = wrapMethod(name, id); }
|
||||
if (f == IdFunction.WAS_OVERWRITTEN) { break L; }
|
||||
}
|
||||
else {
|
||||
f = checkConstructor(name);
|
||||
if (f == null) { break L; }
|
||||
}
|
||||
// Update cache
|
||||
f.methodName = name;
|
||||
lastFunction = f;
|
||||
return f;
|
||||
}
|
||||
return super.get(name, start);
|
||||
}
|
||||
|
||||
public void put(String name, Scriptable start, Object value) {
|
||||
if (doOverwrite(name, start)) {
|
||||
super.put(name, start, value);
|
||||
}
|
||||
if (doOverwrite(name, start)) {
|
||||
super.put(name, start, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete(String name) {
|
||||
if (doOverwrite(name, this)) {
|
||||
super.delete(name);
|
||||
}
|
||||
super.delete(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void scopeInit(Context cx, Scriptable scope, boolean sealed) {
|
||||
useDynamicScope = cx.hasCompileFunctionsWithDynamicScope();
|
||||
|
||||
prototypeFunctionPool = new IdFunction[getMaxPrototypeMethodId() + 1];
|
||||
prototypeFunctionPool = new IdFunction[getMaxPrototypeMethodId() + 1];
|
||||
|
||||
seal_functions = sealed;
|
||||
|
||||
setPrototype(getObjectPrototype(scope));
|
||||
|
||||
seal_functions = sealed;
|
||||
|
||||
setPrototype(getObjectPrototype(scope));
|
||||
|
||||
String name = getClassName();
|
||||
|
||||
IdFunction ctor = newIdFunction(name, CONSTRUCTOR_ID);
|
||||
|
@ -151,165 +151,139 @@ public abstract class IdScriptable extends ScriptableObject
|
|||
|
||||
ctor.setImmunePrototypeProperty(this);
|
||||
|
||||
fillConstructorProperties(cx, ctor, sealed);
|
||||
fillConstructorProperties(cx, ctor, sealed);
|
||||
|
||||
if (!name.equals("With")) {
|
||||
// A "With" object would delegate these calls to the prototype:
|
||||
// not the right thing to do here!
|
||||
prototypeFunctionPool[CONSTRUCTOR_ID] = ctor;
|
||||
prototypeFunctionPool[CONSTRUCTOR_ID] = ctor;
|
||||
}
|
||||
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
ctor.addPropertyAttribute(READONLY);
|
||||
sealObject();
|
||||
}
|
||||
}
|
||||
|
||||
defineProperty(scope, name, ctor, ScriptableObject.DONTENUM);
|
||||
}
|
||||
defineProperty(scope, name, ctor, ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
protected void fillConstructorProperties
|
||||
(Context cx, IdFunction ctor, boolean sealed)
|
||||
{
|
||||
}
|
||||
protected void fillConstructorProperties
|
||||
(Context cx, IdFunction ctor, boolean sealed)
|
||||
{
|
||||
}
|
||||
|
||||
protected void addIdFunctionProperty
|
||||
(Scriptable obj, String name, int id, boolean sealed)
|
||||
{
|
||||
IdFunction f = newIdFunction(name, id);
|
||||
if (sealed) { f.sealObject(); }
|
||||
defineProperty(obj, name, f, DONTENUM);
|
||||
}
|
||||
|
||||
protected void addIdFunctionProperty
|
||||
(Scriptable obj, String name, int id, boolean sealed)
|
||||
{
|
||||
IdFunction f = newIdFunction(name, id);
|
||||
if (sealed) { f.sealObject(); }
|
||||
defineProperty(obj, name, f, DONTENUM);
|
||||
}
|
||||
|
||||
/** Utility method for converting target object into native this.
|
||||
Possible usage would be to have a private function like realThis:
|
||||
|
||||
private NativeSomething realThis(Scriptable thisObj,
|
||||
IdFunction f, boolean searchPrototype)
|
||||
{
|
||||
while (!(thisObj instanceof NativeSomething)) {
|
||||
thisObj = nextInstanceCheck(thisObj, f, searchPrototype);
|
||||
}
|
||||
return (NativeSomething)thisObj;
|
||||
}
|
||||
|
||||
Note that although such function can be implemented universally via
|
||||
java.lang.Class.isInstance(), it would be much more slower
|
||||
Possible usage would be to have a private function like realThis:
|
||||
|
||||
private NativeSomething realThis(Scriptable thisObj,
|
||||
IdFunction f, boolean searchPrototype)
|
||||
{
|
||||
while (!(thisObj instanceof NativeSomething)) {
|
||||
thisObj = nextInstanceCheck(thisObj, f, searchPrototype);
|
||||
}
|
||||
return (NativeSomething)thisObj;
|
||||
}
|
||||
|
||||
Note that although such function can be implemented universally via
|
||||
java.lang.Class.isInstance(), it would be much more slower
|
||||
*/
|
||||
protected Scriptable nextInstanceCheck(Scriptable thisObj,
|
||||
IdFunction f,
|
||||
boolean searchPrototype)
|
||||
{
|
||||
if (searchPrototype && useDynamicScope) {
|
||||
thisObj = thisObj.getPrototype();
|
||||
if (thisObj != null) { return thisObj; }
|
||||
}
|
||||
throw NativeGlobal.typeError1("msg.incompat.call", f.methodName, f);
|
||||
}
|
||||
|
||||
protected IdFunction newIdFunction(String name, int id) {
|
||||
return new IdFunction(this, name, id);
|
||||
}
|
||||
IdFunction f,
|
||||
boolean searchPrototype)
|
||||
{
|
||||
if (searchPrototype && useDynamicScope) {
|
||||
thisObj = thisObj.getPrototype();
|
||||
if (thisObj != null) { return thisObj; }
|
||||
}
|
||||
throw NativeGlobal.typeError1("msg.incompat.call", f.methodName, f);
|
||||
}
|
||||
|
||||
protected IdFunction newIdFunction(String name, int id) {
|
||||
return new IdFunction(this, name, id);
|
||||
}
|
||||
|
||||
protected final Object wrap_dbl(double x) {
|
||||
protected final Object wrap_double(double x) {
|
||||
return (x == x) ? new Double(x) : ScriptRuntime.NaNobj;
|
||||
}
|
||||
}
|
||||
|
||||
protected final Object wrap_int(int x) {
|
||||
byte b = (byte)x;
|
||||
protected final Object wrap_int(int x) {
|
||||
byte b = (byte)x;
|
||||
if (b == x) { return new Byte(b); }
|
||||
return new Integer(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_boolean(boolean x) {
|
||||
return x ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
protected final double to_dbl(Object arg) {
|
||||
return ScriptRuntime.toNumber(arg);
|
||||
}
|
||||
|
||||
protected final double to_int(Object arg) {
|
||||
return ScriptRuntime.toInt32(arg);
|
||||
}
|
||||
|
||||
protected final boolean to_boolean(Object arg) {
|
||||
return ScriptRuntime.toBoolean(arg);
|
||||
}
|
||||
|
||||
protected final String to_str(Object arg) {
|
||||
return ScriptRuntime.toString(arg);
|
||||
}
|
||||
|
||||
protected final double to_dbl(Object[] args, int index) {
|
||||
return ScriptRuntime.toNumber(args, index);
|
||||
}
|
||||
|
||||
protected final double to_int(Object[] args, int index) {
|
||||
return ScriptRuntime.toInt32(args, index);
|
||||
}
|
||||
|
||||
protected final boolean to_boolean(Object[] args, int index) {
|
||||
return (index < args.length) ? to_boolean(args[index]) : false;
|
||||
}
|
||||
|
||||
protected final String to_str(Object[] args, int index) {
|
||||
return ScriptRuntime.toString(args, index);
|
||||
}
|
||||
|
||||
return new Integer(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_long(long x) {
|
||||
int i = (int)x;
|
||||
if (i == x) { return wrap_int(i); }
|
||||
return new Long(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_boolean(boolean x) {
|
||||
return x ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
// Return true to invoke put/delete in super class
|
||||
private boolean doOverwrite(String name, Scriptable start) {
|
||||
// Let the super class to throw exceptions for sealed objects
|
||||
if (!isSealed() && prototypeFunctionPool != null) {
|
||||
if (null != checkConstructor(name)) {
|
||||
// If constructor is present, it is read-only
|
||||
return false;
|
||||
}
|
||||
if (this == start) {
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
overwriteMethod(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private IdFunction wrapMethod(String name, int id) {
|
||||
synchronized (this) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f == null) {
|
||||
f = newIdFunction(name, id);
|
||||
if (seal_functions) { f.sealObject(); }
|
||||
prototypeFunctionPool[id] = f;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
private void overwriteMethod(int id) {
|
||||
if (prototypeFunctionPool[id] != IdFunction.WAS_OVERWRITTEN) {
|
||||
// Must be synchronized to avoid clearance of overwritten mark
|
||||
// by another thread running in wrapMethod
|
||||
synchronized (this) {
|
||||
prototypeFunctionPool[id] = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdFunction checkConstructor(String name) {
|
||||
return name.equals("constructor")
|
||||
? prototypeFunctionPool[CONSTRUCTOR_ID]
|
||||
: null;
|
||||
}
|
||||
if (!isSealed() && prototypeFunctionPool != null) {
|
||||
if (null != checkConstructor(name)) {
|
||||
// If constructor is present, it is read-only
|
||||
return false;
|
||||
}
|
||||
if (this == start) {
|
||||
int id = mapNameToMethodId(name);
|
||||
if (id != 0) {
|
||||
overwriteMethod(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private IdFunction wrapMethod(String name, int id) {
|
||||
synchronized (this) {
|
||||
IdFunction f = prototypeFunctionPool[id];
|
||||
if (f == null) {
|
||||
f = newIdFunction(name, id);
|
||||
if (seal_functions) { f.sealObject(); }
|
||||
prototypeFunctionPool[id] = f;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
private void overwriteMethod(int id) {
|
||||
if (prototypeFunctionPool[id] != IdFunction.WAS_OVERWRITTEN) {
|
||||
// Must be synchronized to avoid clearance of overwritten mark
|
||||
// by another thread running in wrapMethod
|
||||
synchronized (this) {
|
||||
prototypeFunctionPool[id] = IdFunction.WAS_OVERWRITTEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IdFunction checkConstructor(String name) {
|
||||
return name.equals("constructor")
|
||||
? prototypeFunctionPool[CONSTRUCTOR_ID]
|
||||
: null;
|
||||
}
|
||||
|
||||
private IdFunction[] prototypeFunctionPool;
|
||||
|
||||
|
||||
// Not null to simplify logic
|
||||
private IdFunction lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
|
||||
private boolean seal_functions;
|
||||
private IdFunction lastFunction = IdFunction.WAS_OVERWRITTEN;
|
||||
|
||||
private boolean seal_functions;
|
||||
|
||||
private boolean useDynamicScope;
|
||||
}
|
||||
|
|
|
@ -121,11 +121,11 @@ public class NativeDate extends IdScriptable {
|
|||
throws JavaScriptException
|
||||
{
|
||||
switch (methodId) {
|
||||
case ConstructorId_UTC: return wrap_dbl
|
||||
case ConstructorId_UTC: return wrap_double
|
||||
(jsStaticFunction_UTC(cx, thisObj, args, f));
|
||||
|
||||
case ConstructorId_parse: return wrap_dbl
|
||||
(jsStaticFunction_parse(to_str(args, 0)));
|
||||
case ConstructorId_parse: return wrap_double
|
||||
(jsStaticFunction_parse(ScriptRuntime.toString(args, 0)));
|
||||
|
||||
case CONSTRUCTOR_ID:
|
||||
return jsConstructor(cx, args, f, thisObj == null);
|
||||
|
@ -139,125 +139,127 @@ public class NativeDate extends IdScriptable {
|
|||
case Id_toDateString: return realThis(thisObj, f, true).
|
||||
jsFunction_toDateString();
|
||||
|
||||
case Id_toLocaleString: return realThis(thisObj, f, true).
|
||||
case Id_toLocaleString: return realThis(thisObj, f, true).
|
||||
jsFunction_toLocaleString();
|
||||
|
||||
case Id_toLocaleTimeString: return realThis(thisObj, f, true).
|
||||
case Id_toLocaleTimeString: return realThis(thisObj, f, true).
|
||||
jsFunction_toLocaleTimeString();
|
||||
|
||||
case Id_toLocaleDateString: return realThis(thisObj, f, true).
|
||||
case Id_toLocaleDateString: return realThis(thisObj, f, true).
|
||||
jsFunction_toLocaleDateString();
|
||||
|
||||
case Id_toUTCString: return realThis(thisObj, f, true).
|
||||
jsFunction_toUTCString();
|
||||
|
||||
case Id_valueOf: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_valueOf: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_valueOf());
|
||||
|
||||
case Id_getTime: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getTime: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getTime());
|
||||
|
||||
case Id_getYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getYear());
|
||||
|
||||
case Id_getFullYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getFullYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getFullYear());
|
||||
|
||||
case Id_getUTCFullYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCFullYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCFullYear());
|
||||
|
||||
case Id_getMonth: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getMonth: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getMonth());
|
||||
|
||||
case Id_getUTCMonth: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCMonth: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMonth());
|
||||
|
||||
case Id_getDate: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getDate: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getDate());
|
||||
|
||||
case Id_getUTCDate: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCDate: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCDate());
|
||||
|
||||
case Id_getDay: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getDay: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getDay());
|
||||
|
||||
case Id_getUTCDay: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCDay: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCDay());
|
||||
|
||||
case Id_getHours: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getHours: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getHours());
|
||||
|
||||
case Id_getUTCHours: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCHours: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCHours());
|
||||
|
||||
case Id_getMinutes: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getMinutes: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getMinutes());
|
||||
|
||||
case Id_getUTCMinutes: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCMinutes: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMinutes());
|
||||
|
||||
case Id_getSeconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getSeconds: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getSeconds());
|
||||
|
||||
case Id_getUTCSeconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getUTCSeconds: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCSeconds());
|
||||
|
||||
case Id_getMilliseconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
case Id_getMilliseconds: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getMilliseconds());
|
||||
|
||||
case Id_getUTCMilliseconds: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMilliseconds());
|
||||
case Id_getUTCMilliseconds:
|
||||
return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getUTCMilliseconds());
|
||||
|
||||
case Id_getTimezoneOffset: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_getTimezoneOffset());
|
||||
case Id_getTimezoneOffset:
|
||||
return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_getTimezoneOffset());
|
||||
|
||||
case Id_setTime: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_setTime(to_dbl(args, 0)));
|
||||
case Id_setTime: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_setTime(ScriptRuntime.toNumber(args, 0)));
|
||||
|
||||
case Id_setMilliseconds: return wrap_dbl
|
||||
case Id_setMilliseconds: return wrap_double
|
||||
(jsFunction_setMilliseconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCMilliseconds: return wrap_dbl(
|
||||
case Id_setUTCMilliseconds: return wrap_double(
|
||||
jsFunction_setUTCMilliseconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setSeconds: return wrap_dbl(
|
||||
case Id_setSeconds: return wrap_double(
|
||||
jsFunction_setSeconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCSeconds:return wrap_dbl(
|
||||
case Id_setUTCSeconds: return wrap_double(
|
||||
jsFunction_setUTCSeconds(cx, thisObj, args, f));
|
||||
|
||||
case Id_setMinutes: return wrap_dbl(
|
||||
case Id_setMinutes: return wrap_double(
|
||||
jsFunction_setMinutes(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCMinutes: return wrap_dbl(
|
||||
case Id_setUTCMinutes: return wrap_double(
|
||||
jsFunction_setUTCMinutes(cx, thisObj, args, f));
|
||||
|
||||
case Id_setHours: return wrap_dbl(
|
||||
case Id_setHours: return wrap_double(
|
||||
jsFunction_setHours(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCHours: return wrap_dbl(
|
||||
case Id_setUTCHours: return wrap_double(
|
||||
jsFunction_setUTCHours(cx, thisObj, args, f));
|
||||
|
||||
case Id_setDate: return wrap_dbl(
|
||||
case Id_setDate: return wrap_double(
|
||||
jsFunction_setDate(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCDate: return wrap_dbl(
|
||||
case Id_setUTCDate: return wrap_double(
|
||||
jsFunction_setUTCDate(cx, thisObj, args, f));
|
||||
|
||||
case Id_setMonth: return wrap_dbl(
|
||||
case Id_setMonth: return wrap_double(
|
||||
jsFunction_setMonth(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCMonth: return wrap_dbl(
|
||||
case Id_setUTCMonth: return wrap_double(
|
||||
jsFunction_setUTCMonth(cx, thisObj, args, f));
|
||||
|
||||
case Id_setFullYear: return wrap_dbl(
|
||||
case Id_setFullYear: return wrap_double(
|
||||
jsFunction_setFullYear(cx, thisObj, args, f));
|
||||
|
||||
case Id_setUTCFullYear: return wrap_dbl(
|
||||
case Id_setUTCFullYear: return wrap_double(
|
||||
jsFunction_setUTCFullYear(cx, thisObj, args, f));
|
||||
|
||||
case Id_setYear: return wrap_dbl(realThis(thisObj, f, true).
|
||||
jsFunction_setYear(to_dbl(args, 0)));
|
||||
case Id_setYear: return wrap_double(realThis(thisObj, f, true).
|
||||
jsFunction_setYear(ScriptRuntime.toNumber(args, 0)));
|
||||
}
|
||||
|
||||
return Scriptable.NOT_FOUND;
|
||||
|
|
|
@ -50,18 +50,62 @@ import java.lang.reflect.Method;
|
|||
* @author Mike Shaver
|
||||
*/
|
||||
|
||||
public class NativeGlobal implements IdFunction.Master {
|
||||
public class NativeGlobal implements ScopeInitializer, IdFunction.Master {
|
||||
|
||||
public static void init(Scriptable scope)
|
||||
throws PropertyException,
|
||||
NotAFunctionException,
|
||||
JavaScriptException
|
||||
{
|
||||
NativeGlobal instance = new NativeGlobal();
|
||||
Context cx = Context.getContext();
|
||||
// We can downcast here because Context.initStandardObjects
|
||||
// takes a ScriptableObject scope.
|
||||
instance.initForGlobal(cx, (ScriptableObject) scope, false);
|
||||
public void scopeInit(Context cx, Scriptable scope, boolean sealed) {
|
||||
|
||||
for (int id = 1; id <= LAST_METHOD_ID; ++id) {
|
||||
String name = getMethodName(id);
|
||||
IdFunction f = new IdFunction(this, name, id);
|
||||
f.setParentScope(scope);
|
||||
if (sealed) { f.sealObject(); }
|
||||
ScriptableObject.defineProperty(scope, name, f,
|
||||
ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
ScriptableObject.defineProperty(scope, "NaN",
|
||||
ScriptRuntime.NaNobj,
|
||||
ScriptableObject.DONTENUM);
|
||||
ScriptableObject.defineProperty(scope, "Infinity",
|
||||
new Double(Double.POSITIVE_INFINITY),
|
||||
ScriptableObject.DONTENUM);
|
||||
ScriptableObject.defineProperty(scope, "undefined",
|
||||
Undefined.instance,
|
||||
ScriptableObject.DONTENUM);
|
||||
|
||||
String[] errorMethods = { "ConversionError",
|
||||
"EvalError",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"URIError"
|
||||
};
|
||||
|
||||
/*
|
||||
Each error constructor gets its own Error object as a prototype,
|
||||
with the 'name' property set to the name of the error.
|
||||
*/
|
||||
for (int i = 0; i < errorMethods.length; i++) {
|
||||
String name = errorMethods[i];
|
||||
IdFunction ctor = new IdFunction(this, name, Id_new_CommonError);
|
||||
ctor.setFunctionType(IdFunction.FUNCTION_AND_CONSTRUCTOR);
|
||||
ctor.setParentScope(scope);
|
||||
ScriptableObject.defineProperty(scope, name, ctor,
|
||||
ScriptableObject.DONTENUM);
|
||||
|
||||
Scriptable errorProto = ScriptRuntime.newObject
|
||||
(cx, scope, "Error", ScriptRuntime.emptyArgs);
|
||||
|
||||
errorProto.put("name", errorProto, name);
|
||||
ctor.put("prototype", ctor, errorProto);
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
if (errorProto instanceof ScriptableObject) {
|
||||
((ScriptableObject)errorProto).sealObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object execMethod(int methodId, IdFunction function, Context cx,
|
||||
|
@ -112,60 +156,6 @@ public class NativeGlobal implements IdFunction.Master {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void initForGlobal(Context cx, ScriptableObject global,
|
||||
boolean sealed)
|
||||
throws PropertyException,
|
||||
NotAFunctionException,
|
||||
JavaScriptException
|
||||
{
|
||||
for (int id = 1; id <= LAST_METHOD_ID; ++id) {
|
||||
String name = getMethodName(id);
|
||||
IdFunction f = new IdFunction(this, name, id);
|
||||
f.setParentScope(global);
|
||||
if (sealed) { f.sealObject(); }
|
||||
global.defineProperty(name, f, ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
global.defineProperty("NaN", ScriptRuntime.NaNobj,
|
||||
ScriptableObject.DONTENUM);
|
||||
global.defineProperty("Infinity", new Double(Double.POSITIVE_INFINITY),
|
||||
ScriptableObject.DONTENUM);
|
||||
global.defineProperty("undefined", Undefined.instance,
|
||||
ScriptableObject.DONTENUM);
|
||||
|
||||
String[] errorMethods = { "ConversionError",
|
||||
"EvalError",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"URIError"
|
||||
};
|
||||
|
||||
/*
|
||||
Each error constructor gets its own Error object as a prototype,
|
||||
with the 'name' property set to the name of the error.
|
||||
*/
|
||||
for (int i = 0; i < errorMethods.length; i++) {
|
||||
String name = errorMethods[i];
|
||||
IdFunction ctor = new IdFunction(this, name, Id_new_CommonError);
|
||||
ctor.setFunctionType(IdFunction.FUNCTION_AND_CONSTRUCTOR);
|
||||
ctor.setParentScope(global);
|
||||
global.defineProperty(name, ctor, ScriptableObject.DONTENUM);
|
||||
|
||||
Scriptable errorProto = cx.newObject(global, "Error");
|
||||
errorProto.put("name", errorProto, name);
|
||||
ctor.put("prototype", ctor, errorProto);
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
if (errorProto instanceof ScriptableObject) {
|
||||
((ScriptableObject)errorProto).sealObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The global method parseInt, as per ECMA-262 15.1.2.2.
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче