Skip to content

Commit dc314a6

Browse files
committed
Implemented private fields in operator.
1 parent 4f4b578 commit dc314a6

File tree

14 files changed

+377
-32
lines changed

14 files changed

+377
-32
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ This changelog summarizes major changes between GraalVM versions of the GraalVM
44
The main focus is on user-observable behavior of the engine.
55

66
## Version 21.3.0
7+
* Implemented the [Private Fields in `in`](https://tc39.es/proposal-private-fields-in-in) proposal. It is available behind the experimental option `--js.private-fields-in`.
78
* Implemented the [JavaScript BigInt to WebAssembly i64 integration](https://github.com/WebAssembly/JS-BigInt-integration) proposal. It can be disabled using the `--js.wasm-bigint=false` option.
89
* Updated Node.js to version 14.17.6.
910
* Implemented the [Error Cause](https://github.com/tc39/proposal-error-cause) proposal. It is available behind the experimental option `--js.error-cause`.

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

+21-2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import static com.oracle.js.parser.TokenType.IDENT;
7373
import static com.oracle.js.parser.TokenType.IF;
7474
import static com.oracle.js.parser.TokenType.IMPORT;
75+
import static com.oracle.js.parser.TokenType.IN;
7576
import static com.oracle.js.parser.TokenType.INCPOSTFIX;
7677
import static com.oracle.js.parser.TokenType.INCPREFIX;
7778
import static com.oracle.js.parser.TokenType.LBRACE;
@@ -81,6 +82,7 @@
8182
import static com.oracle.js.parser.TokenType.MUL;
8283
import static com.oracle.js.parser.TokenType.OF;
8384
import static com.oracle.js.parser.TokenType.PERIOD;
85+
import static com.oracle.js.parser.TokenType.PRIVATE_IDENT;
8486
import static com.oracle.js.parser.TokenType.RBRACE;
8587
import static com.oracle.js.parser.TokenType.RBRACKET;
8688
import static com.oracle.js.parser.TokenType.RPAREN;
@@ -3806,6 +3808,10 @@ private Expression primaryExpression(boolean yield, boolean await) {
38063808
throw error(AbstractParser.message(MESSAGE_EXPECTED_OPERAND, type.getNameOrType()));
38073809
}
38083810

3811+
private boolean isPrivateFieldsIn() {
3812+
return env.privateFieldsIn;
3813+
}
3814+
38093815
/**
38103816
* Convert execString to a call to $EXEC.
38113817
*
@@ -5970,7 +5976,13 @@ private Expression arrowFunctionRestParameter(Expression paramListExpr, long com
59705976
}
59715977

59725978
private Expression expression(int minPrecedence, boolean in, boolean yield, boolean await) {
5973-
return expression(unaryExpression(yield, await), minPrecedence, in, yield, await);
5979+
Expression lhs;
5980+
if (in && type == PRIVATE_IDENT && isPrivateFieldsIn() && lookahead() == IN) {
5981+
lhs = privateIdentifierUse().setIsPrivateInCheck();
5982+
} else {
5983+
lhs = unaryExpression(yield, await);
5984+
}
5985+
return expression(lhs, minPrecedence, in, yield, await);
59745986
}
59755987

59765988
private JoinPredecessorExpression joinPredecessorExpression(boolean yield, boolean await) {
@@ -6003,12 +6015,19 @@ private Expression expression(Expression exprLhs, int minPrecedence, boolean in,
60036015
// Build up node.
60046016
lhs = new TernaryNode(op, lhs, new JoinPredecessorExpression(trueExpr), new JoinPredecessorExpression(falseExpr));
60056017
} else {
6018+
final TokenType opType = type;
60066019
// Skip operator.
60076020
next();
60086021

60096022
assert !Token.descType(op).isAssignment();
60106023
// Get the next primary expression.
6011-
Expression rhs = unaryExpression(yield, await);
6024+
Expression rhs;
6025+
if (in && type == PRIVATE_IDENT && isPrivateFieldsIn() && lookahead() == IN && precedence < IN.getPrecedence()) {
6026+
assert opType != IN;
6027+
rhs = privateIdentifierUse().setIsPrivateInCheck();
6028+
} else {
6029+
rhs = unaryExpression(yield, await);
6030+
}
60126031

60136032
// Get precedence of next operator.
60146033
int nextPrecedence = type.getPrecedence();

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,12 @@ public enum FunctionStatementBehavior {
116116
/** Are import assertions enabled. */
117117
final boolean importAssertions;
118118

119+
/** Is private field in enabled */
120+
final boolean privateFieldsIn;
121+
119122
private ScriptEnvironment(boolean strict, int ecmaScriptVersion, boolean emptyStatements, boolean syntaxExtensions, boolean scripting, boolean shebang,
120-
boolean constAsVar, boolean allowBigInt, boolean annexB, boolean classFields, boolean importAssertions, FunctionStatementBehavior functionStatementBehavior,
123+
boolean constAsVar, boolean allowBigInt, boolean annexB, boolean classFields, boolean importAssertions, boolean privateFieldsIn,
124+
FunctionStatementBehavior functionStatementBehavior,
121125
PrintWriter dumpOnError) {
122126
this.namespace = new Namespace();
123127
this.err = dumpOnError;
@@ -135,6 +139,7 @@ private ScriptEnvironment(boolean strict, int ecmaScriptVersion, boolean emptySt
135139
this.annexB = annexB;
136140
this.classFields = classFields;
137141
this.importAssertions = importAssertions;
142+
this.privateFieldsIn = privateFieldsIn;
138143
}
139144

140145
/**
@@ -176,6 +181,7 @@ public static final class Builder {
176181
private boolean annexB = true;
177182
private boolean classFields = true;
178183
private boolean importAssertions = false;
184+
private boolean privateFieldsIn = false;
179185
private FunctionStatementBehavior functionStatementBehavior = FunctionStatementBehavior.ERROR;
180186
private PrintWriter dumpOnError;
181187

@@ -237,6 +243,11 @@ public Builder importAssertions(boolean importAssertions) {
237243
return this;
238244
}
239245

246+
public Builder privateFieldsIn(boolean privateFieldsIn) {
247+
this.privateFieldsIn = privateFieldsIn;
248+
return this;
249+
}
250+
240251
public Builder functionStatementBehavior(FunctionStatementBehavior functionStatementBehavior) {
241252
this.functionStatementBehavior = functionStatementBehavior;
242253
return this;
@@ -249,7 +260,7 @@ public Builder dumpOnError(PrintWriter dumpOnError) {
249260

250261
public ScriptEnvironment build() {
251262
return new ScriptEnvironment(strict, ecmaScriptVersion, emptyStatements, syntaxExtensions, scripting, shebang, constAsVar, allowBigInt, annexB,
252-
classFields, importAssertions, functionStatementBehavior, dumpOnError);
263+
classFields, importAssertions, privateFieldsIn, functionStatementBehavior, dumpOnError);
253264
}
254265
}
255266
}

graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/IdentNode.java

+10-1
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
@@ -65,6 +65,7 @@ public final class IdentNode extends Expression implements PropertyKey, Function
6565
private static final int ARGUMENTS = 1 << 11;
6666
private static final int APPLY_ARGUMENTS = 1 << 12;
6767
private static final int PRIVATE_IDENT = 1 << 13;
68+
private static final int PRIVATE_IN_CHECK = 1 << 14;
6869
//@formatter:on
6970

7071
/** Identifier. */
@@ -303,4 +304,12 @@ public IdentNode setIsPrivate() {
303304
public boolean isPrivate() {
304305
return (flags & PRIVATE_IDENT) != 0;
305306
}
307+
308+
public IdentNode setIsPrivateInCheck() {
309+
return new IdentNode(this, name, flags | PRIVATE_IN_CHECK);
310+
}
311+
312+
public boolean isPrivateInCheck() {
313+
return (flags & PRIVATE_IN_CHECK) != 0;
314+
}
306315
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ private static ScriptEnvironment makeScriptEnvironment(JSParserOptions parserOpt
189189
builder.annexB(parserOptions.isAnnexB());
190190
builder.classFields(parserOptions.isClassFields());
191191
builder.importAssertions(parserOptions.isImportAssertions());
192+
builder.privateFieldsIn(parserOptions.isPrivateFieldsIn());
192193
if (parserOptions.isFunctionStatementError()) {
193194
builder.functionStatementBehavior(FunctionStatementBehavior.ERROR);
194195
} else {

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

+34-13
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,17 @@ public JavaScriptNode enterIdentNode(IdentNode identNode) {
15501550
result = enterNewTarget();
15511551
} else if (identNode.isImportMeta()) {
15521552
result = enterImportMeta();
1553+
} else if (identNode.isPrivateInCheck()) {
1554+
String privateVarName = identNode.getName();
1555+
VarRef privateVarRef = environment.findLocalVar(privateVarName);
1556+
JavaScriptNode readNode = privateVarRef.createReadNode();
1557+
FrameSlot frameSlot = privateVarRef.getFrameSlot();
1558+
if (JSFrameUtil.needsPrivateBrandCheck(frameSlot)) {
1559+
// Create a brand node so that a brand check can be performed in the InNode.
1560+
result = getPrivateBrandNode(frameSlot, privateVarRef);
1561+
} else {
1562+
result = readNode;
1563+
}
15531564
} else {
15541565
String varName = identNode.getName();
15551566
VarRef varRef = findScopeVarCheckTDZ(varName, false);
@@ -2427,9 +2438,16 @@ public JavaScriptNode enterBinaryNode(BinaryNode binaryNode) {
24272438
}
24282439

24292440
private JavaScriptNode enterBinaryExpressionNode(BinaryNode binaryNode) {
2430-
JavaScriptNode lhs = transform(binaryNode.getLhs());
2441+
Expression lhsExpr = binaryNode.getLhs();
2442+
JavaScriptNode lhs = transform(lhsExpr);
24312443
JavaScriptNode rhs = transform(binaryNode.getRhs());
2432-
return tagExpression(factory.createBinary(context, tokenTypeToBinaryOperation(binaryNode.tokenType()), lhs, rhs), binaryNode);
2444+
JavaScriptNode result;
2445+
if (lhsExpr instanceof IdentNode && ((IdentNode) lhsExpr).isPrivateInCheck()) {
2446+
result = factory.createPrivateFieldIn(lhs, rhs);
2447+
} else {
2448+
result = factory.createBinary(context, tokenTypeToBinaryOperation(binaryNode.tokenType()), lhs, rhs);
2449+
}
2450+
return tagExpression(result, binaryNode);
24332451
}
24342452

24352453
private JavaScriptNode enterBinaryTransformNode(BinaryNode binaryNode) {
@@ -2886,23 +2904,26 @@ private JavaScriptNode createPrivateFieldSet(AccessNode accessNode, JavaScriptNo
28862904
private JavaScriptNode insertPrivateBrandCheck(JavaScriptNode base, VarRef privateNameVar) {
28872905
FrameSlot frameSlot = privateNameVar.getFrameSlot();
28882906
if (JSFrameUtil.needsPrivateBrandCheck(frameSlot)) {
2889-
int frameLevel = ((AbstractFrameVarRef) privateNameVar).getFrameLevel();
2890-
int scopeLevel = ((AbstractFrameVarRef) privateNameVar).getScopeLevel();
2891-
Environment memberEnv = environment.getParentAt(frameLevel, scopeLevel);
2892-
FrameSlot constructorSlot = memberEnv.getBlockFrameDescriptor().findFrameSlot(ClassNode.PRIVATE_CONSTRUCTOR_BINDING_NAME);
2893-
JavaScriptNode constructor = environment.createLocal(constructorSlot, frameLevel, scopeLevel);
2894-
JavaScriptNode brand;
2895-
if (JSFrameUtil.isPrivateNameStatic(frameSlot)) {
2896-
brand = constructor;
2897-
} else {
2898-
brand = factory.createGetPrivateBrand(context, constructor);
2899-
}
2907+
JavaScriptNode brand = getPrivateBrandNode(frameSlot, privateNameVar);
29002908
return factory.createPrivateBrandCheck(base, brand);
29012909
} else {
29022910
return base;
29032911
}
29042912
}
29052913

2914+
private JavaScriptNode getPrivateBrandNode(FrameSlot frameSlot, VarRef privateNameVar) {
2915+
int frameLevel = ((AbstractFrameVarRef) privateNameVar).getFrameLevel();
2916+
int scopeLevel = ((AbstractFrameVarRef) privateNameVar).getScopeLevel();
2917+
Environment memberEnv = environment.getParentAt(frameLevel, scopeLevel);
2918+
FrameSlot constructorSlot = memberEnv.getBlockFrameDescriptor().findFrameSlot(ClassNode.PRIVATE_CONSTRUCTOR_BINDING_NAME);
2919+
JavaScriptNode constructor = environment.createLocal(constructorSlot, frameLevel, scopeLevel);
2920+
if (JSFrameUtil.isPrivateNameStatic(frameSlot)) {
2921+
return constructor;
2922+
} else {
2923+
return factory.createGetPrivateBrand(context, constructor);
2924+
}
2925+
}
2926+
29062927
@Override
29072928
public JavaScriptNode enterIndexNode(IndexNode indexNode) {
29082929
JavaScriptNode base = transform(indexNode.getBase());

graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ public class Test262Runnable extends TestRunnable {
180180
"caller",
181181
"class",
182182
"class-fields-private",
183+
"class-fields-private-in",
183184
"class-fields-public",
184185
"class-methods-private",
185186
"class-static-block",
@@ -242,7 +243,6 @@ public class Test262Runnable extends TestRunnable {
242243
"Temporal",
243244
"arbitrary-module-namespace-names",
244245
"array-find-from-last",
245-
"class-fields-private-in",
246246
"resizable-arraybuffer",
247247
"tail-call-optimization",
248248
}));
@@ -252,6 +252,7 @@ public class Test262Runnable extends TestRunnable {
252252
"Object.hasOwn",
253253
"String.prototype.at",
254254
"TypedArray.prototype.at",
255+
"class-fields-private-in",
255256
"class-fields-private",
256257
"class-fields-public",
257258
"class-methods-private",

graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/testv8/TestV8Runnable.java

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public class TestV8Runnable extends TestRunnable {
102102
"--harmony-atomics-waitasync",
103103
"--harmony-class-static-blocks",
104104
"--harmony-object-has-own",
105+
"--harmony-private-brand-checks",
105106
"--harmony-regexp-match-indices",
106107
"--harmony-top-level-await"
107108
}));

0 commit comments

Comments
 (0)