12020-06-04 Caitlin Potter <caitp@igalia.com>
2
3 [JSC] Add support for private class fields
4 https://bugs.webkit.org/show_bug.cgi?id=206431
5
6 Reviewed by Saam Barati.
7
8 Expanding upon the earlier public class fields patch, we implement the remaining (and
9 significant parts) of the instance fields (https://tc39.es/proposal-class-fields/).
10
11 There are a variety of key changes here:
12
13 - Parser now understands the concept of private names (Token PRIVATENAME).
14 - 1 new opcode (op_get_private_name), one changed opcode (op_put_by_val_direct).
15 - A method for creating Symbol objects with a null PrivateSymbolImpl is exposed as a
16 LinkTimeConstant (@createPrivateSymbol).
17 - Null Private Symbols are stored by name (not a valid identifier) in a JSScope, and
18 are loaded from the outer scope whenever they are used by the modified opcodes.
19
20 The changes to op_put_by_val_direct include a new bytecode operand (PutByValFlags) which are
21 used to distinguish between overwriting or defining a new private field. Specifically, when it
22 comes to private field accesses, it's necessary to throw an exception when accessing a field
23 which does not exist, or when attempting to define a private field which has already been
24 defined.
25
26 During the evaluation of a class expression, before the class element list is evaluated (in case
27 any computed property names expressions refer to a new private field), a new PrivateSymbol is
28 created for each individual private field name, and stored in the class lexical scope.
29
30 Private field names are loaded from scope before their use. This prevents multiple evaluations
31 of the same class source from accessing each other's private fields, because the values of the
32 symbols loaded from the class scope would be distinct. This is required by the proposal text,
33 and is the key reason why we use ByVal lookups rather than ById lookups.
34
35 To illustrate, typical private field access will look like:
36
37 <Field Reads>
38 resolve_scope <scope=>, <currentScope>, "#x", GlobalProperty, 0
39 get_from_scope <symbol=>, <scope>, "#x", 1050624<DoNotThrowIfNotFound|GlobalProperty|NotInitialization>, 0, 0
40 get_private_name <value=>, <receiver --- probably 'this'>, <symbol>
41
42 <Field Writes>
43 resolve_scope <scope=>, <currentScope>, "#x", GlobalProperty, 0
44 get_from_scope <symbol=>, <scope>, "#x", 1050624<DoNotThrowIfNotFound|GlobalProperty|NotInitialization>, 0, 0
45 put_by_val_direct <receiver, probably 'this'>, <symbol>, <value>, <PutByValPrivateName>
46
47 <Field Definition>
48 resolve_scope <scope=>, <currentScope>, "#x", GlobalProperty, 0
49 get_from_scope <symbol=>, <scope>, "#x", 1050624<DoNotThrowIfNotFound|GlobalProperty|NotInitialization>, 0, 0
50 put_by_val_direct <receiver, probably 'this'>, <symbol>, <value>, <PutByValPrivateName|PutByValThrowIfExists>
51
52 The feature is currently hidden behind the feature flag JSC::Options::usePrivateClassFields.
53
54 * CMakeLists.txt:
55 * JavaScriptCore.xcodeproj/project.pbxproj:
56 * Sources.txt:
57 * builtins/BuiltinNames.h:
58 * bytecode/BytecodeList.rb:
59 * bytecode/BytecodeUseDef.cpp:
60 (JSC::computeUsesForBytecodeIndexImpl):
61 (JSC::computeDefsForBytecodeIndexImpl):
62 * bytecode/CodeBlock.cpp:
63 (JSC::CodeBlock::finalizeLLIntInlineCaches):
64 * bytecode/Fits.h:
65 * bytecode/LinkTimeConstant.h:
66 * bytecode/PutByValFlags.cpp: Copied from Source/JavaScriptCore/bytecode/PutKind.h.
67 (WTF::printInternal):
68 * bytecode/PutByValFlags.h: Added.
69 (JSC::PutByValFlags::create):
70 (JSC::PutByValFlags::createDirect):
71 (JSC::PutByValFlags::createDefinePrivateField):
72 (JSC::PutByValFlags::createPutPrivateField):
73 (JSC::PutByValFlags::isDirect const):
74 (JSC::PutByValFlags::ecmaMode const):
75 (JSC::PutByValFlags::privateFieldAccessKind const):
76 (JSC::PutByValFlags::isPrivateFieldAccess const):
77 (JSC::PutByValFlags::isPrivateFieldPut const):
78 (JSC::PutByValFlags::isPrivateFieldAdd const):
79 (JSC::PutByValFlags::PutByValFlags):
80 * bytecode/PutKind.h:
81 * bytecode/UnlinkedFunctionExecutable.cpp:
82 (JSC::generateUnlinkedFunctionCodeBlock):
83 * bytecompiler/BytecodeGenerator.cpp:
84 (JSC::BytecodeGenerator::instantiateLexicalVariables):
85 (JSC::BytecodeGenerator::emitDirectGetByVal):
86 (JSC::BytecodeGenerator::emitDirectPutByVal):
87 (JSC::BytecodeGenerator::emitDefinePrivateField):
88 (JSC::BytecodeGenerator::emitPrivateFieldPut):
89 * bytecompiler/BytecodeGenerator.h:
90 * bytecompiler/NodesCodegen.cpp:
91 (JSC::PropertyListNode::emitDeclarePrivateFieldNames):
92 (JSC::PropertyListNode::emitBytecode):
93 (JSC::PropertyListNode::emitPutConstantProperty):
94 (JSC::DotAccessorNode::emitBytecode):
95 (JSC::BaseDotNode::emitGetPropertyValue):
96 (JSC::BaseDotNode::emitPutProperty):
97 (JSC::FunctionCallDotNode::emitBytecode):
98 (JSC::PostfixNode::emitDot):
99 (JSC::PrefixNode::emitDot):
100 (JSC::AssignDotNode::emitBytecode):
101 (JSC::ReadModifyDotNode::emitBytecode):
102 (JSC::DefineFieldNode::emitBytecode):
103 (JSC::ClassExprNode::emitBytecode):
104 * dfg/DFGByteCodeParser.cpp:
105 (JSC::DFG::ecmaMode):
106 (JSC::DFG::ecmaMode<OpPutByValDirect>):
107 (JSC::DFG::ByteCodeParser::handlePutByVal):
108 * dfg/DFGCapabilities.cpp:
109 (JSC::DFG::capabilityLevel):
110 * dfg/DFGSpeculativeJIT.cpp:
111 (JSC::DFG::SpeculativeJIT::cachedPutById):
112 * ftl/FTLLowerDFGToB3.cpp:
113 (JSC::FTL::DFG::LowerDFGToB3::compilePutById):
114 * generator/DSL.rb:
115 * jit/ICStats.h:
116 * jit/JIT.cpp:
117 (JSC::JIT::privateCompileMainPass):
118 * jit/JIT.h:
119 * jit/JITInlineCacheGenerator.cpp:
120 (JSC::JITPutByIdGenerator::JITPutByIdGenerator):
121 (JSC::JITPutByIdGenerator::slowPathFunction):
122 * jit/JITInlineCacheGenerator.h:
123 (JSC::JITPutByIdGenerator::JITPutByIdGenerator):
124 * jit/JITInlines.h:
125 (JSC::JIT::ecmaMode):
126 (JSC::JIT::ecmaMode<OpPutById>):
127 (JSC::JIT::ecmaMode<OpPutByValDirect>):
128 (JSC::JIT::privateFieldAccessKind):
129 (JSC::JIT::privateFieldAccessKind<OpPutByValDirect>):
130 * jit/JITOperations.cpp:
131 (JSC::putPrivateField):
132 (JSC::definePrivateField):
133 * jit/JITOperations.h:
134 * jit/JITPropertyAccess.cpp:
135 (JSC::JIT::emitPutByValWithCachedId):
136 (JSC::JIT::emitSlow_op_put_by_val):
137 (JSC::JIT::emit_op_put_by_id):
138 * jit/JITPropertyAccess32_64.cpp:
139 (JSC::JIT::emitSlow_op_put_by_val):
140 (JSC::JIT::emit_op_put_by_id):
141 * jit/Repatch.cpp:
142 (JSC::appropriateGenericPutByIdFunction):
143 (JSC::appropriateOptimizingPutByIdFunction):
144 (JSC::tryCachePutByID):
145 * llint/LLIntOffsetsExtractor.cpp:
146 * llint/LLIntSlowPaths.cpp:
147 (JSC::LLInt::LLINT_SLOW_PATH_DECL):
148 * llint/LLIntSlowPaths.h:
149 * llint/LowLevelInterpreter32_64.asm:
150 * llint/LowLevelInterpreter64.asm:
151 * parser/ASTBuilder.h:
152 (JSC::ASTBuilder::createDotAccess):
153 (JSC::ASTBuilder::isPrivateLocation):
154 (JSC::ASTBuilder::makeFunctionCallNode):
155 (JSC::ASTBuilder::makeAssignNode):
156 * parser/Lexer.cpp:
157 (JSC::Lexer<LChar>::parseIdentifier):
158 (JSC::Lexer<UChar>::parseIdentifier):
159 (JSC::Lexer<CharacterType>::parseIdentifierSlowCase):
160 (JSC::Lexer<T>::lexWithoutClearingLineTerminator):
161 * parser/NodeConstructors.h:
162 (JSC::BaseDotNode::BaseDotNode):
163 (JSC::DotAccessorNode::DotAccessorNode):
164 (JSC::FunctionCallDotNode::FunctionCallDotNode):
165 (JSC::CallFunctionCallDotNode::CallFunctionCallDotNode):
166 (JSC::ApplyFunctionCallDotNode::ApplyFunctionCallDotNode):
167 (JSC::HasOwnPropertyFunctionCallDotNode::HasOwnPropertyFunctionCallDotNode):
168 (JSC::AssignDotNode::AssignDotNode):
169 (JSC::ReadModifyDotNode::ReadModifyDotNode):
170 * parser/Nodes.cpp:
171 (JSC::PropertyListNode::shouldCreateLexicalScopeForClass):
172 * parser/Nodes.h:
173 (JSC::ExpressionNode::isPrivateLocation const):
174 (JSC::BaseDotNode::base const):
175 (JSC::BaseDotNode::identifier const):
176 (JSC::BaseDotNode::type const):
177 (JSC::BaseDotNode::isPrivateField const):
178 * parser/Parser.cpp:
179 (JSC::Parser<LexerType>::parseVariableDeclarationList):
180 (JSC::Parser<LexerType>::parseDestructuringPattern):
181 (JSC::Parser<LexerType>::parseClass):
182 (JSC::Parser<LexerType>::parseInstanceFieldInitializerSourceElements):
183 (JSC::Parser<LexerType>::usePrivateName):
184 (JSC::Parser<LexerType>::parseMemberExpression):
185 (JSC::Parser<LexerType>::parseUnaryExpression):
186 (JSC::Parser<LexerType>::printUnexpectedTokenText):
187 * parser/Parser.h:
188 (JSC::Scope::isPrivateNameScope const):
189 (JSC::Scope::setIsPrivateNameScope):
190 (JSC::Scope::hasPrivateName):
191 (JSC::Scope::copyUndeclaredPrivateNamesTo):
192 (JSC::Scope::hasUsedButUndeclaredPrivateNames const):
193 (JSC::Scope::usePrivateName):
194 (JSC::Scope::declarePrivateName):
195 (JSC::Parser::findPrivateNameScope):
196 (JSC::Parser::privateNameScope):
197 (JSC::Parser::copyUndeclaredPrivateNamesToOuterScope):
198 (JSC::Parser::matchAndUpdate):
199 (JSC::Parser<LexerType>::parse):
200 (JSC::parse):
201 * parser/ParserTokens.h:
202 * parser/SyntaxChecker.h:
203 (JSC::SyntaxChecker::createDotAccess):
204 (JSC::SyntaxChecker::operatorStackPop):
205 * parser/VariableEnvironment.cpp:
206 (JSC::VariableEnvironment::operator=):
207 (JSC::VariableEnvironment::swap):
208 (JSC::CompactVariableEnvironment::CompactVariableEnvironment):
209 * parser/VariableEnvironment.h:
210 (JSC::VariableEnvironmentEntry::isPrivateName const):
211 (JSC::VariableEnvironmentEntry::setIsPrivateName):
212 (JSC::PrivateNameEntry::PrivateNameEntry):
213 (JSC::PrivateNameEntry::isUsed const):
214 (JSC::PrivateNameEntry::isDeclared const):
215 (JSC::PrivateNameEntry::setIsUsed):
216 (JSC::PrivateNameEntry::setIsDeclared):
217 (JSC::PrivateNameEntry::bits const):
218 (JSC::PrivateNameEntry::operator== const):
219 (JSC::VariableEnvironment::VariableEnvironment):
220 (JSC::VariableEnvironment::size const):
221 (JSC::VariableEnvironment::mapSize const):
222 (JSC::VariableEnvironment::declarePrivateName):
223 (JSC::VariableEnvironment::usePrivateName):
224 (JSC::VariableEnvironment::privateNames const):
225 (JSC::VariableEnvironment::privateNamesSize const):
226 (JSC::VariableEnvironment::hasPrivateName):
227 (JSC::VariableEnvironment::copyPrivateNamesTo const):
228 (JSC::VariableEnvironment::copyUndeclaredPrivateNamesTo const):
229 (JSC::VariableEnvironment::RareData::RareData):
230 (JSC::VariableEnvironment::getOrAddPrivateName):
231 * runtime/CachedTypes.cpp:
232 (JSC::CachedOptional::decodeAsPtr const):
233 (JSC::CachedVariableEnvironmentRareData::encode):
234 (JSC::CachedVariableEnvironmentRareData::decode const):
235 (JSC::CachedVariableEnvironment::encode):
236 (JSC::CachedVariableEnvironment::decode const):
237 (JSC::CachedSymbolTableRareData::encode):
238 (JSC::CachedSymbolTableRareData::decode const):
239 (JSC::CachedSymbolTable::encode):
240 (JSC::CachedSymbolTable::decode const):
241 * runtime/CodeCache.cpp:
242 (JSC::generateUnlinkedCodeBlockImpl):
243 * runtime/CommonIdentifiers.cpp:
244 (JSC::CommonIdentifiers::CommonIdentifiers):
245 * runtime/CommonIdentifiers.h:
246 * runtime/CommonSlowPaths.cpp:
247 (JSC::SLOW_PATH_DECL):
248 * runtime/CommonSlowPaths.h:
249 * runtime/ExceptionHelpers.cpp:
250 (JSC::createInvalidPrivateNameError):
251 (JSC::createRedefinedPrivateNameError):
252 * runtime/ExceptionHelpers.h:
253 * runtime/JSGlobalObject.cpp:
254 (JSC::createPrivateSymbol):
255 (JSC::JSGlobalObject::init):
256 * runtime/JSObject.h:
257 * runtime/JSObjectInlines.h:
258 (JSC::JSObject::getPrivateFieldSlot):
259 (JSC::JSObject::getPrivateField):
260 (JSC::JSObject::putPrivateField):
261 (JSC::JSObject::definePrivateField):
262 * runtime/JSScope.cpp:
263 (JSC::JSScope::collectClosureVariablesUnderTDZ):
264 * runtime/OptionsList.h:
265 * runtime/SymbolTable.cpp:
266 (JSC::SymbolTable::cloneScopePart):
267 * runtime/SymbolTable.h:
268