зеркало из https://github.com/mozilla/pjs.git
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:
Родитель
5bbc5dcc41
Коммит
335b23c60e
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче