Skip to content

Commit

Permalink
NativeProxy has to support revoking from a trap
Browse files Browse the repository at this point in the history
SymbolKeys are shallowEq to symbols
isArray has to take care of proxies
  • Loading branch information
rbri committed Aug 24, 2023
1 parent f0f9aa6 commit 2e58558
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 34 deletions.
3 changes: 3 additions & 0 deletions src/org/mozilla/javascript/NativeArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -2241,6 +2241,9 @@ private static boolean js_isArray(Object o) {
if (!(o instanceof Scriptable)) {
return false;
}
if (o instanceof NativeProxy) {
return js_isArray(((NativeProxy)o).getTargetThrowIfRevoked());
}
return "Array".equals(((Scriptable) o).getClassName());
}

Expand Down
65 changes: 33 additions & 32 deletions src/org/mozilla/javascript/NativeProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ final class NativeProxy extends ScriptableObject implements Callable, Constructa
private static final String TRAP_APPLY = "apply";
private static final String TRAP_CONSTRUCT = "construct";

private ScriptableObject target;
private Scriptable handler;
private ScriptableObject targetObj;
private Scriptable handlerObj;
private final String typeOf;

private static final class Revoker implements Callable {
Expand All @@ -49,8 +49,8 @@ public Revoker(NativeProxy proxy) {
@Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
if (revocableProxy != null) {
revocableProxy.handler = null;
revocableProxy.target = null;
revocableProxy.handlerObj = null;
revocableProxy.targetObj = null;
revocableProxy = null;
}
return Undefined.instance;
Expand Down Expand Up @@ -88,8 +88,8 @@ public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
}

private NativeProxy(ScriptableObject target, Scriptable handler) {
this.target = target;
this.handler = handler;
this.targetObj = target;
this.handlerObj = handler;

if (target == null || !(target instanceof Callable)) {
typeOf = super.getTypeOf();
Expand All @@ -100,7 +100,7 @@ private NativeProxy(ScriptableObject target, Scriptable handler) {

@Override
public String getClassName() {
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();
return target.getClassName();
}

Expand All @@ -124,7 +124,7 @@ public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
* 10. If Type(newObj) is not Object, throw a TypeError exception.
* 11. Return newObj.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_CONSTRUCT);
if (trap != null) {
Expand Down Expand Up @@ -161,7 +161,7 @@ public boolean has(String name, Scriptable start) {
* iii. If extensibleTarget is false, throw a TypeError exception.
* 10. Return booleanTrapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_HAS);
if (trap != null) {
Expand Down Expand Up @@ -211,7 +211,7 @@ public boolean has(int index, Scriptable start) {
* iii. If extensibleTarget is false, throw a TypeError exception.
* 10. Return booleanTrapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_HAS);
if (trap != null) {
Expand Down Expand Up @@ -241,7 +241,7 @@ public boolean has(int index, Scriptable start) {
*/
@Override
public boolean has(Symbol key, Scriptable start) {
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_HAS);
if (trap != null) {
Expand Down Expand Up @@ -307,7 +307,7 @@ Object[] getIds(boolean getNonEnumerable, boolean getSymbols) {
* 22. If uncheckedResultKeys is not empty, throw a TypeError exception.
* 23. Return trapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_OWN_KEYS);
if (trap != null) {
Expand Down Expand Up @@ -407,7 +407,7 @@ public Object get(String name, Scriptable start) {
* i. If trapResult is not undefined, throw a TypeError exception.
* 11. Return trapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_GET);
if (trap != null) {
Expand Down Expand Up @@ -463,7 +463,7 @@ public Object get(int index, Scriptable start) {
* i. If trapResult is not undefined, throw a TypeError exception.
* 11. Return trapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_GET);
if (trap != null) {
Expand Down Expand Up @@ -519,7 +519,7 @@ public Object get(Symbol key, Scriptable start) {
* i. If trapResult is not undefined, throw a TypeError exception.
* 11. Return trapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_GET);
if (trap != null) {
Expand Down Expand Up @@ -579,7 +579,7 @@ public void put(String name, Scriptable start, Object value) {
* i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
* 12. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_SET);
if (trap != null) {
Expand Down Expand Up @@ -614,7 +614,7 @@ public void put(int index, Scriptable start, Object value) {
* i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
* 12. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_SET);
if (trap != null) {
Expand Down Expand Up @@ -649,7 +649,7 @@ public void put(Symbol key, Scriptable start, Object value) {
* i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
* 12. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_SET);
if (trap != null) {
Expand Down Expand Up @@ -688,7 +688,7 @@ public void delete(String name) {
* 14. If extensibleTarget is false, throw a TypeError exception.
* 15. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_DELETE_PROPERTY);
if (trap != null) {
Expand Down Expand Up @@ -738,7 +738,7 @@ public void delete(int index) {
* 14. If extensibleTarget is false, throw a TypeError exception.
* 15. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_DELETE_PROPERTY);
if (trap != null) {
Expand Down Expand Up @@ -788,7 +788,7 @@ public void delete(Symbol key) {
* 14. If extensibleTarget is false, throw a TypeError exception.
* 15. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_DELETE_PROPERTY);
if (trap != null) {
Expand Down Expand Up @@ -851,7 +851,7 @@ protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) {
* i. If targetDesc.[[Writable]] is true, throw a TypeError exception.
* 18. Return resultDesc.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_GET_OWN_PROPERTY_DESCRIPTOR);
if (trap != null) {
Expand Down Expand Up @@ -939,7 +939,7 @@ public void defineOwnProperty(Context cx, Object id, ScriptableObject desc) {
* i. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception.
* 17. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_DEFINE_PROPERTY);
if (trap != null) {
Expand Down Expand Up @@ -968,7 +968,7 @@ public boolean isExtensible() {
* 9. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception.
* 10. Return booleanTrapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_IS_EXTENSIBLE);
if (trap == null) {
Expand Down Expand Up @@ -1005,7 +1005,7 @@ public void preventExtensions() {
* b. If extensibleTarget is true, throw a TypeError exception.
* 9. Return booleanTrapResult.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_PREVENT_EXTENSIONS);
if (trap == null) {
Expand Down Expand Up @@ -1045,7 +1045,7 @@ public Scriptable getPrototype() {
* 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
* 13. Return handlerProto.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_GET_PROTOTYPE_OF);
if (trap != null) {
Expand Down Expand Up @@ -1101,7 +1101,7 @@ public void setPrototype(Scriptable prototype) {
* 13. If SameValue(V, targetProto) is false, throw a TypeError exception.
* 14. Return true.
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Callable trap = getTrap(TRAP_SET_PROTOTYPE_OF);
if (trap != null) {
Expand Down Expand Up @@ -1137,7 +1137,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar
* 7. Let argArray be ! CreateArrayFromList(argumentsList).
* 8. Return ? Call(trap, handler, « target, thisArgument, argArray »).
*/
assertNotRevoked();
ScriptableObject target = getTargetThrowIfRevoked();

Scriptable argumentsList = cx.newArray(scope, args);

Expand Down Expand Up @@ -1184,7 +1184,7 @@ private static Object revocable(
}

private Callable getTrap(String trapName) {
Object handlerProp = ScriptableObject.getProperty(handler, trapName);
Object handlerProp = ScriptableObject.getProperty(handlerObj, trapName);
if (Scriptable.NOT_FOUND == handlerProp) {
return null;
}
Expand All @@ -1199,12 +1199,13 @@ private Callable getTrap(String trapName) {
}

private Object callTrap(Callable trap, Object[] args) {
return trap.call(Context.getContext(), handler, handler, args);
return trap.call(Context.getContext(), handlerObj, handlerObj, args);
}

private void assertNotRevoked() {
if (target == null) {
ScriptableObject getTargetThrowIfRevoked() {
if (targetObj == null) {
throw ScriptRuntime.typeError("Illegal operation attempted on a revoked proxy");
}
return targetObj;
}
}
4 changes: 4 additions & 0 deletions src/org/mozilla/javascript/ScriptRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -3645,6 +3645,10 @@ public static boolean shallowEq(Object x, Object y) {
if (y instanceof Boolean) {
return x.equals(y);
}
} else if (x instanceof SymbolKey) {
return x.equals(y);
} else if (y instanceof SymbolKey) {
return y.equals(x);
} else if (x instanceof Scriptable) {
if (x instanceof Wrapper && y instanceof Wrapper) {
return ((Wrapper) x).unwrap() == ((Wrapper) y).unwrap();
Expand Down
4 changes: 2 additions & 2 deletions testsrc/org/mozilla/javascript/tests/es6/NativeProxyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public void testToStringRevoke() {
+ "rev.revoke();\n"
+ "try {"
+ " Object.prototype.toString.call(%s);\n"
+ "} catch(e) {"
+ " '' + e;"
+ "} catch(e) {\n"
+ " '' + e;\n"
+ "}";

testString(
Expand Down

0 comments on commit 2e58558

Please sign in to comment.