Partial fix for bug #224334: implements __defineGetter__ and __defineSetter__.

This commit is contained in:
inonit%inonit.com 2007-01-19 21:43:49 +00:00
Родитель 8006d4dc8a
Коммит d7a73ba3b4
6 изменённых файлов: 758 добавлений и 520 удалений

Просмотреть файл

@ -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