Skip to content

Commit 281b81e

Browse files
committed
[GR-30915] Fix NamedEvaluation of anonymous class expressions in class field initializers.
PullRequest: js/1983
2 parents 91e3758 + 56673e2 commit 281b81e

File tree

7 files changed

+129
-18
lines changed

7 files changed

+129
-18
lines changed

graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,7 @@ private Pair<FunctionNode, Boolean> fieldInitializer(int lineNumber, long fieldT
19651965
initializer = setAnonymousFunctionName(initializer, ((PropertyKey) propertyName).getPropertyName());
19661966
} else {
19671967
isAnonymousFunctionDefinition = true;
1968+
initializer = new UnaryNode(Token.recast(initializer.getToken(), TokenType.NAMEDEVALUATION), initializer);
19681969
}
19691970
}
19701971

graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/TokenType.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -229,7 +229,8 @@ public enum TokenType {
229229
SPREAD_ARRAY (IR, null),
230230
SPREAD_OBJECT (IR, null),
231231
YIELD_STAR (IR, null),
232-
ASSIGN_INIT (IR, null);
232+
ASSIGN_INIT (IR, null),
233+
NAMEDEVALUATION(IR, null);
233234
//@formatter:on
234235

235236
/** Next token kind in token lookup table. */

graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,8 @@ public JavaScriptNode enterUnaryNode(UnaryNode unaryNode) {
19711971
return tagExpression(createYieldNode(unaryNode), unaryNode);
19721972
case AWAIT:
19731973
return tagExpression(translateAwaitNode(unaryNode), unaryNode);
1974+
case NAMEDEVALUATION:
1975+
return enterNamedEvaluation(unaryNode);
19741976
default:
19751977
throw new UnsupportedOperationException(unaryNode.tokenType().toString());
19761978
}
@@ -2098,6 +2100,10 @@ private static UnaryOperation tokenTypeToUnaryOperation(TokenType tokenType) {
20982100
}
20992101
}
21002102

2103+
private JavaScriptNode enterNamedEvaluation(UnaryNode unaryNode) {
2104+
return factory.createNamedEvaluation(transform(unaryNode.getExpression()), factory.createAccessArgument(0));
2105+
}
2106+
21012107
private JavaScriptNode enterDelete(UnaryNode unaryNode) {
21022108
Expression rhs = unaryNode.getExpression();
21032109
if (rhs instanceof AccessNode || rhs instanceof IndexNode) {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
6+
*/
7+
8+
/**
9+
* Tests NamedEvaluation of anonymous function definitions in class field initializers.
10+
*
11+
* @option ecmascript-version=2021
12+
*/
13+
14+
load('assert.js');
15+
16+
let C;
17+
C = class { x = class { static y = this.name; } }; assertSame("x", new C().x.y);
18+
C = class { ['x'] = class { static y = this.name; } }; assertSame("x", new C().x.y);
19+
C = class { static x = class { static y = this.name; } }; assertSame("x", C.x.y);
20+
C = class { static ['x'] = class { static y = this.name; } }; assertSame("x", C.x.y);

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
import com.oracle.truffle.js.nodes.function.JSFunctionCallNode;
200200
import com.oracle.truffle.js.nodes.function.JSFunctionExpressionNode;
201201
import com.oracle.truffle.js.nodes.function.JSNewNode;
202+
import com.oracle.truffle.js.nodes.function.NamedEvaluationNode;
202203
import com.oracle.truffle.js.nodes.function.NewTargetRootNode;
203204
import com.oracle.truffle.js.nodes.function.SpreadArgumentNode;
204205
import com.oracle.truffle.js.nodes.module.ImportMetaNode;
@@ -1166,6 +1167,10 @@ public JavaScriptNode createOptionalChainShortCircuit(JavaScriptNode valueNode)
11661167
return OptionalChainNode.createShortCircuit(valueNode);
11671168
}
11681169

1170+
public JavaScriptNode createNamedEvaluation(JavaScriptNode expressionNode, JavaScriptNode nameNode) {
1171+
return NamedEvaluationNode.create(expressionNode, nameNode);
1172+
}
1173+
11691174
public IfNode copyIfWithCondition(IfNode origIfNode, JavaScriptNode condition) {
11701175
return IfNode.create(condition, origIfNode.getThenPart(), origIfNode.getElsePart());
11711176
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/InitializeInstanceElementsNode.java

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,6 +40,8 @@
4040
*/
4141
package com.oracle.truffle.js.nodes.access;
4242

43+
import java.util.Set;
44+
4345
import com.oracle.truffle.api.CompilerAsserts;
4446
import com.oracle.truffle.api.dsl.Cached;
4547
import com.oracle.truffle.api.dsl.Cached.Shared;
@@ -52,15 +54,12 @@
5254
import com.oracle.truffle.js.nodes.JavaScriptBaseNode;
5355
import com.oracle.truffle.js.nodes.JavaScriptNode;
5456
import com.oracle.truffle.js.nodes.function.JSFunctionCallNode;
55-
import com.oracle.truffle.js.nodes.function.SetFunctionNameNode;
5657
import com.oracle.truffle.js.runtime.JSArguments;
5758
import com.oracle.truffle.js.runtime.JSContext;
5859
import com.oracle.truffle.js.runtime.JSRuntime;
5960
import com.oracle.truffle.js.runtime.builtins.JSFunction;
6061
import com.oracle.truffle.js.runtime.objects.Undefined;
6162

62-
import java.util.Set;
63-
6463
/**
6564
* InitializeInstanceElements (O, constructor).
6665
*
@@ -175,34 +174,27 @@ static DefineFieldNode[] createFieldNodes(Object[][] fields, JSContext context)
175174
if (initializer != Undefined.instance) {
176175
callNode = JSFunctionCallNode.createCall();
177176
}
178-
SetFunctionNameNode setFunctionNameNode = null;
179-
if (isAnonymousFunctionDefinition) {
180-
setFunctionNameNode = SetFunctionNameNode.create();
181-
}
182-
fieldNodes[i] = new DefineFieldNode(writeNode, callNode, setFunctionNameNode);
177+
fieldNodes[i] = new DefineFieldNode(writeNode, callNode, isAnonymousFunctionDefinition);
183178
}
184179
return fieldNodes;
185180
}
186181

187182
static final class DefineFieldNode extends JavaScriptBaseNode {
188183
@Child JavaScriptBaseNode writeNode;
189184
@Child JSFunctionCallNode callNode;
190-
@Child SetFunctionNameNode setFunctionNameNode;
185+
private final boolean isAnonymousFunctionDefinition;
191186

192-
DefineFieldNode(JavaScriptBaseNode writeNode, JSFunctionCallNode callNode, SetFunctionNameNode setFunctionNameNode) {
187+
DefineFieldNode(JavaScriptBaseNode writeNode, JSFunctionCallNode callNode, boolean isAnonymousFunctionDefinition) {
193188
this.writeNode = writeNode;
194189
this.callNode = callNode;
195-
this.setFunctionNameNode = setFunctionNameNode;
190+
this.isAnonymousFunctionDefinition = isAnonymousFunctionDefinition;
196191
}
197192

198193
void defineField(Object target, Object key, Object initializer) {
199194
assert (callNode != null) == (initializer != Undefined.instance);
200195
Object value = Undefined.instance;
201196
if (callNode != null) {
202-
value = callNode.executeCall(JSArguments.createZeroArg(target, initializer));
203-
if (setFunctionNameNode != null) {
204-
setFunctionNameNode.execute(value, key);
205-
}
197+
value = callNode.executeCall(isAnonymousFunctionDefinition ? JSArguments.createOneArg(target, initializer, key) : JSArguments.createZeroArg(target, initializer));
206198
}
207199
if (writeNode instanceof PrivateFieldAddNode) {
208200
assert key instanceof HiddenKey : key;
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.js.nodes.function;
42+
43+
import java.util.Set;
44+
45+
import com.oracle.truffle.api.frame.VirtualFrame;
46+
import com.oracle.truffle.api.instrumentation.Tag;
47+
import com.oracle.truffle.js.nodes.JSNodeUtil;
48+
import com.oracle.truffle.js.nodes.JavaScriptNode;
49+
50+
/**
51+
* Represent a NamedEvaluation with a name that is computed / not already known at parse time.
52+
*/
53+
public class NamedEvaluationNode extends JavaScriptNode {
54+
@Child protected JavaScriptNode nameNode;
55+
@Child protected JavaScriptNode expressionNode;
56+
@Child SetFunctionNameNode setFunctionNameNode;
57+
58+
protected NamedEvaluationNode(JavaScriptNode expressionNode, JavaScriptNode nameNode) {
59+
this.nameNode = nameNode;
60+
this.expressionNode = expressionNode;
61+
this.setFunctionNameNode = JSNodeUtil.getWrappedNode(expressionNode) instanceof ClassDefinitionNode ? null : SetFunctionNameNode.create();
62+
}
63+
64+
public static JavaScriptNode create(JavaScriptNode expressionNode, JavaScriptNode nameNode) {
65+
return new NamedEvaluationNode(expressionNode, nameNode);
66+
}
67+
68+
@Override
69+
public Object execute(VirtualFrame frame) {
70+
Object name = nameNode.execute(frame);
71+
Object function;
72+
JavaScriptNode unwrappedExprNode;
73+
if ((unwrappedExprNode = JSNodeUtil.getWrappedNode(expressionNode)) instanceof ClassDefinitionNode) {
74+
function = ((ClassDefinitionNode) unwrappedExprNode).executeWithClassName(frame, name);
75+
} else {
76+
function = expressionNode.execute(frame);
77+
setFunctionNameNode.execute(function, name);
78+
}
79+
return function;
80+
}
81+
82+
@Override
83+
protected JavaScriptNode copyUninitialized(Set<Class<? extends Tag>> materializedTags) {
84+
return create(cloneUninitialized(expressionNode, materializedTags), cloneUninitialized(nameNode, materializedTags));
85+
}
86+
}

0 commit comments

Comments
 (0)