Skip to content

Commit

Permalink
Handle super.__proto__, which has a special implementation
Browse files Browse the repository at this point in the history
Co-authored-by: Satish Srinivasan <satish.srinivasan@servicenow.com>
  • Loading branch information
andreabergia and 0xe committed Dec 2, 2024
1 parent f82d9aa commit 2852f35
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 3 deletions.
19 changes: 16 additions & 3 deletions rhino/src/main/java/org/mozilla/javascript/IRFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -1964,16 +1964,29 @@ private Node createPropertyGet(
}
parser.checkActivationName(name, Token.GETPROP);
if (ScriptRuntime.isSpecialProperty(name)) {
if (target.getType() == Token.SUPER) {
// We have an access to super.__proto__ or super.__parent__.
// This needs to behave in the same way as this.__proto__ - it really is not
// obvious why, but you can test it in v8 or any other engine. So, we just
// replace SUPER with THIS in the AST. It's a bit hacky, but it works - see the
// test cases in SuperTest!
if (!(target instanceof KeywordLiteral)) {
throw Kit.codeBug();
}
KeywordLiteral oldTarget = (KeywordLiteral) target;
target =
new KeywordLiteral(
oldTarget.getPosition(), oldTarget.getLength(), Token.THIS);
target.setLineColumnNumber(oldTarget.getLineno(), oldTarget.getColumn());
}

Node ref = new Node(Token.REF_SPECIAL, target);
ref.putProp(Node.NAME_PROP, name);
Node getRef = new Node(Token.GET_REF, ref);
if (type == Token.QUESTION_DOT) {
ref.putIntProp(Node.OPTIONAL_CHAINING, 1);
getRef.putIntProp(Node.OPTIONAL_CHAINING, 1);
}
if (target.getType() == Token.SUPER) {
getRef.putIntProp(Node.SUPER_PROPERTY_ACCESS, 1);
}
return getRef;
}

Expand Down
59 changes: 59 additions & 0 deletions rhino/src/test/java/org/mozilla/javascript/SuperTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -942,4 +942,63 @@ void doublyNestedLambdaCaptureSuper() {
Utils.assertWithAllOptimizationLevelsES6("object", script);
}
}

/**
* Test cases related to the special handling of REF in Rhino, which includes the special
* properties __proto__ and __parent__. It also includes XML stuff, but we do not support it for
* super.
*/
@Nested
class Ref {
@Test
void propertyGet() {
String script =
""
+ "var a = {x: 'a'};\n"
+ "var b = {x: 'b'};\n"
+ "var c = {x: 'c',\n"
+ " f() {\n"
+ " return super.__proto__.x;\n"
+ " }\n"
+ "};\n"
+ "Object.setPrototypeOf(c, b);\n"
+ "Object.setPrototypeOf(b, a);\n"
+ "c.f();";
Utils.assertWithAllOptimizationLevelsES6("b", script);
}

@Test
void propertyGetter() {
String script =
""
+ "var a = {get x() { return 'a' + this.y }, y: 'a' };\n"
+ "var b = {get x() { return 'b' + this.y }, y: 'b' };\n"
+ "var c = {\n"
+ " get x() { return 'c' + this.y }, y: 'c',\n"
+ " f() { return super.__proto__.x },"
+ "};\n"
+ "Object.setPrototypeOf(c, b);\n"
+ "Object.setPrototypeOf(b, a);\n"
+ "c.f();";
Utils.assertWithAllOptimizationLevelsES6("bb", script);
}

@Test
void propertySet() {
String script =
""
+ "var a = {x: 'a'};\n"
+ "var b = {x: 'b'};\n"
+ "var c = {x: 'c',\n"
+ " f() {\n"
+ " super.__proto__ = a;\n"
+ " return Object.getPrototypeOf(this).x;\n"
+ " }\n"
+ "};\n"
+ "Object.setPrototypeOf(c, b);\n"
+ "Object.setPrototypeOf(b, a);\n"
+ "c.f();";
Utils.assertWithAllOptimizationLevelsES6("a", script);
}
}
}

0 comments on commit 2852f35

Please sign in to comment.