зеркало из 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
|
* @see org.mozilla.javascript.Scriptable#getClassName
|
||||||
*/
|
*/
|
||||||
public void addAsConstructor(Scriptable scope, Scriptable prototype)
|
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);
|
ScriptRuntime.setFunctionProtoAndParent(this, scope);
|
||||||
setImmunePrototypeProperty(prototype);
|
setImmunePrototypeProperty(prototype);
|
||||||
|
|
||||||
prototype.setParentScope(this);
|
prototype.setParentScope(this);
|
||||||
|
|
||||||
final int attr = ScriptableObject.DONTENUM |
|
defineProperty(prototype, "constructor", this,
|
||||||
ScriptableObject.PERMANENT |
|
ScriptableObject.DONTENUM |
|
||||||
ScriptableObject.READONLY;
|
ScriptableObject.PERMANENT |
|
||||||
defineProperty(prototype, "constructor", this, attr);
|
ScriptableObject.READONLY);
|
||||||
|
|
||||||
String name = prototype.getClassName();
|
|
||||||
defineProperty(scope, name, this, ScriptableObject.DONTENUM);
|
|
||||||
|
|
||||||
setParentScope(scope);
|
setParentScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*
|
*
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* Norris Boyd
|
* Norris Boyd
|
||||||
|
* Igor Bukanov
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* 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
|
* the GNU General Public License Version 2 or later (the "GPL"), in which
|
||||||
|
@ -38,7 +39,6 @@
|
||||||
|
|
||||||
package org.mozilla.javascript;
|
package org.mozilla.javascript;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,81 +46,88 @@ import java.lang.reflect.*;
|
||||||
*
|
*
|
||||||
* <p> This improves startup time and average memory usage.
|
* <p> This improves startup time and average memory usage.
|
||||||
*/
|
*/
|
||||||
public final class LazilyLoadedCtor implements Serializable {
|
public final class LazilyLoadedCtor implements java.io.Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
public LazilyLoadedCtor(ScriptableObject scope,
|
private static final int STATE_BEFORE_INIT = 0;
|
||||||
String ctorName, String className, boolean sealed)
|
private static final int STATE_INITIALIZING = 1;
|
||||||
|
private static final int STATE_WITH_VALUE = 2;
|
||||||
|
|
||||||
|
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.className = className;
|
||||||
this.ctorName = ctorName;
|
|
||||||
this.sealed = sealed;
|
this.sealed = sealed;
|
||||||
|
this.state = STATE_BEFORE_INIT;
|
||||||
|
|
||||||
if (setter == null) {
|
scope.addLazilyInitializedValue(propertyName, 0, this,
|
||||||
Method[] methods = FunctionObject.getMethodList(getClass());
|
ScriptableObject.DONTENUM);
|
||||||
getter = FunctionObject.findSingleMethod(methods, "getProperty");
|
|
||||||
setter = FunctionObject.findSingleMethod(methods, "setProperty");
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.defineProperty(ctorName, this, getter, setter,
|
|
||||||
ScriptableObject.DONTENUM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getProperty(ScriptableObject obj) {
|
void init()
|
||||||
synchronized (obj) {
|
{
|
||||||
if (!isReplaced) {
|
synchronized (this) {
|
||||||
boolean removeOnError = false;
|
if (state == STATE_INITIALIZING)
|
||||||
Class cl = Kit.classOrNull(className);
|
throw new IllegalStateException(
|
||||||
if (cl == null) {
|
"Recursive initialization for "+propertyName);
|
||||||
removeOnError = true;
|
if (state == STATE_BEFORE_INIT) {
|
||||||
} else {
|
state = STATE_INITIALIZING;
|
||||||
try {
|
// Set value now to have something to set in finaly block if
|
||||||
ScriptableObject.defineClass(obj, cl, sealed);
|
// buildValue throws.
|
||||||
isReplaced = true;
|
Object value = Undefined.instance;
|
||||||
} catch (InvocationTargetException ex) {
|
try {
|
||||||
Throwable target = ex.getTargetException();
|
value = buildValue();
|
||||||
if (target instanceof RuntimeException) {
|
} finally {
|
||||||
throw (RuntimeException)target;
|
initializedValue = value;
|
||||||
}
|
state = STATE_WITH_VALUE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get just added object
|
|
||||||
return obj.get(ctorName, obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object setProperty(ScriptableObject obj, Object val) {
|
Object getValue()
|
||||||
synchronized (obj) {
|
{
|
||||||
isReplaced = true;
|
if (state != STATE_WITH_VALUE)
|
||||||
return val;
|
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;
|
static final long serialVersionUID = 6358550398665688245L;
|
||||||
|
|
||||||
|
private transient Member memberObject;
|
||||||
|
transient Class[] argTypes;
|
||||||
|
Object delegateTo;
|
||||||
|
|
||||||
MemberBox(Method method)
|
MemberBox(Method method)
|
||||||
{
|
{
|
||||||
init(method);
|
init(method);
|
||||||
|
@ -343,8 +347,5 @@ final class MemberBox implements Serializable
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private transient Member memberObject;
|
|
||||||
transient Class[] argTypes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,10 @@ public class NativeObject extends IdScriptableObject
|
||||||
arity=1; s="propertyIsEnumerable"; break;
|
arity=1; s="propertyIsEnumerable"; break;
|
||||||
case Id_isPrototypeOf: arity=1; s="isPrototypeOf"; break;
|
case Id_isPrototypeOf: arity=1; s="isPrototypeOf"; break;
|
||||||
case Id_toSource: arity=0; s="toSource"; 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));
|
default: throw new IllegalArgumentException(String.valueOf(id));
|
||||||
}
|
}
|
||||||
initPrototypeMethod(OBJECT_TAG, id, s, arity);
|
initPrototypeMethod(OBJECT_TAG, id, s, arity);
|
||||||
|
@ -185,7 +189,32 @@ public class NativeObject extends IdScriptableObject
|
||||||
case Id_toSource:
|
case Id_toSource:
|
||||||
return ScriptRuntime.defaultObjectToSource(cx, scope, thisObj,
|
return ScriptRuntime.defaultObjectToSource(cx, scope, thisObj,
|
||||||
args);
|
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)
|
protected int findPrototypeId(String s)
|
||||||
{
|
{
|
||||||
int id;
|
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;
|
L0: { id = 0; String X = null; int c;
|
||||||
L: switch (s.length()) {
|
L: switch (s.length()) {
|
||||||
case 7: X="valueOf";id=Id_valueOf; break L;
|
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; }
|
if (c=='h') { X="hasOwnProperty";id=Id_hasOwnProperty; }
|
||||||
else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }
|
else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; }
|
||||||
break L;
|
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;
|
case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; break L;
|
||||||
}
|
}
|
||||||
if (X!=null && X!=s && !X.equals(s)) id = 0;
|
if (X!=null && X!=s && !X.equals(s)) id = 0;
|
||||||
|
@ -225,7 +258,9 @@ public class NativeObject extends IdScriptableObject
|
||||||
Id_propertyIsEnumerable = 6,
|
Id_propertyIsEnumerable = 6,
|
||||||
Id_isPrototypeOf = 7,
|
Id_isPrototypeOf = 7,
|
||||||
Id_toSource = 8,
|
Id_toSource = 8,
|
||||||
MAX_PROTOTYPE_ID = 8;
|
Id___defineGetter__ = 9,
|
||||||
|
Id___defineSetter__ = 10,
|
||||||
|
MAX_PROTOTYPE_ID = 10;
|
||||||
|
|
||||||
// #/string_id_map#
|
// #/string_id_map#
|
||||||
}
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -514,6 +514,9 @@ msg.obj.getter.parms =\
|
||||||
msg.getter.static =\
|
msg.getter.static =\
|
||||||
Getter and setter must both be static or neither be 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 =\
|
msg.setter2.parms =\
|
||||||
Two-parameter setter must take a ScriptableObject as its first parameter.
|
Two-parameter setter must take a ScriptableObject as its first parameter.
|
||||||
|
|
||||||
|
@ -539,6 +542,9 @@ msg.remove.sealed =\
|
||||||
msg.modify.sealed =\
|
msg.modify.sealed =\
|
||||||
Cannot modify a property of a sealed object: {0}.
|
Cannot modify a property of a sealed object: {0}.
|
||||||
|
|
||||||
|
msg.modify.readonly =\
|
||||||
|
Cannot modify readonly property: {0}.
|
||||||
|
|
||||||
# TokenStream
|
# TokenStream
|
||||||
msg.missing.exponent =\
|
msg.missing.exponent =\
|
||||||
missing exponent
|
missing exponent
|
||||||
|
|
Загрузка…
Ссылка в новой задаче