зеркало из https://github.com/mozilla/gecko-dev.git
Partial fix for bug #224334: implements __defineGetter__ and __defineSetter__.
This commit is contained in:
Родитель
8006d4dc8a
Коммит
d7a73ba3b4
|
@ -354,20 +354,23 @@ public class FunctionObject extends BaseFunction
|
|||
* @see org.mozilla.javascript.Scriptable#getClassName
|
||||
*/
|
||||
public void addAsConstructor(Scriptable scope, Scriptable prototype)
|
||||
{
|
||||
initAsConstructor(scope, prototype);
|
||||
defineProperty(scope, prototype.getClassName(),
|
||||
this, ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
void initAsConstructor(Scriptable scope, Scriptable prototype)
|
||||
{
|
||||
ScriptRuntime.setFunctionProtoAndParent(this, scope);
|
||||
setImmunePrototypeProperty(prototype);
|
||||
|
||||
prototype.setParentScope(this);
|
||||
|
||||
final int attr = ScriptableObject.DONTENUM |
|
||||
ScriptableObject.PERMANENT |
|
||||
ScriptableObject.READONLY;
|
||||
defineProperty(prototype, "constructor", this, attr);
|
||||
|
||||
String name = prototype.getClassName();
|
||||
defineProperty(scope, name, this, ScriptableObject.DONTENUM);
|
||||
|
||||
defineProperty(prototype, "constructor", this,
|
||||
ScriptableObject.DONTENUM |
|
||||
ScriptableObject.PERMANENT |
|
||||
ScriptableObject.READONLY);
|
||||
setParentScope(scope);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*
|
||||
* Contributor(s):
|
||||
* Norris Boyd
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License Version 2 or later (the "GPL"), in which
|
||||
|
@ -38,7 +39,6 @@
|
|||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
/**
|
||||
|
@ -46,81 +46,88 @@ import java.lang.reflect.*;
|
|||
*
|
||||
* <p> This improves startup time and average memory usage.
|
||||
*/
|
||||
public final class LazilyLoadedCtor implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public final class LazilyLoadedCtor implements java.io.Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int STATE_BEFORE_INIT = 0;
|
||||
private static final int STATE_INITIALIZING = 1;
|
||||
private static final int STATE_WITH_VALUE = 2;
|
||||
|
||||
public LazilyLoadedCtor(ScriptableObject scope,
|
||||
String ctorName, String className, boolean sealed)
|
||||
private final ScriptableObject scope;
|
||||
private final String propertyName;
|
||||
private final String className;
|
||||
private final boolean sealed;
|
||||
private Object initializedValue;
|
||||
private int state;
|
||||
|
||||
public LazilyLoadedCtor(ScriptableObject scope, String propertyName,
|
||||
String className, boolean sealed)
|
||||
{
|
||||
|
||||
this.scope = scope;
|
||||
this.propertyName = propertyName;
|
||||
this.className = className;
|
||||
this.ctorName = ctorName;
|
||||
this.sealed = sealed;
|
||||
this.state = STATE_BEFORE_INIT;
|
||||
|
||||
if (setter == null) {
|
||||
Method[] methods = FunctionObject.getMethodList(getClass());
|
||||
getter = FunctionObject.findSingleMethod(methods, "getProperty");
|
||||
setter = FunctionObject.findSingleMethod(methods, "setProperty");
|
||||
}
|
||||
|
||||
scope.defineProperty(ctorName, this, getter, setter,
|
||||
ScriptableObject.DONTENUM);
|
||||
scope.addLazilyInitializedValue(propertyName, 0, this,
|
||||
ScriptableObject.DONTENUM);
|
||||
}
|
||||
|
||||
public Object getProperty(ScriptableObject obj) {
|
||||
synchronized (obj) {
|
||||
if (!isReplaced) {
|
||||
boolean removeOnError = false;
|
||||
Class cl = Kit.classOrNull(className);
|
||||
if (cl == null) {
|
||||
removeOnError = true;
|
||||
} else {
|
||||
try {
|
||||
ScriptableObject.defineClass(obj, cl, sealed);
|
||||
isReplaced = true;
|
||||
} catch (InvocationTargetException ex) {
|
||||
Throwable target = ex.getTargetException();
|
||||
if (target instanceof RuntimeException) {
|
||||
throw (RuntimeException)target;
|
||||
}
|
||||
removeOnError = true;
|
||||
} catch (RhinoException ex) {
|
||||
removeOnError = true;
|
||||
} catch (InstantiationException ex) {
|
||||
removeOnError = true;
|
||||
} catch (IllegalAccessException ex) {
|
||||
removeOnError = true;
|
||||
} catch (SecurityException ex) {
|
||||
// Treat security exceptions as absence of object.
|
||||
// They can be due to the following reasons:
|
||||
// java.lang.RuntimePermission createClassLoader
|
||||
removeOnError = true;
|
||||
} catch (LinkageError ex) {
|
||||
// No dependant classes
|
||||
removeOnError = true;
|
||||
}
|
||||
}
|
||||
if (removeOnError) {
|
||||
obj.delete(ctorName);
|
||||
return Scriptable.NOT_FOUND;
|
||||
void init()
|
||||
{
|
||||
synchronized (this) {
|
||||
if (state == STATE_INITIALIZING)
|
||||
throw new IllegalStateException(
|
||||
"Recursive initialization for "+propertyName);
|
||||
if (state == STATE_BEFORE_INIT) {
|
||||
state = STATE_INITIALIZING;
|
||||
// Set value now to have something to set in finaly block if
|
||||
// buildValue throws.
|
||||
Object value = Undefined.instance;
|
||||
try {
|
||||
value = buildValue();
|
||||
} finally {
|
||||
initializedValue = value;
|
||||
state = STATE_WITH_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get just added object
|
||||
return obj.get(ctorName, obj);
|
||||
}
|
||||
|
||||
public Object setProperty(ScriptableObject obj, Object val) {
|
||||
synchronized (obj) {
|
||||
isReplaced = true;
|
||||
return val;
|
||||
Object getValue()
|
||||
{
|
||||
if (state != STATE_WITH_VALUE)
|
||||
throw new IllegalStateException(propertyName);
|
||||
return initializedValue;
|
||||
}
|
||||
|
||||
private Object buildValue()
|
||||
{
|
||||
Class cl = Kit.classOrNull(className);
|
||||
if (cl != null) {
|
||||
try {
|
||||
Object value = ScriptableObject.buildClassCtor(scope, cl,
|
||||
sealed, false);
|
||||
if (value == null) {
|
||||
// cl has own static initializer which is expected
|
||||
// to set the property on its own.
|
||||
value = scope.get(propertyName, scope);
|
||||
if (value != Scriptable.NOT_FOUND)
|
||||
return value;
|
||||
}
|
||||
} catch (InvocationTargetException ex) {
|
||||
Throwable target = ex.getTargetException();
|
||||
if (target instanceof RuntimeException) {
|
||||
throw (RuntimeException)target;
|
||||
}
|
||||
} catch (RhinoException ex) {
|
||||
} catch (InstantiationException ex) {
|
||||
} catch (IllegalAccessException ex) {
|
||||
} catch (SecurityException ex) {
|
||||
}
|
||||
}
|
||||
return Undefined.instance;
|
||||
}
|
||||
|
||||
private static Method getter, setter;
|
||||
|
||||
private String ctorName;
|
||||
private String className;
|
||||
private boolean sealed;
|
||||
private boolean isReplaced;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,10 @@ final class MemberBox implements Serializable
|
|||
{
|
||||
static final long serialVersionUID = 6358550398665688245L;
|
||||
|
||||
private transient Member memberObject;
|
||||
transient Class[] argTypes;
|
||||
Object delegateTo;
|
||||
|
||||
MemberBox(Method method)
|
||||
{
|
||||
init(method);
|
||||
|
@ -343,8 +347,5 @@ final class MemberBox implements Serializable
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private transient Member memberObject;
|
||||
transient Class[] argTypes;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,10 @@ public class NativeObject extends IdScriptableObject
|
|||
arity=1; s="propertyIsEnumerable"; break;
|
||||
case Id_isPrototypeOf: arity=1; s="isPrototypeOf"; break;
|
||||
case Id_toSource: arity=0; s="toSource"; break;
|
||||
case Id___defineGetter__:
|
||||
arity=2; s="__defineGetter__"; break;
|
||||
case Id___defineSetter__:
|
||||
arity=2; s="__defineSetter__"; break;
|
||||
default: throw new IllegalArgumentException(String.valueOf(id));
|
||||
}
|
||||
initPrototypeMethod(OBJECT_TAG, id, s, arity);
|
||||
|
@ -185,7 +189,32 @@ public class NativeObject extends IdScriptableObject
|
|||
case Id_toSource:
|
||||
return ScriptRuntime.defaultObjectToSource(cx, scope, thisObj,
|
||||
args);
|
||||
default: throw new IllegalArgumentException(String.valueOf(id));
|
||||
case Id___defineGetter__:
|
||||
case Id___defineSetter__:
|
||||
{
|
||||
if (args.length < 2 || !(args[1] instanceof Callable)) {
|
||||
Object badArg = (args.length >= 2 ? args[1]
|
||||
: Undefined.instance);
|
||||
throw ScriptRuntime.notFunctionError(badArg);
|
||||
}
|
||||
if (!(thisObj instanceof ScriptableObject)) {
|
||||
throw Context.reportRuntimeError2(
|
||||
"msg.extend.scriptable",
|
||||
thisObj.getClass().getName(),
|
||||
String.valueOf(args[0]));
|
||||
}
|
||||
ScriptableObject so = (ScriptableObject)thisObj;
|
||||
String name = ScriptRuntime.toStringIdOrIndex(cx, args[0]);
|
||||
int index = (name != null ? 0
|
||||
: ScriptRuntime.lastIndexResult(cx));
|
||||
Callable getterOrSetter = (Callable)args[1];
|
||||
boolean isSetter = (id == Id___defineSetter__);
|
||||
so.setGetterOrSetter(name, index, getterOrSetter, isSetter);
|
||||
}
|
||||
return Undefined.instance;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException(String.valueOf(id));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,7 +223,7 @@ public class NativeObject extends IdScriptableObject
|
|||
protected int findPrototypeId(String s)
|
||||
{
|
||||
int id;
|
||||
// #generated# Last update: 2003-11-11 01:51:40 CET
|
||||
// #generated# Last update: 2005-10-03 14:46:07 CEST
|
||||
L0: { id = 0; String X = null; int c;
|
||||
L: switch (s.length()) {
|
||||
case 7: X="valueOf";id=Id_valueOf; break L;
|
||||
|
@ -208,6 +237,10 @@ public class NativeObject extends IdScriptableObject
|
|||
if (c=='h') { X="hasOwnProperty";id=Id_hasOwnProperty; }
|
||||
else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }
|
||||
break L;
|
||||
case 16: c=s.charAt(8);
|
||||
if (c=='G') { X="__defineGetter__";id=Id___defineGetter__; }
|
||||
else if (c=='S') { X="__defineSetter__";id=Id___defineSetter__; }
|
||||
break L;
|
||||
case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; break L;
|
||||
}
|
||||
if (X!=null && X!=s && !X.equals(s)) id = 0;
|
||||
|
@ -225,7 +258,9 @@ public class NativeObject extends IdScriptableObject
|
|||
Id_propertyIsEnumerable = 6,
|
||||
Id_isPrototypeOf = 7,
|
||||
Id_toSource = 8,
|
||||
MAX_PROTOTYPE_ID = 8;
|
||||
Id___defineGetter__ = 9,
|
||||
Id___defineSetter__ = 10,
|
||||
MAX_PROTOTYPE_ID = 10;
|
||||
|
||||
// #/string_id_map#
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -514,6 +514,9 @@ msg.obj.getter.parms =\
|
|||
msg.getter.static =\
|
||||
Getter and setter must both be static or neither be static.
|
||||
|
||||
msg.setter.return =\
|
||||
Setter must have void return type: {0}
|
||||
|
||||
msg.setter2.parms =\
|
||||
Two-parameter setter must take a ScriptableObject as its first parameter.
|
||||
|
||||
|
@ -539,6 +542,9 @@ msg.remove.sealed =\
|
|||
msg.modify.sealed =\
|
||||
Cannot modify a property of a sealed object: {0}.
|
||||
|
||||
msg.modify.readonly =\
|
||||
Cannot modify readonly property: {0}.
|
||||
|
||||
# TokenStream
|
||||
msg.missing.exponent =\
|
||||
missing exponent
|
||||
|
|
Загрузка…
Ссылка в новой задаче