Changing behavior of sealed objects to throw an exception on any attempt to modify them including changing values of existing properties. In the same time making object sealed does not affect read-only status of its properties which allows to override properties of objects with a sealed object as a prototype.

Rhino shell now accepts -sealedlib option to seal all standard objects.
This commit is contained in:
igor%mir2.org 2003-05-16 14:25:57 +00:00
Родитель 78d341b0c4
Коммит 3f84d7fe70
7 изменённых файлов: 73 добавлений и 25 удалений

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

@ -99,8 +99,12 @@ public abstract class IdScriptable extends ScriptableObject
if (maxId != 0) {
int id = mapNameToId_cached(name);
if (id != 0) {
if (start == this && isSealed()) {
throw Context.reportRuntimeError1("msg.modify.sealed",
name);
}
int attr = getIdAttributes(id);
if ((attr & READONLY) == 0 && !isSealed()) {
if ((attr & READONLY) == 0) {
if (start == this) {
setIdValue(id, value);
}

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

@ -80,7 +80,11 @@ public class ImporterTopLevel extends ScriptableObject {
}
public ImporterTopLevel(Context cx) {
cx.initStandardObjects(this);
this(cx, false);
}
public ImporterTopLevel(Context cx, boolean sealed) {
cx.initStandardObjects(this, sealed);
init();
}

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

@ -231,41 +231,45 @@ public class NativeArray extends IdScriptable {
public void put(String id, Scriptable start, Object value)
{
super.put(id, start, value);
if (start == this) {
// If the object is sealed, super will throw exception
long index = toArrayIndex(id);
if (index >= length) {
length = index + 1;
}
}
super.put(id, start, value);
}
public void put(int index, Scriptable start, Object value)
{
if (start == this && !isSealed()
&& dense != null && 0 <= index && index < dense.length)
{
// If start == this && sealed, super will throw exception
dense[index] = value;
} else {
super.put(index, start, value);
}
if (start == this) {
// only set the array length if given an array index (ECMA 15.4.0)
if (this.length <= index) {
// avoid overflowing index!
this.length = (long)index + 1;
}
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = value;
return;
}
}
super.put(index, start, value);
}
public void delete(int index)
{
if (!isSealed()) {
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = NOT_FOUND;
return;
}
if (!isSealed()
&& dense != null && 0 <= index && index < dense.length)
{
dense[index] = NOT_FOUND;
} else {
super.delete(index);
}
super.delete(index);
}
public Object[] getIds()

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

@ -256,8 +256,10 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
}
// Note: cache is not updated in put
}
if ((slot.attributes & ScriptableObject.READONLY) != 0 || isSealed()) {
if (start == this && isSealed()) {
throw Context.reportRuntimeError1("msg.modify.sealed", name);
}
if ((slot.attributes & ScriptableObject.READONLY) != 0) {
return;
}
if ((slot.flags & Slot.HAS_SETTER) != 0) {
@ -293,9 +295,16 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
setterThis = start;
args = new Object[] { actualArg };
} else {
if (start != this) Context.codeBug();
setterThis = slot.delegateTo;
args = new Object[] { this, actualArg };
}
// Check start is sealed: start is always instance of ScriptableObject
// due to logic in if (start != this) above
if (((ScriptableObject)start).isSealed()) {
throw Context.reportRuntimeError1("msg.modify.sealed",
slot.stringKey);
}
try {
setterResult = slot.setter.invoke(setterThis, args);
@ -343,8 +352,13 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
}
slot = getSlotToSet(null, index);
}
if ((slot.attributes & ScriptableObject.READONLY) != 0 || isSealed())
if (start == this && isSealed()) {
throw Context.reportRuntimeError1("msg.modify.sealed",
Integer.toString(index));
}
if ((slot.attributes & ScriptableObject.READONLY) != 0) {
return;
}
if (this == start) {
slot.value = value;
} else {
@ -1571,8 +1585,10 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
* caused the table to grow while this thread was searching.
*/
private synchronized Slot addSlot(String id, int index, Slot newSlot) {
if (isSealed())
throw Context.reportRuntimeError0("msg.add.sealed");
if (isSealed()) {
String str = (id != null) ? id : Integer.toString(index);
throw Context.reportRuntimeError1("msg.add.sealed", str);
}
if (slots == null) { slots = new Slot[5]; }
@ -1619,8 +1635,10 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
* deletes are not common.
*/
private synchronized void removeSlot(String name, int index) {
if (isSealed())
throw Context.reportRuntimeError0("msg.remove.sealed");
if (isSealed()) {
String str = (name != null) ? name : Integer.toString(index);
throw Context.reportRuntimeError1("msg.remove.sealed", str);
}
int i = getSlotPosition(slots, name, index);
if (i >= 0) {

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

@ -430,10 +430,13 @@ msg.setter.parms =\
Expected either one or two parameters for setter.
msg.add.sealed =\
Cannot add a property to a sealed object.
Cannot add a property to a sealed object: {0}.
msg.remove.sealed =\
Cannot remove a property from a sealed object.
Cannot remove a property from a sealed object: {0}.
msg.modify.sealed =\
Cannot modify a property of a sealed object: {0}.
# TokenStream
msg.missing.exponent =\

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

@ -58,7 +58,7 @@ public class Global extends ImporterTopLevel {
{
// Define some global functions particular to the shell. Note
// that these functions are not part of ECMA.
super(cx);
super(cx, Main.sealedStdLib);
String[] names = { "print", "quit", "version", "load", "help",
"loadClass", "defineClass", "spawn", "sync",
"serialize", "deserialize", "runCommand" };

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

@ -82,6 +82,15 @@ public class Main {
* Execute the given arguments, but don't System.exit at the end.
*/
public static int exec(String args[]) {
for (int i=0; i < args.length; i++) {
String arg = args[i];
if (arg.equals("-sealedlib")) {
sealedStdLib = true;
break;
}
}
Context cx = enterContext();
// Create the top-level scope object.
global = getGlobal();
@ -177,6 +186,11 @@ public class Main {
fileList.addElement(args[i].equals("-") ? null : args[i]);
continue;
}
if (arg.equals("-sealedlib")) {
// Should already be processed
if (!sealedStdLib) Context.codeBug();
continue;
}
usage(arg);
}
return new String[0];
@ -447,6 +461,7 @@ public class Main {
static private final int EXITCODE_FILE_NOT_FOUND = 4;
//static private DebugShell debugShell;
static boolean processStdin = true;
static boolean sealedStdLib = false;
static Vector fileList = new Vector(5);
private static SecurityProxy securityImpl;
}