Source/JavaScriptCore/ChangeLog

 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
12692020-06-04 Mark Lam <mark.lam@apple.com>
2270
3271 Reduce DFGDoesGCCheck to only storing a uint32_t.

Source/JavaScriptCore/CMakeLists.txt

@@set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
540540 bytecode/Operands.h
541541 bytecode/PropertyCondition.h
542542 bytecode/PutByIdFlags.h
 543 bytecode/PutByValFlags.h
543544 bytecode/SpeculatedType.h
544545 bytecode/StructureSet.h
545546 bytecode/SuperSampler.h

Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

12501250 86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8012DBA33700A9FE7B /* YarrJIT.h */; settings = {ATTRIBUTES = (Private, ); }; };
12511251 86704B8812DBA33700A9FE7B /* YarrParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8112DBA33700A9FE7B /* YarrParser.h */; settings = {ATTRIBUTES = (Private, ); }; };
12521252 86704B8A12DBA33700A9FE7B /* YarrPattern.h in Headers */ = {isa = PBXBuildFile; fileRef = 86704B8312DBA33700A9FE7B /* YarrPattern.h */; settings = {ATTRIBUTES = (Private, ); }; };
 1253 8676C6E82346467E00FAAFF3 /* PutByValFlags.h in Headers */ = {isa = PBXBuildFile; fileRef = 8676C6E62346450B00FAAFF3 /* PutByValFlags.h */; settings = {ATTRIBUTES = (Private, ); }; };
12531254 868916B0155F286300CB2B9A /* PrivateName.h in Headers */ = {isa = PBXBuildFile; fileRef = 868916A9155F285400CB2B9A /* PrivateName.h */; settings = {ATTRIBUTES = (Private, ); }; };
12541255 868921C21F9C0CB7001159F6 /* JSBigInt.h in Headers */ = {isa = PBXBuildFile; fileRef = 868921C11F9C0CB7001159F6 /* JSBigInt.h */; settings = {ATTRIBUTES = (Private, ); }; };
12551256 86976E5E1FA3E8B600E7C4E1 /* BigIntPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = 86976E5A1FA3758A00E7C4E1 /* BigIntPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };

41154116 86704B8112DBA33700A9FE7B /* YarrParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrParser.h; path = yarr/YarrParser.h; sourceTree = "<group>"; };
41164117 86704B8212DBA33700A9FE7B /* YarrPattern.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YarrPattern.cpp; path = yarr/YarrPattern.cpp; sourceTree = "<group>"; };
41174118 86704B8312DBA33700A9FE7B /* YarrPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YarrPattern.h; path = yarr/YarrPattern.h; sourceTree = "<group>"; };
 4119 8676C6E62346450B00FAAFF3 /* PutByValFlags.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PutByValFlags.h; sourceTree = "<group>"; };
 4120 8676C6E7234645B300FAAFF3 /* PutByValFlags.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PutByValFlags.cpp; sourceTree = "<group>"; };
41184121 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT32_64.cpp; path = dfg/DFGSpeculativeJIT32_64.cpp; sourceTree = "<group>"; };
41194122 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT64.cpp; path = dfg/DFGSpeculativeJIT64.cpp; sourceTree = "<group>"; };
41204123 868916A9155F285400CB2B9A /* PrivateName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrivateName.h; sourceTree = "<group>"; };

84058408 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */,
84068409 0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */,
84078410 0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */,
 8411 8676C6E7234645B300FAAFF3 /* PutByValFlags.cpp */,
 8412 8676C6E62346450B00FAAFF3 /* PutByValFlags.h */,
84088413 0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */,
84098414 0F44A7AD20BF685F0022B171 /* RecordedStatuses.cpp */,
84108415 0F44A7AA20BF685E0022B171 /* RecordedStatuses.h */,

93419346 C2981FD917BAEE4B00A3BC98 /* DFGDesiredWeakReferences.h in Headers */,
93429347 0FF427651591A1CE004CB9FF /* DFGDisassembler.h in Headers */,
93439348 0F5A1274192D9FDF008764A3 /* DFGDoesGC.h in Headers */,
 9349 FEC3A3A1248735CA00395B54 /* DFGDoesGCCheck.h in Headers */,
93449350 0FD81AD3154FB4F000983E72 /* DFGDominators.h in Headers */,
93459351 0F1E3A471534CBB9000F9456 /* DFGDoubleFormatState.h in Headers */,
93469352 0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */,

1015310159 0F15CD231BA5F9860031FFD3 /* PutByIdFlags.h in Headers */,
1015410160 0F9332A414CA7DD90085F3C6 /* PutByIdStatus.h in Headers */,
1015510161 0F93B4AA18B92C4D00178A3F /* PutByIdVariant.h in Headers */,
 10162 8676C6E82346467E00FAAFF3 /* PutByValFlags.h in Headers */,
1015610163 0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */,
1015710164 0F9FC8C514E1B60400D52AE0 /* PutKind.h in Headers */,
1015810165 147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */,

1020110208 79D5CD5B1C1106A900CECA07 /* SamplingProfiler.h in Headers */,
1020210209 0FE050281AA9095600D33B33 /* ScopedArguments.h in Headers */,
1020310210 0FE050291AA9095600D33B33 /* ScopedArgumentsTable.h in Headers */,
10204  FEC3A3A1248735CA00395B54 /* DFGDoesGCCheck.h in Headers */,
1020510211 0FE0502B1AA9095600D33B33 /* ScopeOffset.h in Headers */,
1020610212 0F24E55217EE274900ABB217 /* ScratchRegisterAllocator.h in Headers */,
1020710213 33111B8B2397256500AA34CE /* Scribble.h in Headers */,

Source/JavaScriptCore/Sources.txt

@@bytecode/ProxyableAccessCase.cpp
268268bytecode/PutByIdFlags.cpp
269269bytecode/PutByIdStatus.cpp
270270bytecode/PutByIdVariant.cpp
 271bytecode/PutByValFlags.cpp
271272bytecode/RecordedStatuses.cpp
272273bytecode/ReduceWhitespace.cpp
273274bytecode/SpeculatedType.cpp

Source/JavaScriptCore/builtins/BuiltinNames.h

@@namespace JSC {
169169 macro(webAssemblyCompileStreamingInternal) \
170170 macro(webAssemblyInstantiateStreamingInternal) \
171171 macro(instanceFieldInitializer) \
172  macro(hasOwnPropertyFunction)
 172 macro(hasOwnPropertyFunction) \
 173 macro(createPrivateSymbol)
173174
174175namespace Symbols {
175176#define DECLARE_BUILTIN_STATIC_SYMBOLS(name) extern JS_EXPORT_PRIVATE SymbolImpl::StaticSymbolImpl name##Symbol;

Source/JavaScriptCore/bytecode/BytecodeList.rb

@@types [
4949 :ProfileTypeBytecodeFlag,
5050 :PropertyOffset,
5151 :PutByIdFlags,
 52 :PutByValFlags,
5253 :ResolveType,
5354 :Structure,
5455 :StructureID,

@@op :get_by_val,
550551 seenIdentifiers: GetByValHistory,
551552 }
552553
 554op :get_private_name,
 555 args: {
 556 dst: VirtualRegister,
 557 base: VirtualRegister,
 558 property: VirtualRegister,
 559 },
 560 metadata: {
 561 profile: ValueProfile,
 562 structureID: StructureID,
 563 offset: unsigned,
 564 property: WriteBarrier[JSCell],
 565 }
 566
553567op :put_by_val,
554568 args: {
555569 base: VirtualRegister,

@@op :put_by_val_direct,
575589 base: VirtualRegister,
576590 property: VirtualRegister,
577591 value: VirtualRegister,
578  ecmaMode: ECMAMode,
 592 flags: PutByValFlags,
579593 },
580594 metadata: {
581595 arrayProfile: ArrayProfile,

Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp

@@void computeUsesForBytecodeIndexImpl(VirtualRegister scopeRegister, const Instru
213213 USES(OpEnumeratorStructurePname, enumerator, index)
214214 USES(OpEnumeratorGenericPname, enumerator, index)
215215 USES(OpGetByVal, base, property)
 216 USES(OpGetPrivateName, base, property)
216217 USES(OpInByVal, base, property)
217218 USES(OpOverridesHasInstance, constructor, hasInstanceValue)
218219 USES(OpInstanceof, value, prototype)

@@void computeDefsForBytecodeIndexImpl(unsigned numVars, const Instruction* instru
428429 DEFS(OpInstanceof, dst)
429430 DEFS(OpInstanceofCustom, dst)
430431 DEFS(OpGetByVal, dst)
 432 DEFS(OpGetPrivateName, dst)
431433 DEFS(OpTypeof, dst)
432434 DEFS(OpIdentityWithProfile, srcDst)
433435 DEFS(OpIsEmpty, dst)

Source/JavaScriptCore/bytecode/CodeBlock.cpp

@@void CodeBlock::finalizeLLIntInlineCaches()
12511251 metadata.m_offset = 0;
12521252 });
12531253
 1254 m_metadata->forEach<OpGetPrivateName>([&] (auto& metadata) {
 1255 JSCell* property = metadata.m_property.get();
 1256 StructureID structureID = metadata.m_structureID;
 1257
 1258 if ((!property || vm.heap.isMarked(property)) && (!structureID || vm.heap.isMarked(vm.heap.structureIDTable().get(structureID))))
 1259 return;
 1260
 1261 dataLogLnIf(Options::verboseOSR(), "Clearing LLInt private property access.");
 1262 metadata.m_structureID = 0;
 1263 metadata.m_offset = 0;
 1264 metadata.m_property.clear();
 1265 });
 1266
12541267 m_metadata->forEach<OpPutById>([&] (auto& metadata) {
12551268 StructureID oldStructureID = metadata.m_oldStructureID;
12561269 StructureID newStructureID = metadata.m_newStructureID;

Source/JavaScriptCore/bytecode/Fits.h

3131#include "OpcodeSize.h"
3232#include "ProfileTypeBytecodeFlag.h"
3333#include "PutByIdFlags.h"
 34#include "PutByValFlags.h"
3435#include "ResultType.h"
3536#include "SymbolTableOrScopeDepth.h"
3637#include "VirtualRegister.h"

@@struct Fits<PutByIdFlags, size> {
256257 return isDirect ? PutByIdFlags::createDirect(ecmaMode) : PutByIdFlags::create(ecmaMode);
257258 }
258259};
 260
 261template<OpcodeSize size>
 262struct Fits<PutByValFlags, size> {
 263 using TargetType = typename TypeBySize<size>::unsignedType;
 264
 265 // PutByValFlags is 2 booleans and a 2 bit enum, encoded as:
 266 // isStrict
 267 // v
 268 // 0000|00|0|0 < isDirect
 269 // ^
 270 // PrivateFieldAccessKind {0 = None, 1 = Put, 2 = Create }
 271 static constexpr int s_isDirectBit = 1;
 272 static constexpr int s_isStrictBit = 2;
 273 static constexpr int s_privateFieldAccessKindMask = 12;
 274 static constexpr int s_privateFieldAccessKindShift = 2;
 275
 276 static bool check(PutByValFlags)
 277 {
 278 return true;
 279 }
 280
 281 static TargetType convert(PutByValFlags flags)
 282 {
 283 auto isDirect = static_cast<uint8_t>(flags.isDirect());
 284 auto isStrict = static_cast<uint8_t>(flags.ecmaMode().isStrict());
 285 auto privateFieldAccessKind = static_cast<uint8_t>(flags.privateFieldAccessKind());
 286 return (privateFieldAccessKind << s_privateFieldAccessKindShift) | (isStrict << 1) | isDirect;
 287 }
 288
 289 static PutByValFlags convert(TargetType gpi)
 290 {
 291 auto isDirect = static_cast<bool>(gpi & s_isDirectBit);
 292 auto isStrict = static_cast<bool>(gpi & s_isStrictBit);
 293 auto access = static_cast<PrivateFieldAccessKind>((gpi & s_privateFieldAccessKindMask) >> s_privateFieldAccessKindShift);
 294 auto ecmaMode = isStrict ? ECMAMode::strict() : ECMAMode::sloppy();
 295 return access == PrivateFieldAccessKind::None ?
 296 isDirect ? PutByValFlags::createDirect(ecmaMode) : PutByValFlags::create(ecmaMode) :
 297 access == PrivateFieldAccessKind::Put ? PutByValFlags::createPutPrivateField(ecmaMode) : PutByValFlags::createDefinePrivateField(ecmaMode);
 298 }
 299};
 300
259301template<typename E, OpcodeSize size>
260302struct Fits<E, size, std::enable_if_t<sizeof(E) != size && std::is_enum<E>::value, std::true_type>> : public Fits<std::underlying_type_t<E>, size> {
261303 using Base = Fits<std::underlying_type_t<E>, size>;

Source/JavaScriptCore/bytecode/LinkTimeConstant.h

@@class JSGlobalObject;
105105 v(applyFunction, nullptr) \
106106 v(callFunction, nullptr) \
107107 v(hasOwnPropertyFunction, nullptr) \
 108 v(createPrivateSymbol, nullptr) \
108109
109110
110111#define DECLARE_LINK_TIME_CONSTANT(name, code) name,

Source/JavaScriptCore/bytecode/PutByValFlags.cpp

 1/*
 2 * Copyright (C) 2020 Apple Inc. All rights reserved.
 3 * Copyright (C) 2020 Igalia S.L.
 4 *
 5 * Redistribution and use in source and binary forms, with or without
 6 * modification, are permitted provided that the following conditions
 7 * are met:
 8 * 1. Redistributions of source code must retain the above copyright
 9 * notice, this list of conditions and the following disclaimer.
 10 * 2. Redistributions in binary form must reproduce the above copyright
 11 * notice, this list of conditions and the following disclaimer in the
 12 * documentation and/or other materials provided with the distribution.
 13 *
 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 25 */
 26
 27#include "config.h"
 28#include "PutByValFlags.h"
 29
 30#include <wtf/CommaPrinter.h>
 31#include <wtf/PrintStream.h>
 32#include <wtf/StringPrintStream.h>
 33
 34namespace WTF {
 35
 36using namespace JSC;
 37
 38void printInternal(PrintStream& out, PutByValFlags flags)
 39{
 40 CommaPrinter comma("|");
 41 if (flags.isDirect())
 42 out.print(comma, "Direct");
 43 if (flags.isPrivateFieldPut())
 44 out.print(comma, "PrivateField+Put");
 45 if (flags.isPrivateFieldAdd())
 46 out.print(comma, "PrivateField+Add");
 47}
 48
 49} // namespace WTF

Source/JavaScriptCore/bytecode/PutByValFlags.h

 1/*
 2 * Copyright (C) 2020 Apple Inc. All rights reserved.
 3 * Copyright (C) 2020 Igalia S.L.
 4 *
 5 * Redistribution and use in source and binary forms, with or without
 6 * modification, are permitted provided that the following conditions
 7 * are met:
 8 * 1. Redistributions of source code must retain the above copyright
 9 * notice, this list of conditions and the following disclaimer.
 10 * 2. Redistributions in binary form must reproduce the above copyright
 11 * notice, this list of conditions and the following disclaimer in the
 12 * documentation and/or other materials provided with the distribution.
 13 *
 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 25 */
 26
 27#pragma once
 28
 29#include "StructureIDTable.h"
 30
 31namespace JSC {
 32
 33enum class PrivateFieldAccessKind : uint8_t {
 34 None,
 35 Put,
 36 Create,
 37};
 38
 39class PutByValFlags {
 40public:
 41 constexpr static PutByValFlags create(ECMAMode ecmaMode)
 42 {
 43 return PutByValFlags(false, ecmaMode);
 44 }
 45
 46 // A direct put_by_id means that we store the property without checking if the
 47 // prototype chain has a setter.
 48 constexpr static PutByValFlags createDirect(ECMAMode ecmaMode)
 49 {
 50 return PutByValFlags(true, ecmaMode);
 51 }
 52
 53 constexpr static PutByValFlags createDefinePrivateField(ECMAMode ecmaMode)
 54 {
 55 return PutByValFlags(PrivateFieldAccessKind::Create, ecmaMode);
 56 }
 57
 58 constexpr static PutByValFlags createPutPrivateField(ECMAMode ecmaMode)
 59 {
 60 return PutByValFlags(PrivateFieldAccessKind::Put, ecmaMode);
 61 }
 62
 63 bool isDirect() const { return m_isDirect; }
 64 ECMAMode ecmaMode() const { return m_ecmaMode; }
 65 PrivateFieldAccessKind privateFieldAccessKind() const { return m_privateFieldAccessKind; }
 66 bool isPrivateFieldAccess() const { return m_privateFieldAccessKind != PrivateFieldAccessKind::None; }
 67 bool isPrivateFieldPut() const { return m_privateFieldAccessKind == PrivateFieldAccessKind::Put; }
 68 bool isPrivateFieldAdd() const { return m_privateFieldAccessKind == PrivateFieldAccessKind::Create; }
 69
 70private:
 71
 72 constexpr PutByValFlags(bool isDirect, ECMAMode ecmaMode)
 73 : m_isDirect(isDirect)
 74 , m_privateFieldAccessKind(PrivateFieldAccessKind::None)
 75 , m_ecmaMode(ecmaMode)
 76 {
 77 }
 78
 79 constexpr PutByValFlags(PrivateFieldAccessKind access, ECMAMode ecmaMode)
 80 : m_isDirect(true)
 81 , m_privateFieldAccessKind(access)
 82 , m_ecmaMode(ecmaMode)
 83 {
 84 }
 85
 86 bool m_isDirect;
 87 PrivateFieldAccessKind m_privateFieldAccessKind;
 88 ECMAMode m_ecmaMode;
 89};
 90
 91} // namespace JSC
 92
 93namespace WTF {
 94
 95class PrintStream;
 96
 97void printInternal(PrintStream&, JSC::PutByValFlags);
 98
 99} // namespace WTF

Source/JavaScriptCore/bytecode/PutKind.h

2727
2828namespace JSC {
2929
30 enum PutKind { Direct, NotDirect };
 30enum PutKind { Direct, NotDirect, DirectPrivateFieldCreate, DirectPrivateFieldPut };
3131
3232} // namespace JSC

Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

@@static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
5858 ASSERT(isFunctionParseMode(executable->parseMode()));
5959 Vector<JSTextPosition>* instanceFieldLocations = executable->instanceFieldLocations();
6060 std::unique_ptr<FunctionNode> function = parse<FunctionNode>(
61  vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr, ConstructorKind::None, DerivedContextType::None, EvalContextType::None, nullptr, instanceFieldLocations);
 61 vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr, ConstructorKind::None, DerivedContextType::None, EvalContextType::None, nullptr, nullptr, instanceFieldLocations);
6262
6363 if (!function) {
6464 ASSERT(error.isValid());

Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

@@bool BytecodeGenerator::instantiateLexicalVariables(const VariableEnvironment& l
18921892
18931893 SymbolTableEntry newEntry(varOffset, static_cast<unsigned>(entry.value.isConst() ? PropertyAttribute::ReadOnly : PropertyAttribute::None));
18941894 symbolTable->add(NoLockingNecessary, entry.key.get(), newEntry);
 1895
 1896 // FIXME: only do this if there is an eval() within a nested scope --- otherwise it isn't needed.
 1897 // https://bugs.webkit.org/show_bug.cgi?id=206663
 1898 if (entry.value.isPrivateName())
 1899 symbolTable->addPrivateName(entry.key.get());
18951900 }
18961901 }
18971902 return hasCapturedVariables;

@@RegisterID* BytecodeGenerator::emitPutByVal(RegisterID* base, RegisterID* thisVa
26932698 return value;
26942699}
26952700
 2701RegisterID* BytecodeGenerator::emitDirectGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property)
 2702{
 2703 OpGetPrivateName::emit(this, dst, base, property);
 2704 return dst;
 2705}
 2706
26962707RegisterID* BytecodeGenerator::emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value)
26972708{
2698  OpPutByValDirect::emit(this, base, property, value, ecmaMode());
 2709 OpPutByValDirect::emit(this, base, property, value, PutByValFlags::createDirect(ecmaMode()));
26992710 return value;
27002711}
27012712

@@RegisterID* BytecodeGenerator::emitPutInternalField(RegisterID* base, unsigned i
27172728 return value;
27182729}
27192730
 2731RegisterID* BytecodeGenerator::emitDefinePrivateField(RegisterID* base, RegisterID* property, RegisterID* value)
 2732{
 2733 OpPutByValDirect::emit(this, base, property, value, PutByValFlags::createDefinePrivateField(ecmaMode()));
 2734 return value;
 2735}
 2736
 2737RegisterID* BytecodeGenerator::emitPrivateFieldPut(RegisterID* base, RegisterID* property, RegisterID* value)
 2738{
 2739 OpPutByValDirect::emit(this, base, property, value, PutByValFlags::createPutPrivateField(ecmaMode()));
 2740 return value;
 2741}
 2742
27202743void BytecodeGenerator::emitSuperSamplerBegin()
27212744{
27222745 OpSuperSamplerBegin::emit(this);

Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

@@namespace JSC {
813813 RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
814814 RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
815815 RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value);
 816 RegisterID* emitDirectGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
816817 RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
817818 RegisterID* emitDeleteByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
818819
819820 RegisterID* emitGetInternalField(RegisterID* dst, RegisterID* base, unsigned index);
820821 RegisterID* emitPutInternalField(RegisterID* base, unsigned index, RegisterID* value);
 822 RegisterID* emitDefinePrivateField(RegisterID* base, RegisterID* property, RegisterID* value);
 823 RegisterID* emitPrivateFieldPut(RegisterID* base, RegisterID* property, RegisterID* value);
821824
822825 void emitSuperSamplerBegin();
823826 void emitSuperSamplerEnd();

Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

@@static inline void emitPutHomeObject(BytecodeGenerator& generator, RegisterID* f
544544 generator.emitPutById(function, generator.propertyNames().builtinNames().homeObjectPrivateName(), homeObject);
545545}
546546
 547void PropertyListNode::emitDeclarePrivateFieldNames(BytecodeGenerator& generator, RegisterID* scope)
 548{
 549 // Walk the list and declare any Private property names (e.g. `#foo`) in the provided scope.
 550 RefPtr<RegisterID> createPrivateSymbol;
 551 for (PropertyListNode* p = this; p; p = p->m_next) {
 552 const PropertyNode& node = *p->m_node;
 553 if (node.type() & PropertyNode::Private) {
 554 if (!createPrivateSymbol)
 555 createPrivateSymbol = generator.moveLinkTimeConstant(nullptr, LinkTimeConstant::createPrivateSymbol);
 556
 557 CallArguments arguments(generator, nullptr, 0);
 558 generator.emitLoad(arguments.thisRegister(), jsUndefined());
 559 RefPtr<RegisterID> symbol = generator.emitCall(generator.finalDestination(nullptr, createPrivateSymbol.get()), createPrivateSymbol.get(), NoExpectedFunction, arguments, position(), position(), position(), DebuggableCall::No);
 560
 561 Variable var = generator.variable(*node.name());
 562 generator.emitPutToScope(scope, var, symbol.get(), DoNotThrowIfNotFound, InitializationMode::ConstInitialization);
 563 }
 564 }
 565}
 566
547567RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype, Vector<JSTextPosition>* instanceFieldLocations)
548568{
549  // Fast case: this loop just handles regular value properties.
550569 PropertyListNode* p = this;
551570 RegisterID* dst = nullptr;
 571
 572 // Fast case: this loop just handles regular value properties.
552573 for (; p && (p->m_node->m_type & PropertyNode::Constant); p = p->m_next) {
553574 dst = p->m_node->isInstanceClassProperty() ? prototype : dstOrConstructor;
554575

@@RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, Registe
710731
711732void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node)
712733{
 734 // Private fields are handled in the synthetic instanceFieldInitializer function, not here.
 735 ASSERT(!(node.type() & PropertyNode::Private));
 736
713737 bool shouldSetFunctionName = generator.shouldSetFunctionName(node.m_assign);
714738
715739 RefPtr<RegisterID> propertyName;

@@RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register
840864 }
841865
842866 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
843  RegisterID* ret;
844  if (baseIsSuper) {
845  RefPtr<RegisterID> thisValue = generator.ensureThis();
846  ret = generator.emitGetById(finalDest.get(), base.get(), thisValue.get(), m_ident);
847  } else
848  ret = generator.emitGetById(finalDest.get(), base.get(), m_ident);
 867 RegisterID* ret = emitGetPropertyValue(generator, finalDest.get(), base.get());
 868
849869 generator.emitProfileType(finalDest.get(), divotStart(), divotEnd());
850870 return ret;
851871}
852872
 873RegisterID* BaseDotNode::emitGetPropertyValue(BytecodeGenerator& generator, RegisterID* dst, RegisterID* base, RefPtr<RegisterID>& thisValue)
 874{
 875 if (isPrivateField()) {
 876 Variable var = generator.variable(m_ident);
 877 ASSERT_WITH_MESSAGE(!var.local(), "Private Field names must be stored in captured variables");
 878
 879 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
 880 RefPtr<RegisterID> privateName = generator.newTemporary();
 881 generator.emitGetFromScope(privateName.get(), scope.get(), var, DoNotThrowIfNotFound);
 882 return generator.emitDirectGetByVal(dst, base, privateName.get());
 883 }
 884
 885 if (m_base->isSuperNode()) {
 886 if (!thisValue)
 887 thisValue = generator.ensureThis();
 888 return generator.emitGetById(dst, base, thisValue.get(), m_ident);
 889 }
 890
 891 return generator.emitGetById(dst, base, m_ident);
 892}
 893
 894RegisterID* BaseDotNode::emitGetPropertyValue(BytecodeGenerator& generator, RegisterID* dst, RegisterID* base)
 895{
 896 RefPtr<RegisterID> thisValue;
 897 return emitGetPropertyValue(generator, dst, base, thisValue);
 898}
 899
 900RegisterID* BaseDotNode::emitPutProperty(BytecodeGenerator& generator, RegisterID* base, RegisterID* value, RefPtr<RegisterID>& thisValue)
 901{
 902 if (isPrivateField()) {
 903 Variable var = generator.variable(m_ident);
 904 ASSERT_WITH_MESSAGE(!var.local(), "Private Field names must be stored in captured variables");
 905
 906 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
 907 RefPtr<RegisterID> privateName = generator.newTemporary();
 908 generator.emitGetFromScope(privateName.get(), scope.get(), var, DoNotThrowIfNotFound);
 909 return generator.emitPrivateFieldPut(base, privateName.get(), value);
 910 }
 911
 912 if (m_base->isSuperNode()) {
 913 if (!thisValue)
 914 thisValue = generator.ensureThis();
 915 return generator.emitPutById(base, thisValue.get(), m_ident, value);
 916 }
 917
 918 return generator.emitPutById(base, m_ident, value);
 919}
 920
 921RegisterID* BaseDotNode::emitPutProperty(BytecodeGenerator& generator, RegisterID* base, RegisterID* value)
 922{
 923 RefPtr<RegisterID> thisValue;
 924 return emitPutProperty(generator, base, value, thisValue);
 925}
 926
853927// ------------------------------ ArgumentListNode -----------------------------
854928
855929RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)

@@RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, Regi
17341808 generator.emitOptionalCheck(callArguments.thisRegister());
17351809 }
17361810 generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
1737  if (baseIsSuper) {
1738  RefPtr<RegisterID> superBase = emitSuperBaseForCallee(generator);
1739  generator.emitGetById(function.get(), superBase.get(), callArguments.thisRegister(), m_ident);
1740  } else
1741  generator.emitGetById(function.get(), callArguments.thisRegister(), m_ident);
 1811
 1812 RefPtr<RegisterID> base = baseIsSuper ? emitSuperBaseForCallee(generator) : callArguments.thisRegister();
 1813 emitGetPropertyValue(generator, function.get(), base.get());
17421814
17431815 if (isOptionalChainBase())
17441816 generator.emitOptionalCheck(function.get());

@@RegisterID* PostfixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst)
21282200 RefPtr<RegisterID> base = generator.emitNode(baseNode);
21292201
21302202 generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd());
 2203
 2204 if (dotAccessor->isPrivateField()) {
 2205 ASSERT(!baseIsSuper);
 2206 Variable var = generator.variable(ident);
 2207 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
 2208 RefPtr<RegisterID> privateName = generator.newTemporary();
 2209 generator.emitGetFromScope(privateName.get(), scope.get(), var, DoNotThrowIfNotFound);
 2210
 2211 RefPtr<RegisterID> value = generator.emitDirectGetByVal(generator.newTemporary(), base.get(), privateName.get());
 2212 RefPtr<RegisterID> oldValue = emitPostIncOrDec(generator, generator.tempDestination(dst), value.get(), m_operator);
 2213 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
 2214 generator.emitPrivateFieldPut(base.get(), privateName.get(), value.get());
 2215 generator.emitProfileType(value.get(), divotStart(), divotEnd());
 2216 return generator.move(dst, oldValue.get());
 2217 }
 2218
21312219 RefPtr<RegisterID> value;
21322220 RefPtr<RegisterID> thisValue;
21332221 if (baseIsSuper) {

@@RegisterID* PrefixNode::emitDot(BytecodeGenerator& generator, RegisterID* dst)
23512439
23522440 generator.emitExpressionInfo(dotAccessor->divot(), dotAccessor->divotStart(), dotAccessor->divotEnd());
23532441 RegisterID* value;
 2442 if (dotAccessor->isPrivateField()) {
 2443 ASSERT(!baseNode->isSuperNode());
 2444 Variable var = generator.variable(ident);
 2445 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
 2446 RefPtr<RegisterID> privateName = generator.newTemporary();
 2447 generator.emitGetFromScope(privateName.get(), scope.get(), var, DoNotThrowIfNotFound);
 2448
 2449 value = generator.emitDirectGetByVal(propDst.get(), base.get(), privateName.get());
 2450 emitIncOrDec(generator, value, m_operator);
 2451 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
 2452 generator.emitPrivateFieldPut(base.get(), privateName.get(), value);
 2453 generator.emitProfileType(value, divotStart(), divotEnd());
 2454 return generator.move(dst, propDst.get());
 2455 }
 2456
23542457 RefPtr<RegisterID> thisValue;
23552458 if (baseNode->isSuperNode()) {
23562459 thisValue = generator.ensureThis();

@@RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID
31933296 RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
31943297 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
31953298 RefPtr<RegisterID> forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.move(generator.tempDestination(result.get()), result.get());
3196  if (m_base->isSuperNode()) {
3197  RefPtr<RegisterID> thisValue = generator.ensureThis();
3198  generator.emitPutById(base.get(), thisValue.get(), m_ident, forwardResult.get());
3199  } else
3200  generator.emitPutById(base.get(), m_ident, forwardResult.get());
 3299 emitPutProperty(generator, base.get(), forwardResult.get());
32013300 generator.emitProfileType(forwardResult.get(), divotStart(), divotEnd());
32023301 return generator.move(dst, forwardResult.get());
32033302}

@@RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, Regist
32093308 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator));
32103309
32113310 generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
3212  RefPtr<RegisterID> value;
32133311 RefPtr<RegisterID> thisValue;
3214  if (m_base->isSuperNode()) {
3215  thisValue = generator.ensureThis();
3216  value = generator.emitGetById(generator.tempDestination(dst), base.get(), thisValue.get(), m_ident);
3217  } else
3218  value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
 3312 RefPtr<RegisterID> value = emitGetPropertyValue(generator, generator.tempDestination(dst), base.get(), thisValue);
 3313
32193314 RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
32203315
32213316 generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
3222  RegisterID* ret;
3223  if (m_base->isSuperNode())
3224  ret = generator.emitPutById(base.get(), thisValue.get(), m_ident, updatedValue);
3225  else
3226  ret = generator.emitPutById(base.get(), m_ident, updatedValue);
 3317 RefPtr<RegisterID> ret = emitPutProperty(generator, base.get(), updatedValue, thisValue);
32273318 generator.emitProfileType(updatedValue, divotStart(), divotEnd());
3228  return ret;
 3319 return ret.get();
32293320}
32303321
32313322// ------------------------------ ShortCircuitReadModifyDotNode -----------------------------------

@@void DefineFieldNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
46984789 generator.emitCallDefineProperty(generator.thisRegister(), propertyName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
46994790 break;
47004791 }
 4792 case DefineFieldNode::Type::PrivateName: {
 4793 Variable var = generator.variable(*m_ident);
 4794 ASSERT_WITH_MESSAGE(!var.local(), "Private Field names must be stored in captured variables");
 4795
 4796 generator.emitExpressionInfo(position(), position(), position() + m_ident->length());
 4797 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
 4798 RefPtr<RegisterID> privateName = generator.newTemporary();
 4799 generator.emitGetFromScope(privateName.get(), scope.get(), var, DoNotThrowIfNotFound);
 4800 generator.emitDefinePrivateField(generator.thisRegister(), privateName.get(), value.get());
 4801 break;
 4802 }
47014803 case DefineFieldNode::Type::ComputedName: {
47024804 // FIXME: Improve performance of public class fields
47034805 // https://bugs.webkit.org/show_bug.cgi?id=198330

@@void DefineFieldNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
47084810 ASSERT_WITH_MESSAGE(!var.local(), "Computed names must be stored in captured variables");
47094811
47104812 generator.emitExpressionInfo(position(), position(), position() + 1);
4711  RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), var);
 4813 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
47124814 RefPtr<RegisterID> privateName = generator.newTemporary();
47134815 generator.emitGetFromScope(privateName.get(), scope.get(), var, ThrowIfNotFound);
47144816 generator.emitProfileType(privateName.get(), var, m_position, m_position + m_ident->length());

@@RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID
48004902 generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position);
48014903
48024904 if (m_classElements) {
 4905 m_classElements->emitDeclarePrivateFieldNames(generator, generator.scopeRegister());
 4906
48034907 Vector<JSTextPosition> instanceFieldLocations;
48044908 generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get(), instanceFieldLocations);
48054909 if (!instanceFieldLocations.isEmpty()) {

Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

7171#include "PreciseJumpTargets.h"
7272#include "PutByIdFlags.h"
7373#include "PutByIdStatus.h"
 74#include "PutByValFlags.h"
7475#include "RegExpPrototype.h"
7576#include "StackAlignment.h"
7677#include "StringConstructor.h"

@@private:
12651266 bool m_hasAnyForceOSRExits { false };
12661267};
12671268
 1269template<typename Bytecode>
 1270ECMAMode ecmaMode(Bytecode bytecode)
 1271{
 1272 return bytecode.m_ecmaMode;
 1273}
 1274
 1275template<>
 1276ALWAYS_INLINE ECMAMode ecmaMode<OpPutByValDirect>(OpPutByValDirect bytecode)
 1277{
 1278 return bytecode.m_flags.ecmaMode();
 1279}
 1280
12681281BasicBlock* ByteCodeParser::allocateTargetableBlock(BytecodeIndex bytecodeIndex)
12691282{
12701283 ASSERT(bytecodeIndex);

@@void ByteCodeParser::handlePutByVal(Bytecode bytecode, BytecodeIndex osrExitInde
82368249 }
82378250
82388251 if (compiledAsPutById)
8239  handlePutById(base, identifier, identifierNumber, value, putByIdStatus, isDirect, osrExitIndex, bytecode.m_ecmaMode);
 8252 handlePutById(base, identifier, identifierNumber, value, putByIdStatus, isDirect, osrExitIndex, ecmaMode(bytecode));
82408253 }
82418254
82428255 if (!compiledAsPutById) {

@@void ByteCodeParser::handlePutByVal(Bytecode bytecode, BytecodeIndex osrExitInde
82478260 addVarArgChild(value);
82488261 addVarArgChild(nullptr); // Leave room for property storage.
82498262 addVarArgChild(nullptr); // Leave room for length.
8250  addToGraph(Node::VarArg, isDirect ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(bytecode.m_ecmaMode));
 8263 addToGraph(Node::VarArg, isDirect ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(ecmaMode(bytecode)));
82518264 m_exitOK = false; // PutByVal and PutByValDirect must be treated as if they clobber exit state, since FixupPhase may make them generic.
82528265 }
82538266}

Source/JavaScriptCore/dfg/DFGCapabilities.cpp

@@CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const I
298298
299299 case op_yield:
300300 case op_create_generator_frame_environment:
 301 case op_get_private_name: // FIXME: op_get_private_name will need DFG/FTL support to ship class fields. (https://bugs.webkit.org/show_bug.cgi?id=212781)
301302 case llint_program_prologue:
302303 case llint_eval_prologue:
303304 case llint_module_program_prologue:

Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

@@void SpeculativeJIT::cachedPutById(CodeOrigin codeOrigin, GPRReg baseGPR, JSValu
1438114381 JITPutByIdGenerator gen(
1438214382 m_jit.codeBlock(), codeOrigin, callSite, usedRegisters, identifier,
1438314383 JSValueRegs::payloadOnly(baseGPR), valueRegs,
14384  scratchGPR, ecmaMode, putKind);
 14384 scratchGPR, ecmaMode, putKind, PrivateFieldAccessKind::None);
1438514385
1438614386 gen.generateFastPath(m_jit);
1438714387

Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

@@private:
42074207 jit.codeBlock(), node->origin.semantic, callSiteIndex,
42084208 params.unavailableRegisters(), identifier, JSValueRegs(params[0].gpr()),
42094209 JSValueRegs(params[1].gpr()), GPRInfo::patchpointScratchRegister, ecmaMode,
4210  node->op() == PutByIdDirect ? Direct : NotDirect);
 4210 node->op() == PutByIdDirect ? Direct : NotDirect, PrivateFieldAccessKind::None);
42114211
42124212 generator->generateFastPath(jit);
42134213 CCallHelpers::Label done = jit.label();

Source/JavaScriptCore/generator/DSL.rb

@@module DSL
141141#include "Opcode.h"
142142#include "PutByIdStatus.h"
143143#include "PutByIdFlags.h"
 144#include "PutByValFlags.h"
144145#include "ToThisStatus.h"
145146
146147namespace JSC {

Source/JavaScriptCore/jit/ICStats.h

@@namespace JSC {
6767 macro(OperationPutByIdNonStrictBuildList) \
6868 macro(OperationPutByIdDirectStrictBuildList) \
6969 macro(OperationPutByIdDirectNonStrictBuildList) \
 70 macro(OperationPutByIdDefinePrivateFieldFieldStrictOptimize) \
 71 macro(OperationPutByIdPutPrivateFieldFieldStrictOptimize) \
7072 macro(PutByIdAddAccessCase) \
7173 macro(PutByIdReplaceWithJump) \
7274 macro(PutByIdSelfPatch) \

Source/JavaScriptCore/jit/JIT.cpp

@@void JIT::privateCompileMainPass()
292292 DEFINE_SLOW_OP(push_with_scope)
293293 DEFINE_SLOW_OP(create_lexical_environment)
294294 DEFINE_SLOW_OP(get_by_val_with_this)
 295 DEFINE_SLOW_OP(get_private_name)
295296 DEFINE_SLOW_OP(put_by_id_with_this)
296297 DEFINE_SLOW_OP(put_by_val_with_this)
297298 DEFINE_SLOW_OP(resolve_scope_for_hoisting_func_decl_in_eval)

Source/JavaScriptCore/jit/JIT.h

@@namespace JSC {
401401 template<typename Op>
402402 JumpList emitFloatTypedArrayPutByVal(Op, PatchableJump& badType, TypedArrayType);
403403
404  // Identifier check helper for PutByVal.
 404 template<typename Op>
 405 ECMAMode ecmaMode(Op);
 406
 407 // Determines the type of private field access for a bytecode.
 408 template<typename Op>
 409 PrivateFieldAccessKind privateFieldAccessKind(Op);
 410
 411 // Identifier check helper for GetByVal and PutByVal.
405412 void emitByValIdentifierCheck(RegisterID cell, RegisterID scratch, CacheableIdentifier, JumpList& slowCases);
406413
407414 template<typename Op>

Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp

@@void JITGetByIdWithThisGenerator::generateFastPath(MacroAssembler& jit)
136136JITPutByIdGenerator::JITPutByIdGenerator(
137137 CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, const RegisterSet& usedRegisters, CacheableIdentifier,
138138 JSValueRegs base, JSValueRegs value, GPRReg scratch,
139  ECMAMode ecmaMode, PutKind putKind)
140  : JITByIdGenerator(
141  codeBlock, codeOrigin, callSite, AccessType::Put, usedRegisters, base, value)
142  , m_ecmaMode(ecmaMode)
143  , m_putKind(putKind)
 139 ECMAMode ecmaMode, PutKind putKind, PrivateFieldAccessKind privateFieldAccessKind)
 140 : JITByIdGenerator(codeBlock, codeOrigin, callSite, AccessType::Put, usedRegisters, base, value)
 141 , m_ecmaMode(ecmaMode)
 142 , m_putKind(putKind)
 143 , m_privateFieldAccessKind(privateFieldAccessKind)
144144{
145145 m_stubInfo->usedRegisters.clear(scratch);
146146}

@@void JITPutByIdGenerator::generateFastPath(MacroAssembler& jit)
152152
153153V_JITOperation_GSsiJJC JITPutByIdGenerator::slowPathFunction()
154154{
 155 if (m_privateFieldAccessKind != PrivateFieldAccessKind::None) {
 156 ASSERT(m_putKind == Direct);
 157 ASSERT(m_ecmaMode.isStrict());
 158 if (m_privateFieldAccessKind == PrivateFieldAccessKind::Create)
 159 return operationPutByIdDefinePrivateFieldStrictOptimize;
 160 return operationPutByIdPutPrivateFieldStrictOptimize;
 161 }
 162
155163 if (m_ecmaMode.isStrict()) {
156164 if (m_putKind == Direct)
157165 return operationPutByIdDirectStrictOptimize;

Source/JavaScriptCore/jit/JITInlineCacheGenerator.h

3030#include "CodeOrigin.h"
3131#include "JITOperations.h"
3232#include "JSCJSValue.h"
 33#include "PutByValFlags.h"
3334#include "PutKind.h"
3435#include "RegisterSet.h"
3536

@@class JITPutByIdGenerator : public JITByIdGenerator {
130131public:
131132 JITPutByIdGenerator()
132133 : m_ecmaMode(ECMAMode::strict())
 134 , m_privateFieldAccessKind(PrivateFieldAccessKind::None)
133135 { }
134136
135137 JITPutByIdGenerator(
136138 CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet& usedRegisters, CacheableIdentifier, JSValueRegs base,
137  JSValueRegs value, GPRReg scratch, ECMAMode, PutKind);
 139 JSValueRegs value, GPRReg scratch, ECMAMode, PutKind, PrivateFieldAccessKind privateAccess);
138140
139141 void generateFastPath(MacroAssembler&);
140142

@@public:
143145private:
144146 ECMAMode m_ecmaMode;
145147 PutKind m_putKind;
 148 PrivateFieldAccessKind m_privateFieldAccessKind;
146149};
147150
148151class JITDelByValGenerator : public JITInlineCacheGenerator {

Source/JavaScriptCore/jit/JITInlines.h

@@ALWAYS_INLINE BinaryArithProfile JIT::copiedArithProfile(BinaryOp bytecode)
686686 return arithProfile;
687687}
688688
 689template<typename Op>
 690ALWAYS_INLINE ECMAMode JIT::ecmaMode(Op op)
 691{
 692 return op.m_ecmaMode;
 693}
 694
 695template<>
 696ALWAYS_INLINE ECMAMode JIT::ecmaMode<OpPutById>(OpPutById op)
 697{
 698 return op.m_flags.ecmaMode();
 699}
 700
 701template<>
 702ALWAYS_INLINE ECMAMode JIT::ecmaMode<OpPutByValDirect>(OpPutByValDirect op)
 703{
 704 return op.m_flags.ecmaMode();
 705}
 706
 707template<typename Op>
 708PrivateFieldAccessKind JIT::privateFieldAccessKind(Op)
 709{
 710 return PrivateFieldAccessKind::None;
 711}
 712
 713template<>
 714ALWAYS_INLINE PrivateFieldAccessKind JIT::privateFieldAccessKind<OpPutByValDirect>(OpPutByValDirect op)
 715{
 716 return op.m_flags.privateFieldAccessKind();
 717}
 718
689719} // namespace JSC
690720
691721#endif // ENABLE(JIT)

Source/JavaScriptCore/jit/JITOperations.cpp

@@void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(JSGlobalObject* globa
697697 repatchPutByID(globalObject, codeBlock, baseObject, structure, identifier, slot, *stubInfo, Direct);
698698}
699699
 700} // extern "C"
 701
 702using PutPrivateFieldCallback = std::function<void(VM&, CodeBlock*, Structure*, PutPropertySlot&, const Identifier&)>;
 703ALWAYS_INLINE static void putPrivateField(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame, JSValue baseValue, CacheableIdentifier identifier, JSValue value, const PutPrivateFieldCallback& callback = PutPrivateFieldCallback())
 704{
 705 auto scope = DECLARE_THROW_SCOPE(vm);
 706
 707 Identifier ident = Identifier::fromUid(vm, identifier.uid());
 708 ASSERT(ident.isPrivateName());
 709
 710 JSObject* baseObject = asObject(baseValue);
 711 CodeBlock* codeBlock = callFrame->codeBlock();
 712 Structure* oldStructure = baseObject->structure(vm);
 713
 714 PutPropertySlot putSlot(baseObject, true, codeBlock->putByIdContext());
 715 baseObject->putPrivateField(globalObject, ident, value, putSlot);
 716 RETURN_IF_EXCEPTION(scope, void());
 717
 718 if (callback)
 719 callback(vm, codeBlock, oldStructure, putSlot, ident);
 720}
 721
 722ALWAYS_INLINE static void definePrivateField(VM& vm, JSGlobalObject* globalObject, CallFrame* callFrame, JSValue baseValue, CacheableIdentifier identifier, JSValue value, const PutPrivateFieldCallback& callback = PutPrivateFieldCallback())
 723{
 724 auto scope = DECLARE_THROW_SCOPE(vm);
 725
 726 Identifier ident = Identifier::fromUid(vm, identifier.uid());
 727 ASSERT(ident.isPrivateName());
 728
 729 JSObject* baseObject = asObject(baseValue);
 730 CodeBlock* codeBlock = callFrame->codeBlock();
 731 Structure* oldStructure = baseObject->structure(vm);
 732
 733 PutPropertySlot putSlot(baseObject, true, codeBlock->putByIdContext());
 734 baseObject->definePrivateField(globalObject, ident, value, putSlot);
 735 RETURN_IF_EXCEPTION(scope, void());
 736
 737 if (callback)
 738 callback(vm, codeBlock, oldStructure, putSlot, ident);
 739}
 740
 741extern "C" {
 742
 743void JIT_OPERATION operationPutByIdDefinePrivateFieldStrict(JSGlobalObject* globalObject, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t rawCacheableIdentifier)
 744{
 745 VM& vm = globalObject->vm();
 746 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
 747
 748 CacheableIdentifier identifier = CacheableIdentifier::createFromRawBits(rawCacheableIdentifier);
 749 JSValue value = JSValue::decode(encodedValue);
 750 JSValue baseValue = JSValue::decode(encodedBase);
 751
 752 definePrivateField(vm, globalObject, callFrame, baseValue, identifier, value);
 753}
 754
 755void JIT_OPERATION operationPutByIdDefinePrivateFieldStrictOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t rawCacheableIdentifier)
 756{
 757 SuperSamplerScope superSamplerScope(false);
 758 VM& vm = globalObject->vm();
 759 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
 760 JITOperationPrologueCallFrameTracer tracer(vm, callFrame);
 761
 762 CacheableIdentifier identifier = CacheableIdentifier::createFromRawBits(rawCacheableIdentifier);
 763 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
 764 JSValue value = JSValue::decode(encodedValue);
 765 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
 766
 767 definePrivateField(vm, globalObject, callFrame, baseObject, identifier, value, [=](VM& vm, CodeBlock* codeBlock, Structure* oldStructure, PutPropertySlot& putSlot, const Identifier& ident) {
 768 LOG_IC((ICEvent::OperationPutByIdDefinePrivateFieldFieldStrictOptimize, baseObject->classInfo(vm), ident, putSlot.base() == baseObject));
 769
 770 ASSERT_UNUSED(accessType, accessType == static_cast<AccessType>(stubInfo->accessType));
 771
 772 if (stubInfo->considerCachingBy(vm, codeBlock, oldStructure, identifier))
 773 repatchPutByID(globalObject, codeBlock, baseObject, oldStructure, identifier, putSlot, *stubInfo, DirectPrivateFieldCreate);
 774 });
 775}
 776
 777void JIT_OPERATION operationPutByIdPutPrivateFieldStrict(JSGlobalObject* globalObject, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t rawCacheableIdentifier)
 778{
 779 VM& vm = globalObject->vm();
 780 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
 781
 782 CacheableIdentifier identifier = CacheableIdentifier::createFromRawBits(rawCacheableIdentifier);
 783 JSValue value = JSValue::decode(encodedValue);
 784 JSValue baseValue = JSValue::decode(encodedBase);
 785
 786 putPrivateField(vm, globalObject, callFrame, baseValue, identifier, value);
 787}
 788
 789void JIT_OPERATION operationPutByIdPutPrivateFieldStrictOptimize(JSGlobalObject* globalObject, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t rawCacheableIdentifier)
 790{
 791 SuperSamplerScope superSamplerScope(false);
 792 VM& vm = globalObject->vm();
 793 CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
 794 NativeCallFrameTracer tracer(vm, callFrame);
 795
 796 CacheableIdentifier identifier = CacheableIdentifier::createFromRawBits(rawCacheableIdentifier);
 797 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
 798 JSValue value = JSValue::decode(encodedValue);
 799 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
 800
 801 putPrivateField(vm, globalObject, callFrame, baseObject, identifier, value, [&](VM& vm, CodeBlock* codeBlock, Structure* oldStructure, PutPropertySlot& putSlot, const Identifier& ident) {
 802 LOG_IC((ICEvent::OperationPutByIdPutPrivateFieldFieldStrictOptimize, baseObject->classInfo(vm), ident, putSlot.base() == baseObject));
 803
 804 ASSERT_UNUSED(accessType, accessType == static_cast<AccessType>(stubInfo->accessType));
 805
 806 if (stubInfo->considerCachingBy(vm, codeBlock, oldStructure, identifier))
 807 repatchPutByID(globalObject, codeBlock, baseObject, oldStructure, identifier, putSlot, *stubInfo, DirectPrivateFieldPut);
 808 });
 809}
 810
700811static void putByVal(JSGlobalObject* globalObject, JSValue baseValue, JSValue subscript, JSValue value, ByValInfo* byValInfo, ECMAMode ecmaMode)
701812{
702813 VM& vm = globalObject->vm();

Source/JavaScriptCore/jit/JITOperations.h

@@void JIT_OPERATION operationPutByIdStrictOptimize(JSGlobalObject*, StructureStub
188188void JIT_OPERATION operationPutByIdNonStrictOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
189189void JIT_OPERATION operationPutByIdDirectStrictOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
190190void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
 191void JIT_OPERATION operationPutByIdDefinePrivateFieldStrict(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
 192void JIT_OPERATION operationPutByIdDefinePrivateFieldStrictOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
 193void JIT_OPERATION operationPutByIdPutPrivateFieldStrict(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
 194void JIT_OPERATION operationPutByIdPutPrivateFieldStrictOptimize(JSGlobalObject*, StructureStubInfo*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, uintptr_t) WTF_INTERNAL;
191195
192196void JIT_OPERATION operationPutByValOptimize(JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, ECMAMode) WTF_INTERNAL;
193197void JIT_OPERATION operationDirectPutByValOptimize(JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, ECMAMode) WTF_INTERNAL;

Source/JavaScriptCore/jit/JITPropertyAccess.cpp

@@JITPutByIdGenerator JIT::emitPutByValWithCachedId(Op bytecode, PutKind putKind,
275275
276276 JITPutByIdGenerator gen(
277277 m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(), propertyName,
278  JSValueRegs(regT0), JSValueRegs(regT1), regT2, bytecode.m_ecmaMode, putKind);
 278 JSValueRegs(regT0), JSValueRegs(regT1), regT2, ecmaMode(bytecode), putKind, privateFieldAccessKind(bytecode));
279279 gen.generateFastPath(*this);
280280 // IC can write new Structure without write-barrier if a base is cell.
281281 // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size.

@@void JIT::emitSlow_op_put_by_val(const Instruction* currentInstruction, Vector<S
305305 base = bytecode.m_base;
306306 property = bytecode.m_property;
307307 value = bytecode.m_value;
308  ecmaMode = bytecode.m_ecmaMode;
 308 ecmaMode = JIT::ecmaMode(bytecode);
309309 };
310310
311311 if (isDirect)

@@void JIT::emit_op_put_by_id(const Instruction* currentInstruction)
658658 JITPutByIdGenerator gen(
659659 m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
660660 CacheableIdentifier::createFromIdentifierOwnedByCodeBlock(m_codeBlock, *ident),
661  JSValueRegs(regT0), JSValueRegs(regT1), regT2, bytecode.m_flags.ecmaMode(),
662  direct ? Direct : NotDirect);
 661 JSValueRegs(regT0), JSValueRegs(regT1), regT2, ecmaMode(bytecode),
 662 direct ? Direct : NotDirect, privateFieldAccessKind(bytecode));
663663
664664 gen.generateFastPath(*this);
665665 addSlowCase(gen.slowPathJump());

@@JITPutByIdGenerator JIT::emitPutByValWithCachedId(Op bytecode, PutKind putKind,
13171317
13181318 JITPutByIdGenerator gen(
13191319 m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(), propertyName,
1320  JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2), regT1, bytecode.m_ecmaMode, putKind);
 1320 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2), regT1, ecmaMode(bytecode), putKind, privateFieldAccessKind(bytecode));
13211321 gen.generateFastPath(*this);
13221322 doneCases.append(jump());
13231323

Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

@@void JIT::emitSlow_op_put_by_val(const Instruction* currentInstruction, Vector<S
455455 base = bytecode.m_base;
456456 property = bytecode.m_property;
457457 value = bytecode.m_value;
458  ecmaMode = bytecode.m_ecmaMode;
 458 ecmaMode = JIT::ecmaMode(bytecode);
459459 };
460460
461461 if (isDirect)

@@void JIT::emit_op_put_by_id(const Instruction* currentInstruction)
664664 m_codeBlock, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), RegisterSet::stubUnavailableRegisters(),
665665 CacheableIdentifier::createFromIdentifierOwnedByCodeBlock(m_codeBlock, *ident),
666666 JSValueRegs::payloadOnly(regT0), JSValueRegs(regT3, regT2),
667  regT1, bytecode.m_flags.ecmaMode(), direct ? Direct : NotDirect);
 667 regT1, bytecode.m_flags.ecmaMode(), direct ? Direct : NotDirect, PrivateFieldAccessKind::None);
668668
669669 gen.generateFastPath(*this);
670670 addSlowCase(gen.slowPathJump());

Source/JavaScriptCore/jit/Repatch.cpp

@@static auto appropriateGenericPutByIdFunction(const PutPropertySlot &slot, PutKi
520520 if (slot.isStrictMode()) {
521521 if (putKind == Direct)
522522 return operationPutByIdDirectStrict;
 523 if (putKind == DirectPrivateFieldCreate)
 524 return operationPutByIdDefinePrivateFieldStrict;
 525 if (putKind == DirectPrivateFieldPut)
 526 return operationPutByIdPutPrivateFieldStrict;
523527 return operationPutByIdStrict;
524528 }
525529 if (putKind == Direct)

@@static auto appropriateOptimizingPutByIdFunction(const PutPropertySlot &slot, Pu
532536 if (slot.isStrictMode()) {
533537 if (putKind == Direct)
534538 return operationPutByIdDirectStrictOptimize;
 539 if (putKind == DirectPrivateFieldCreate)
 540 return operationPutByIdDefinePrivateFieldStrictOptimize;
 541 if (putKind == DirectPrivateFieldPut)
 542 return operationPutByIdPutPrivateFieldStrictOptimize;
535543 return operationPutByIdStrictOptimize;
536544 }
537545 if (putKind == Direct)

@@static InlineCacheAction tryCachePutByID(JSGlobalObject* globalObject, CodeBlock
625633 std::unique_ptr<PolyProtoAccessChain> prototypeAccessChain;
626634 ObjectPropertyConditionSet conditionSet;
627635 if (putKind == NotDirect) {
 636 ASSERT(putKind != DirectPrivateFieldPut && putKind != DirectPrivateFieldCreate);
628637 auto cacheStatus = prepareChainForCaching(globalObject, baseCell, nullptr);
629638 if (!cacheStatus)
630639 return GiveUpOnCache;

@@static InlineCacheAction tryCachePutByID(JSGlobalObject* globalObject, CodeBlock
642651 }
643652 }
644653
 654 if (putKind == DirectPrivateFieldCreate) {
 655 ASSERT(ident.isPrivateName());
 656 conditionSet = generateConditionsForPropertyMiss(vm, codeBlock, globalObject, newStructure, ident.impl());
 657 if (!conditionSet.isValid())
 658 return GiveUpOnCache;
 659 }
 660
645661 newCase = AccessCase::createTransition(vm, codeBlock, propertyName, offset, oldStructure, newStructure, conditionSet, WTFMove(prototypeAccessChain));
646662 }
647663 } else if (slot.isCacheableCustom() || slot.isCacheableSetter()) {

Source/JavaScriptCore/llint/LLIntOffsetsExtractor.cpp

6060#include "NativeExecutable.h"
6161#include "PutByIdFlags.h"
6262#include "ProtoCallFrame.h"
 63#include "PutByValFlags.h"
6364#include "ShadowChicken.h"
6465#include "Structure.h"
6566#include "StructureChain.h"

Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

@@LLINT_SLOW_PATH_DECL(slow_path_get_by_val)
10701070 LLINT_RETURN_PROFILED(getByVal(vm, globalObject, codeBlock, baseValue, subscript, bytecode));
10711071}
10721072
 1073LLINT_SLOW_PATH_DECL(slow_path_get_private_name)
 1074{
 1075 LLINT_BEGIN();
 1076
 1077 auto bytecode = pc->as<OpGetPrivateName>();
 1078 JSValue baseValue = getOperand(callFrame, bytecode.m_base);
 1079 JSValue subscript = getOperand(callFrame, bytecode.m_property);
 1080 ASSERT(subscript.isSymbol());
 1081
 1082 baseValue.requireObjectCoercible(globalObject);
 1083 LLINT_CHECK_EXCEPTION();
 1084 auto property = subscript.toPropertyKey(globalObject);
 1085 LLINT_CHECK_EXCEPTION();
 1086 ASSERT(property.isPrivateName());
 1087
 1088 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
 1089 asObject(baseValue)->getPrivateField(globalObject, property, slot);
 1090 LLINT_CHECK_EXCEPTION();
 1091
 1092 if (!LLINT_ALWAYS_ACCESS_SLOW && slot.isCacheable() && !slot.isUnset()) {
 1093 auto& metadata = bytecode.metadata(codeBlock);
 1094 {
 1095 StructureID oldStructureID = metadata.m_structureID;
 1096 if (oldStructureID) {
 1097 Structure* a = vm.heap.structureIDTable().get(oldStructureID);
 1098 Structure* b = baseValue.asCell()->structure(vm);
 1099
 1100 if (Structure::shouldConvertToPolyProto(a, b)) {
 1101 ASSERT(a->rareData()->sharedPolyProtoWatchpoint().get() == b->rareData()->sharedPolyProtoWatchpoint().get());
 1102 a->rareData()->sharedPolyProtoWatchpoint()->invalidate(vm, StringFireDetail("Detected poly proto opportunity."));
 1103 }
 1104 }
 1105 }
 1106
 1107 JSCell* baseCell = baseValue.asCell();
 1108 Structure* structure = baseCell->structure(vm);
 1109 if (slot.isValue()) {
 1110 // Start out by clearing out the old cache.
 1111 metadata.m_structureID = 0;
 1112 metadata.m_offset = 0;
 1113
 1114 if (!structure->isUncacheableDictionary()) {
 1115 {
 1116 ConcurrentJSLocker locker(codeBlock->m_lock);
 1117 metadata.m_structureID = structure->id();
 1118 metadata.m_offset = slot.cachedOffset();
 1119
 1120 // Update the cached private symbol
 1121 metadata.m_property.set(vm, codeBlock, subscript.asCell());
 1122 }
 1123 vm.heap.writeBarrier(codeBlock);
 1124 }
 1125 }
 1126 }
 1127
 1128 LLINT_RETURN_PROFILED(slot.getValue(globalObject, property));
 1129}
 1130
10731131LLINT_SLOW_PATH_DECL(slow_path_put_by_val)
10741132{
10751133 LLINT_BEGIN();

@@LLINT_SLOW_PATH_DECL(slow_path_put_by_val_direct)
11111169 JSValue value = getOperand(callFrame, bytecode.m_value);
11121170 RELEASE_ASSERT(baseValue.isObject());
11131171 JSObject* baseObject = asObject(baseValue);
1114  bool isStrictMode = bytecode.m_ecmaMode.isStrict();
 1172 bool isStrictMode = bytecode.m_flags.ecmaMode().isStrict();
 1173 bool isPrivateFieldAccess = bytecode.m_flags.isPrivateFieldAccess();
11151174 if (Optional<uint32_t> index = subscript.tryGetAsUint32Index()) {
 1175 ASSERT(!isPrivateFieldAccess);
11161176 baseObject->putDirectIndex(globalObject, *index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
11171177 LLINT_END();
11181178 }
11191179
 1180 if (subscript.isDouble()) {
 1181 ASSERT(!isPrivateFieldAccess);
 1182 double subscriptAsDouble = subscript.asDouble();
 1183 uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
 1184 if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) {
 1185 baseObject->putDirectIndex(globalObject, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
 1186 LLINT_END();
 1187 }
 1188 }
 1189
11201190 // Don't put to an object if toString threw an exception.
11211191 auto property = subscript.toPropertyKey(globalObject);
11221192 if (UNLIKELY(throwScope.exception()))
11231193 LLINT_END();
11241194
 1195 ASSERT(property.isPrivateName() == isPrivateFieldAccess);
11251196 if (Optional<uint32_t> index = parseIndex(property))
11261197 baseObject->putDirectIndex(globalObject, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
11271198 else {
 1199 if (isPrivateFieldAccess) {
 1200 PutPropertySlot slot(baseObject, isStrictMode);
 1201 if (bytecode.m_flags.isPrivateFieldAdd())
 1202 baseObject->definePrivateField(globalObject, property, value, slot);
 1203 else
 1204 baseObject->putPrivateField(globalObject, property, value, slot);
 1205 LLINT_END();
 1206 }
 1207
11281208 PutPropertySlot slot(baseObject, isStrictMode);
11291209 CommonSlowPaths::putDirectWithReify(vm, globalObject, baseObject, property, value, slot);
11301210 }

Source/JavaScriptCore/llint/LLIntSlowPaths.h

@@LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id);
7272LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id);
7373LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_del_by_id);
7474LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val);
 75LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_private_name);
7576LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_argument_by_val);
7677LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val);
7778LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_direct);

Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

@@llintOpWithMetadata(op_get_by_val, OpGetByVal, macro (size, get, dispatch, metad
15971597
15981598end)
15991599
 1600llintOpWithMetadata(op_get_private_name, OpGetPrivateName, macro (size, get, dispatch, metadata, return)
 1601 metadata(t5, t0)
 1602
 1603 # Slow path if the private field is stale
 1604 get(m_property, t0)
 1605 loadp OpGetPrivateName::Metadata::m_property[t5], t1
 1606 bpneq t1, t0, .opGetPrivateNameSlow
 1607
 1608 get(m_base, t0)
 1609 loadi OpGetPrivateName::Metadata::m_structureID[t5], t1
 1610 loadConstantOrVariablePayload(size, t0, CellTag, t3, .opGetPrivateNameSlow)
 1611 loadi OpGetPrivateName::Metadata::m_offset[t5], t2
 1612 bineq JSCell::m_structureID[t3], t1, .opGetPrivateNameSlow
 1613
 1614 loadPropertyAtVariableOffset(t2, t3, t0, t1)
 1615 valueProfile(OpGetPrivateName, m_profile, t5, t0, t1)
 1616 return(t0, t1)
 1617
 1618.opGetPrivateNameSlow:
 1619 callSlowPath(_llint_slow_path_get_private_name)
 1620 dispatch()
 1621end)
 1622
16001623
16011624macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
16021625 llintOpWithMetadata(op_%opcodeName%, opcodeStruct, macro (size, get, dispatch, metadata, return)

Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

@@llintOpWithMetadata(op_get_by_val, OpGetByVal, macro (size, get, dispatch, metad
16631663
16641664end)
16651665
 1666llintOpWithMetadata(op_get_private_name, OpGetPrivateName, macro (size, get, dispatch, metadata, return)
 1667 metadata(t2, t0)
 1668
 1669 # Slow path if the private field is stale
 1670 get(m_property, t0)
 1671 loadp OpGetPrivateName::Metadata::m_property[t2], t1
 1672 bpneq t1, t0, .opGetPrivateNameSlow
 1673
 1674 get(m_base, t0)
 1675 loadConstantOrVariableCell(size, t0, t3, .opGetPrivateNameSlow)
 1676 loadi JSCell::m_structureID[t3], t1
 1677 loadi OpGetPrivateName::Metadata::m_structureID[t2], t0
 1678 bineq t0, t1, .opGetPrivateNameSlow
 1679
 1680 loadi OpGetPrivateName::Metadata::m_offset[t2], t1
 1681 loadPropertyAtVariableOffset(t1, t3, t0)
 1682 valueProfile(OpGetPrivateName, m_profile, t2, t0)
 1683 return(t0)
 1684
 1685.opGetPrivateNameSlow:
 1686 callSlowPath(_llint_slow_path_get_private_name)
 1687 dispatch()
 1688end)
16661689
16671690macro putByValOp(opcodeName, opcodeStruct, osrExitPoint)
16681691 llintOpWithMetadata(op_%opcodeName%, opcodeStruct, macro (size, get, dispatch, metadata, return)

Source/JavaScriptCore/parser/ASTBuilder.h

@@public:
270270 return node;
271271 }
272272
273  ExpressionNode* createDotAccess(const JSTokenLocation& location, ExpressionNode* base, const Identifier* property, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
 273 ExpressionNode* createDotAccess(const JSTokenLocation& location, ExpressionNode* base, const Identifier* property, DotType type, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
274274 {
275275 if (base->isSuperNode())
276276 usesSuperProperty();
277277
278  DotAccessorNode* node = new (m_parserArena) DotAccessorNode(location, base, *property);
 278 DotAccessorNode* node = new (m_parserArena) DotAccessorNode(location, base, *property, type);
279279 setExceptionLocation(node, start, divot, end);
280280 return node;
281281 }

@@public:
651651 return node->isAssignmentLocation();
652652 }
653653
 654 bool isPrivateLocation(const Expression& node)
 655 {
 656 return node->isPrivateLocation();
 657 }
 658
654659 bool isObjectLiteral(const Expression& node)
655660 {
656661 return node->isObjectLiteral();

@@ExpressionNode* ASTBuilder::makeFunctionCallNode(const JSTokenLocation& location
14381443 DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
14391444 FunctionCallDotNode* node = nullptr;
14401445 if (!previousBaseWasSuper && (dot->identifier() == m_vm.propertyNames->builtinNames().callPublicName() || dot->identifier() == m_vm.propertyNames->builtinNames().callPrivateName()))
1441  node = new (m_parserArena) CallFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd, callOrApplyChildDepth);
 1446 node = new (m_parserArena) CallFunctionCallDotNode(location, dot->base(), dot->identifier(), dot->type(), args, divot, divotStart, divotEnd, callOrApplyChildDepth);
14421447 else if (!previousBaseWasSuper && (dot->identifier() == m_vm.propertyNames->builtinNames().applyPublicName() || dot->identifier() == m_vm.propertyNames->builtinNames().applyPrivateName())) {
14431448 // FIXME: This check is only needed because we haven't taught the bytecode generator to inline
14441449 // Reflect.apply yet. See https://bugs.webkit.org/show_bug.cgi?id=190668.
14451450 if (!dot->base()->isResolveNode() || static_cast<ResolveNode*>(dot->base())->identifier() != m_vm.propertyNames->Reflect)
1446  node = new (m_parserArena) ApplyFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd, callOrApplyChildDepth);
 1451 node = new (m_parserArena) ApplyFunctionCallDotNode(location, dot->base(), dot->identifier(), dot->type(), args, divot, divotStart, divotEnd, callOrApplyChildDepth);
14471452 } else if (!previousBaseWasSuper
14481453 && dot->identifier() == m_vm.propertyNames->hasOwnProperty
14491454 && args->m_listNode

@@ExpressionNode* ASTBuilder::makeFunctionCallNode(const JSTokenLocation& location
14551460 // <resolveNode|thisNode>.hasOwnProperty(<resolveNode>)
14561461 // i.e:
14571462 // o.hasOwnProperty(p)
1458  node = new (m_parserArena) HasOwnPropertyFunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
 1463 node = new (m_parserArena) HasOwnPropertyFunctionCallDotNode(location, dot->base(), dot->identifier(), dot->type(), args, divot, divotStart, divotEnd);
14591464 }
14601465 if (!node)
1461  node = new (m_parserArena) FunctionCallDotNode(location, dot->base(), dot->identifier(), args, divot, divotStart, divotEnd);
 1466 node = new (m_parserArena) FunctionCallDotNode(location, dot->base(), dot->identifier(), dot->type(), args, divot, divotStart, divotEnd);
14621467 node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
14631468 return node;
14641469}

@@ExpressionNode* ASTBuilder::makeAssignNode(const JSTokenLocation& location, Expr
15991604 DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
16001605
16011606 if (op == Operator::Equal)
1602  return new (m_parserArena) AssignDotNode(location, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), start, end);
 1607 return new (m_parserArena) AssignDotNode(location, dot->base(), dot->identifier(), dot->type(), expr, exprHasAssignments, dot->divot(), start, end);
16031608
16041609 if (op == Operator::CoalesceEq || op == Operator::OrEq || op == Operator::AndEq) {
16051610 auto* node = new (m_parserArena) ShortCircuitReadModifyDotNode(location, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, start, end);

@@ExpressionNode* ASTBuilder::makeAssignNode(const JSTokenLocation& location, Expr
16071612 return node;
16081613 }
16091614
1610  ReadModifyDotNode* node = new (m_parserArena) ReadModifyDotNode(location, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, start, end);
 1615 ReadModifyDotNode* node = new (m_parserArena) ReadModifyDotNode(location, dot->base(), dot->identifier(), dot->type(), op, expr, exprHasAssignments, divot, start, end);
16111616 node->setSubexpressionInfo(dot->divot(), dot->divotEnd().offset);
16121617 return node;
16131618}

Source/JavaScriptCore/parser/Lexer.cpp

@@template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::p
945945 return keyword == RESERVED_IF_STRICT && !strictMode ? IDENT : keyword;
946946 }
947947 }
948 
949  bool isPrivateName = m_current == '@' && m_parsingBuiltinFunction;
 948
 949 bool isPrivateName = m_current == '#';
 950 bool isBuiltinName = m_current == '@' && m_parsingBuiltinFunction;
950951 bool isWellKnownSymbol = false;
951  if (isPrivateName) {
 952 if (isBuiltinName) {
952953 ASSERT(m_parsingBuiltinFunction);
953954 shift();
954955 if (m_current == '@') {

@@template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::p
956957 shift();
957958 }
958959 }
959 
 960
960961 const LChar* identifierStart = currentSourcePtr();
 962
 963 if (isPrivateName)
 964 shift();
 965
961966 ASSERT(isIdentStart(m_current) || m_current == '\\');
962967 while (isIdentPart(m_current))
963968 shift();

@@template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::p
969974
970975 if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
971976 int identifierLength = currentSourcePtr() - identifierStart;
972  if (m_parsingBuiltinFunction && isPrivateName) {
 977 ident = makeIdentifier(identifierStart, identifierLength);
 978 if (m_parsingBuiltinFunction && isBuiltinName) {
973979 if (isWellKnownSymbol)
974980 ident = &m_arena->makeIdentifier(m_vm, m_vm.propertyNames->builtinNames().lookUpWellKnownSymbol(identifierStart, identifierLength));
975981 else

@@template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::p
991997 } else
992998 tokenData->ident = nullptr;
993999
994  if (UNLIKELY((remaining < maxTokenLength) && !lexerFlags.contains(LexerFlags::IgnoreReservedWords)) && !isPrivateName) {
 1000 auto identType = isPrivateName ? PRIVATENAME : IDENT;
 1001 if (UNLIKELY((remaining < maxTokenLength) && !lexerFlags.contains(LexerFlags::IgnoreReservedWords)) && !isBuiltinName) {
9951002 ASSERT(shouldCreateIdentifier);
9961003 if (remaining < maxTokenLength) {
9971004 const HashTableValue* entry = JSC::mainTable.entry(*ident);
9981005 ASSERT((remaining < maxTokenLength) || !entry);
9991006 if (!entry)
1000  return IDENT;
 1007 return identType;
10011008 JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
1002  return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
 1009 return (token != RESERVED_IF_STRICT) || strictMode ? token : identType;
10031010 }
1004  return IDENT;
 1011 return identType;
10051012 }
10061013
1007  return IDENT;
 1014 return identType;
10081015}
10091016
10101017template <>

@@template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::p
10211028 }
10221029 }
10231030
 1031 bool isPrivateName = m_current == '#';
10241032 const UChar* identifierStart = currentSourcePtr();
 1033
 1034 if (isPrivateName)
 1035 shift();
 1036
10251037 UChar orAllChars = 0;
10261038 ASSERT(isSingleCharacterIdentStart(m_current) || U16_IS_SURROGATE(m_current) || m_current == '\\');
10271039 while (isSingleCharacterIdentPart(m_current)) {

@@template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::p
10451057 } else
10461058 tokenData->ident = nullptr;
10471059
 1060 if (isPrivateName)
 1061 return PRIVATENAME;
 1062
10481063 if (UNLIKELY((remaining < maxTokenLength) && !lexerFlags.contains(LexerFlags::IgnoreReservedWords))) {
10491064 ASSERT(shouldCreateIdentifier);
10501065 if (remaining < maxTokenLength) {

@@JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData
10691084 ASSERT(m_buffer16.isEmpty());
10701085 ASSERT(!tokenData->escaped);
10711086
 1087 auto identCharsStart = identifierStart;
 1088 bool isPrivateName = *identifierStart == '#';
 1089 if (isPrivateName)
 1090 ++identCharsStart;
 1091
 1092 JSTokenType identType = isPrivateName ? PRIVATENAME : IDENT;
 1093 ASSERT(!isPrivateName || identifierStart != currentSourcePtr());
 1094
10721095 auto fillBuffer = [&] (bool isStart = false) {
10731096 // \uXXXX unicode characters or Surrogate pairs.
10741097 if (identifierStart != currentSourcePtr())

@@JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData
10881111 if (shouldCreateIdentifier)
10891112 recordUnicodeCodePoint(character.value());
10901113 identifierStart = currentSourcePtr();
1091  return IDENT;
 1114 return identType;
10921115 }
10931116
10941117 ASSERT(U16_IS_SURROGATE(m_current));

@@JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData
11041127 shift();
11051128 shift();
11061129 identifierStart = currentSourcePtr();
1107  return IDENT;
 1130 return identType;
11081131 };
11091132
1110  JSTokenType type = fillBuffer(identifierStart == currentSourcePtr());
 1133 JSTokenType type = fillBuffer(identCharsStart == currentSourcePtr());
11111134 if (UNLIKELY(type & ErrorTokenFlag))
11121135 return type;
11131136

@@JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData
11401163 ASSERT(shouldCreateIdentifier);
11411164 const HashTableValue* entry = JSC::mainTable.entry(*ident);
11421165 if (!entry)
1143  return IDENT;
 1166 return identType;
11441167 JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
11451168 if ((token != RESERVED_IF_STRICT) || strictMode)
11461169 return UNEXPECTED_ESCAPE_ERRORTOK;
11471170 }
11481171
1149  return IDENT;
 1172 return identType;
11501173}
11511174
11521175static ALWAYS_INLINE bool characterRequiresParseStringSlowCase(LChar character)

@@start:
24732496 m_hasLineTerminatorBeforeToken = true;
24742497 m_lineStart = m_code;
24752498 goto start;
2476  case CharacterHash:
 2499 case CharacterHash: {
24772500 // Hashbang is only permitted at the start of the source text.
2478  if (peek(1) == '!' && !currentOffset()) {
 2501 auto next = peek(1);
 2502 if (next == '!' && !currentOffset()) {
24792503 shift();
24802504 shift();
24812505 goto inSingleLineComment;
24822506 }
 2507 // Otherwise, it could be a valid PrivateName.
 2508 if (Options::usePrivateClassFields() && (isSingleCharacterIdentStart(next) || next == '\\')) {
 2509 lexerFlags.remove(LexerFlags::DontBuildKeywords);
 2510 goto parseIdent;
 2511 }
24832512 goto invalidCharacter;
 2513 }
24842514 case CharacterPrivateIdentifierStart:
24852515 if (m_parsingBuiltinFunction)
24862516 goto parseIdent;

Source/JavaScriptCore/parser/NodeConstructors.h

@@namespace JSC {
327327 {
328328 }
329329
330  inline DotAccessorNode::DotAccessorNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident)
 330 inline BaseDotNode::BaseDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type)
331331 : ExpressionNode(location)
332332 , m_base(base)
333333 , m_ident(ident)
 334 , m_type(type)
 335 {
 336 }
 337
 338 inline DotAccessorNode::DotAccessorNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type)
 339 : BaseDotNode(location, base, ident, type)
334340 {
335341 }
336342

@@namespace JSC {
418424 {
419425 }
420426
421  inline FunctionCallDotNode::FunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
422  : ExpressionNode(location)
 427 inline FunctionCallDotNode::FunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
 428 : BaseDotNode(location, base, ident, type)
423429 , ThrowableSubExpressionData(divot, divotStart, divotEnd)
424  , m_base(base)
425  , m_ident(ident)
426430 , m_args(args)
427431 {
428432 }

@@namespace JSC {
437441 {
438442 }
439443
440  inline CallFunctionCallDotNode::CallFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply)
441  : FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
 444 inline CallFunctionCallDotNode::CallFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply)
 445 : FunctionCallDotNode(location, base, ident, type, args, divot, divotStart, divotEnd)
442446 , m_distanceToInnermostCallOrApply(distanceToInnermostCallOrApply)
443447 {
444448 }
445449
446  inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply)
447  : FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
 450 inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply)
 451 : FunctionCallDotNode(location, base, ident, type, args, divot, divotStart, divotEnd)
448452 , m_distanceToInnermostCallOrApply(distanceToInnermostCallOrApply)
449453 {
450454 }
451455
452  inline HasOwnPropertyFunctionCallDotNode::HasOwnPropertyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
453  : FunctionCallDotNode(location, base, ident, args, divot, divotStart, divotEnd)
 456 inline HasOwnPropertyFunctionCallDotNode::HasOwnPropertyFunctionCallDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type, ArgumentsNode* args, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
 457 : FunctionCallDotNode(location, base, ident, type, args, divot, divotStart, divotEnd)
454458 {
455459 }
456460

@@namespace JSC {
777781 {
778782 }
779783
780  inline AssignDotNode::AssignDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
781  : ExpressionNode(location)
 784 inline AssignDotNode::AssignDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
 785 : BaseDotNode(location, base, ident, type)
782786 , ThrowableExpressionData(divot, divotStart, divotEnd)
783  , m_base(base)
784  , m_ident(ident)
785787 , m_right(right)
786788 , m_rightHasAssignments(rightHasAssignments)
787789 {
788790 }
789791
790  inline ReadModifyDotNode::ReadModifyDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
791  : ExpressionNode(location)
 792 inline ReadModifyDotNode::ReadModifyDotNode(const JSTokenLocation& location, ExpressionNode* base, const Identifier& ident, DotType type, Operator oper, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
 793 : BaseDotNode(location, base, ident, type)
792794 , ThrowableSubExpressionData(divot, divotStart, divotEnd)
793  , m_base(base)
794  , m_ident(ident)
795795 , m_right(right)
796796 , m_operator(oper)
797797 , m_rightHasAssignments(rightHasAssignments)

Source/JavaScriptCore/parser/Nodes.cpp

@@bool PropertyListNode::hasStaticallyNamedProperty(const Identifier& propName)
335335bool PropertyListNode::shouldCreateLexicalScopeForClass(PropertyListNode* list)
336336{
337337 while (list) {
338  if (list->m_node->isComputedClassField())
 338 if (list->m_node->isComputedClassField() || list->m_node->isPrivate())
339339 return true;
340340 list = list->m_next;
341341 }

Source/JavaScriptCore/parser/Nodes.h

@@namespace JSC {
185185 virtual bool isPure(BytecodeGenerator&) const { return false; }
186186 virtual bool isConstant() const { return false; }
187187 virtual bool isLocation() const { return false; }
 188 virtual bool isPrivateLocation() const { return false; }
188189 virtual bool isAssignmentLocation() const { return isLocation(); }
189190 virtual bool isResolveNode() const { return false; }
190191 virtual bool isAssignResolveNode() const { return false; }

@@namespace JSC {
721722 enum class ClassElementTag : uint8_t { No, Instance, Static, LastTag };
722723 class PropertyNode final : public ParserArenaFreeable {
723724 public:
724  enum Type : uint8_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32 };
 725 enum Type : uint8_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, Private = 64 };
725726 enum PutType : uint8_t { Unknown, KnownDirect };
726727
727728 PropertyNode(const Identifier&, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);

@@namespace JSC {
740741 bool isClassField() const { return isClassProperty() && !needsSuperBinding(); }
741742 bool isInstanceClassField() const { return isInstanceClassProperty() && !needsSuperBinding(); }
742743 bool isOverriddenByDuplicate() const { return m_isOverriddenByDuplicate; }
 744 bool isPrivate() const { return m_type & Private; }
743745 bool hasComputedName() const { return m_expression; }
744746 bool isComputedClassField() const { return isClassField() && hasComputedName(); }
745747 void setIsOverriddenByDuplicate() { m_isOverriddenByDuplicate = true; }

@@namespace JSC {
750752 const Identifier* m_name;
751753 ExpressionNode* m_expression;
752754 ExpressionNode* m_assign;
753  unsigned m_type : 6;
 755 unsigned m_type : 7;
754756 unsigned m_needsSuperBinding : 1;
755757 unsigned m_putType : 1;
756758 static_assert(1 << 2 > static_cast<unsigned>(ClassElementTag::LastTag), "ClassElementTag shouldn't use more than two bits");

@@namespace JSC {
778780
779781 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector<JSTextPosition>*);
780782
 783 void emitDeclarePrivateFieldNames(BytecodeGenerator&, RegisterID* scope);
 784
781785 private:
782786 RegisterID* emitBytecode(BytecodeGenerator& generator, RegisterID* dst = nullptr) final
783787 {

@@namespace JSC {
822826 bool m_subscriptHasAssignments;
823827 };
824828
825  class DotAccessorNode final : public ExpressionNode, public ThrowableExpressionData {
 829 enum class DotType { Name, PrivateField };
 830 class BaseDotNode : public ExpressionNode {
826831 public:
827  DotAccessorNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&);
 832 BaseDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType);
 833
 834 ExpressionNode* base() const { return m_base; }
 835 const Identifier& identifier() const { return m_ident; }
 836 DotType type() const { return m_type; }
 837 bool isPrivateField() const { return m_type == DotType::PrivateField; }
 838
 839 RegisterID* emitGetPropertyValue(BytecodeGenerator&, RegisterID* dst, RegisterID* base, RefPtr<RegisterID>& thisValue);
 840 RegisterID* emitGetPropertyValue(BytecodeGenerator&, RegisterID* dst, RegisterID* base);
 841 RegisterID* emitPutProperty(BytecodeGenerator&, RegisterID* base, RegisterID* value, RefPtr<RegisterID>& thisValue);
 842 RegisterID* emitPutProperty(BytecodeGenerator&, RegisterID* base, RegisterID* value);
 843
 844 protected:
 845 ExpressionNode* m_base;
 846 const Identifier& m_ident;
 847 DotType m_type;
 848 };
 849
 850 class DotAccessorNode final : public BaseDotNode, public ThrowableExpressionData {
 851 public:
 852 DotAccessorNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType);
828853
829854 ExpressionNode* base() const { return m_base; }
830855 const Identifier& identifier() const { return m_ident; }

@@namespace JSC {
833858 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final;
834859
835860 bool isLocation() const final { return true; }
 861 bool isPrivateLocation() const override { return m_type == DotType::PrivateField; }
836862 bool isDotAccessorNode() const final { return true; }
837 
838  ExpressionNode* m_base;
839  const Identifier& m_ident;
840863 };
841864
842865 class SpreadExpressionNode final : public ExpressionNode, public ThrowableExpressionData {

@@namespace JSC {
949972 bool m_subscriptHasAssignments;
950973 };
951974
952  class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData {
 975 class FunctionCallDotNode : public BaseDotNode, public ThrowableSubExpressionData {
953976 public:
954  FunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 977 FunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
955978
956979 private:
957980 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) override;

@@namespace JSC {
959982 protected:
960983 bool isFunctionCall() const override { return true; }
961984
962  ExpressionNode* m_base;
963  const Identifier& m_ident;
964985 ArgumentsNode* m_args;
965986 };
966987

@@namespace JSC {
9971018
9981019 class CallFunctionCallDotNode final : public FunctionCallDotNode {
9991020 public:
1000  CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply);
 1021 CallFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply);
10011022
10021023 private:
10031024 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final;

@@namespace JSC {
10061027
10071028 class ApplyFunctionCallDotNode final : public FunctionCallDotNode {
10081029 public:
1009  ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply);
 1030 ApplyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, size_t distanceToInnermostCallOrApply);
10101031
10111032 private:
10121033 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final;

@@namespace JSC {
10151036
10161037 class HasOwnPropertyFunctionCallDotNode final : public FunctionCallDotNode {
10171038 public:
1018  HasOwnPropertyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 1039 HasOwnPropertyFunctionCallDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ArgumentsNode*, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
10191040
10201041 private:
10211042 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final;

@@namespace JSC {
14771498 bool m_rightHasAssignments : 1;
14781499 };
14791500
1480  class AssignDotNode final : public ExpressionNode, public ThrowableExpressionData {
 1501 class AssignDotNode final : public BaseDotNode, public ThrowableExpressionData {
14811502 public:
1482  AssignDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 1503 AssignDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
14831504
14841505 private:
14851506 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final;
14861507
1487  ExpressionNode* m_base;
1488  const Identifier& m_ident;
14891508 ExpressionNode* m_right;
14901509 bool m_rightHasAssignments;
14911510 };
14921511
1493  class ReadModifyDotNode final : public ExpressionNode, public ThrowableSubExpressionData {
 1512 class ReadModifyDotNode final : public BaseDotNode, public ThrowableSubExpressionData {
14941513 public:
1495  ReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
 1514 ReadModifyDotNode(const JSTokenLocation&, ExpressionNode* base, const Identifier&, DotType, Operator, ExpressionNode* right, bool rightHasAssignments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
14961515
14971516 private:
14981517 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = nullptr) final;
14991518
1500  ExpressionNode* m_base;
1501  const Identifier& m_ident;
15021519 ExpressionNode* m_right;
15031520 Operator m_operator;
15041521 bool m_rightHasAssignments : 1;

@@namespace JSC {
22952312
22962313 class DefineFieldNode final : public StatementNode {
22972314 public:
2298  enum class Type { Name, ComputedName };
 2315 enum class Type { Name, PrivateName, ComputedName };
22992316 DefineFieldNode(const JSTokenLocation&, const Identifier*, ExpressionNode*, Type);
23002317
23012318 private:

Source/JavaScriptCore/parser/Parser.cpp

@@template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVariableDecl
826826 TreeExpression node = 0;
827827 declarations++;
828828 bool hasInitializer = false;
 829
 830 failIfTrue(match(PRIVATENAME), "Cannot use a private name to declare a variable");
829831 if (matchSpecIdentifier()) {
830832 failIfTrue(match(LET) && (declarationType == DeclarationType::LetDeclaration || declarationType == DeclarationType::ConstDeclaration),
831833 "Cannot use 'let' as an identifier name for a LexicalDeclaration");

@@template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDe
12881290 if (kind == DestructuringKind::DestructureToExpressions)
12891291 return 0;
12901292 semanticFailureDueToKeyword(destructuringKindToVariableKindName(kind));
 1293 if (kind != DestructuringKind::DestructureToParameters)
 1294 failIfTrue(match(PRIVATENAME), "Cannot use a private name as a ", destructuringKindToVariableKindName(kind));
12911295 failWithMessage("Expected a parameter pattern or a ')' in parameter list");
12921296 }
12931297 failIfTrue(match(LET) && (kind == DestructuringKind::DestructureToLet || kind == DestructuringKind::DestructureToConst), "Cannot use 'let' as an identifier name for a LexicalDeclaration");

@@parseMethod:
29532957 failIfFalse(computedPropertyName, "Cannot parse computed property name");
29542958 handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
29552959 break;
 2960 case PRIVATENAME: {
 2961 ASSERT(Options::usePrivateClassFields());
 2962 JSToken token = m_token;
 2963 ident = m_token.m_data.ident;
 2964 failIfTrue(tag == ClassElementTag::Static, "Static class element cannot be private");
 2965 failIfTrue(isGetter || isSetter, "Cannot parse class method with private name");
 2966 ASSERT(ident);
 2967 next();
 2968 failIfTrue(matchAndUpdate(OPENPAREN, token), "Cannot parse class method with private name");
 2969 semanticFailIfTrue(classScope->declarePrivateName(*ident) & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare private field twice");
 2970 type = static_cast<PropertyNode::Type>(type | PropertyNode::Private);
 2971 break;
 2972 }
29562973 default:
29572974 if (m_token.m_type & KeywordTokenFlag)
29582975 goto namedKeyword;

@@parseMethod:
29682985 failIfFalse(property, "Cannot parse this method");
29692986 } else if (Options::usePublicClassFields() && !match(OPENPAREN) && tag == ClassElementTag::Instance && parseMode == SourceParseMode::MethodMode) {
29702987 ASSERT(!isGetter && !isSetter);
2971  if (ident)
 2988 if (ident) {
29722989 semanticFailIfTrue(*ident == propertyNames.constructor, "Cannot declare class field named 'constructor'");
 2990 semanticFailIfTrue(*ident == propertyNames.constructorPrivateField, "Cannot declare private class field named '#constructor'");
 2991 }
29732992
29742993 if (computedPropertyName) {
29752994 ident = &m_parserArena.identifierArena().makeNumericIdentifier(m_vm, numComputedFields++);

@@parseMethod:
30333052 info.endOffset = tokenLocation().endOffset - 1;
30343053 consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
30353054
 3055 if (Options::usePrivateClassFields()) {
 3056 // Fail if there are no parent private name scopes and any used-but-undeclared private names.
 3057 semanticFailIfFalse(copyUndeclaredPrivateNamesToOuterScope(), "Cannot reference undeclared private names");
 3058 }
30363059 auto classExpression = context.createClassExpr(location, info, classScope->finalizeLexicalEnvironment(), constructor, parentClass, classElements);
30373060 popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
30383061 return classExpression;

@@template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseInstance
30563079 TreeExpression computedPropertyName = 0;
30573080 DefineFieldNode::Type type = DefineFieldNode::Type::Name;
30583081 switch (m_token.m_type) {
 3082 case PRIVATENAME:
 3083 type = DefineFieldNode::Type::PrivateName;
 3084 FALLTHROUGH;
30593085 case STRING:
30603086 case IDENT:
30613087 namedKeyword:

@@template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseInstance
30953121 if (consume(EQUAL))
30963122 initializer = parseAssignmentExpression(context);
30973123
 3124 if (type == DefineFieldNode::Type::PrivateName)
 3125 currentScope()->useVariable(ident, false);
 3126
30983127 TreeStatement defineField = context.createDefineField(fieldLocation, ident, initializer, type);
30993128 context.appendStatement(sourceElements, defineField);
31003129 }

@@static inline void recordCallOrApplyDepth(ParserType*, VM&, Optional<typename Pa
47984827{
47994828}
48004829
 4830template <typename LexerType>
 4831bool Parser<LexerType>::usePrivateName(const Identifier* ident)
 4832{
 4833 if (m_lexer->isReparsingFunction())
 4834 return true;
 4835
 4836 if (auto maybeCurrent = findPrivateNameScope()) {
 4837 ScopeRef current = maybeCurrent.value();
 4838 if (!current->hasPrivateName(*ident))
 4839 current->usePrivateName(*ident);
 4840 return true;
 4841 }
 4842
 4843 return false;
 4844}
 4845
48014846template <typename LexerType>
48024847template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context)
48034848{

@@template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
49995044 m_parserState.nonTrivialExpressionCount++;
50005045 JSTextPosition expressionEnd = lastTokenEndPosition();
50015046 nextExpectIdentifier(TreeBuilder::DontBuildKeywords | LexerFlags::IgnoreReservedWords);
 5047 const Identifier* ident = m_token.m_data.ident;
 5048 auto type = DotType::Name;
 5049 if (match(PRIVATENAME)) {
 5050 ASSERT(ident);
 5051 failIfTrue(baseIsSuper, "Cannot access private names from super");
 5052 if (UNLIKELY(currentScope()->evalContextType() == EvalContextType::InstanceFieldEvalContext))
 5053 semanticFailIfFalse(currentScope()->hasPrivateName(*ident), "Cannot reference undeclared private field '", ident->impl(), "'");
 5054 semanticFailIfFalse(usePrivateName(ident), "Cannot reference private names outside of class");
 5055 m_parserState.lastPrivateName = ident;
 5056 currentScope()->useVariable(ident, false);
 5057 type = DotType::PrivateField;
 5058 m_token.m_type = IDENT;
 5059 }
50025060 matchOrFail(IDENT, "Expected a property name after ", optionalChainBase ? "'?.'" : "'.'");
5003  base = context.createDotAccess(startLocation, base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEndPosition());
 5061 base = context.createDotAccess(startLocation, base, ident, type, expressionStart, expressionEnd, tokenEndPosition());
50045062 if (UNLIKELY(baseIsSuper && currentScope()->isArrowFunction()))
50055063 currentFunctionScope()->setInnerArrowFunctionUsesSuperProperty();
50065064 next();

@@template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpress
51955253 break;
51965254 case DELETETOKEN:
51975255 failIfTrueIfStrict(context.isResolve(expr), "Cannot delete unqualified property '", m_parserState.lastIdentifier->impl(), "' in strict mode");
 5256 semanticFailIfTrue(context.isPrivateLocation(expr), "Cannot delete private field ", m_parserState.lastPrivateName->impl());
51985257 expr = context.makeDeleteNode(location, expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
51995258 break;
52005259 default:

@@template <typename LexerType> void Parser<LexerType>::printUnexpectedTokenText(W
52715330 case INVALID_PRIVATE_NAME_ERRORTOK:
52725331 out.print("Invalid private name '", getToken(), "'");
52735332 return;
5274 
 5333
 5334 case PRIVATENAME:
 5335 out.print("Unexpected private name ", getToken());
 5336 return;
 5337
52755338 case AWAIT:
52765339 case IDENT:
52775340 out.print("Unexpected identifier '", getToken(), "'");

Source/JavaScriptCore/parser/Parser.h

@@public:
290290 bool isGeneratorBoundary() const { return m_isGeneratorBoundary; }
291291 bool isAsyncFunction() const { return m_isAsyncFunction; }
292292 bool isAsyncFunctionBoundary() const { return m_isAsyncFunctionBoundary; }
 293 bool isPrivateNameScope() const { return m_isClassScope; }
293294 bool isClassScope() const { return m_isClassScope; }
294295
295296 bool hasArguments() const { return m_hasArguments; }

@@public:
309310 m_allowsLexicalDeclarations = true;
310311 }
311312
 313 void setIsPrivateNameScope()
 314 {
 315 // FIXME: Currently, isPrivateNameScope is an alias for isClassScope --- This is potentially misleading,
 316 // particularly when parsing direct eval code which occurs within a class.
 317 setIsClassScope();
 318 }
 319
312320 void setIsClassScope()
313321 {
314322 m_isClassScope = true;

@@public:
475483 {
476484 return m_lexicalVariables.contains(ident.get());
477485 }
478 
 486
 487 bool hasPrivateName(const Identifier& ident)
 488 {
 489 return m_lexicalVariables.hasPrivateName(ident);
 490 }
 491
 492 void copyUndeclaredPrivateNamesTo(Scope& other)
 493 {
 494 m_lexicalVariables.copyUndeclaredPrivateNamesTo(other.m_lexicalVariables);
 495 }
 496
 497 bool hasUsedButUndeclaredPrivateNames() const
 498 {
 499 if (m_lexicalVariables.privateNamesSize() > 0) {
 500 for (auto entry : m_lexicalVariables.privateNames()) {
 501 if (entry.value.isUsed() && !entry.value.isDeclared())
 502 return true;
 503 }
 504 }
 505 return false;
 506 }
 507
 508 void usePrivateName(const Identifier& ident)
 509 {
 510 ASSERT(m_allowsLexicalDeclarations);
 511 m_lexicalVariables.usePrivateName(ident);
 512 }
 513
 514 DeclarationResultMask declarePrivateName(const Identifier& ident)
 515 {
 516 ASSERT(m_allowsLexicalDeclarations);
 517 DeclarationResultMask result = DeclarationResult::Valid;
 518 auto addResult = m_lexicalVariables.declarePrivateName(ident);
 519 if (!addResult.isNewEntry)
 520 result |= DeclarationResult::InvalidDuplicateDeclaration;
 521 return result;
 522 }
 523
479524 ALWAYS_INLINE bool hasDeclaredParameter(const Identifier& ident)
480525 {
481526 return hasDeclaredParameter(ident.impl());

@@public:
910955 ~Parser();
911956
912957 template <class ParsedNode>
913  std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode, ParsingContext, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt, const Vector<JSTextPosition>* = nullptr);
 958 std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode, ParsingContext, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt, const VariableEnvironment* = nullptr, const Vector<JSTextPosition>* = nullptr);
914959
915960 JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
916961 JSTokenLocation locationBeforeLastToken() const { return m_lexer->lastTokenLocation(); }

@@private:
11831228 return ScopeRef(&m_scopeStack, i);
11841229 }
11851230
 1231 Optional<ScopeRef> findPrivateNameScope()
 1232 {
 1233 ASSERT(m_scopeStack.size());
 1234 unsigned i = m_scopeStack.size() - 1;
 1235 while (i && !m_scopeStack[i].isPrivateNameScope())
 1236 i--;
 1237
 1238 if (m_scopeStack[i].isPrivateNameScope())
 1239 return ScopeRef(&m_scopeStack, i);
 1240
 1241 return WTF::nullopt;
 1242 }
 1243
 1244 ScopeRef privateNameScope()
 1245 {
 1246 ASSERT(m_scopeStack.size());
 1247 unsigned i = m_scopeStack.size() - 1;
 1248 while (i && !m_scopeStack[i].isPrivateNameScope())
 1249 i--;
 1250
 1251 ASSERT(m_scopeStack[i].isPrivateNameScope());
 1252 return ScopeRef(&m_scopeStack, i);
 1253 }
 1254
 1255 bool copyUndeclaredPrivateNamesToOuterScope()
 1256 {
 1257 ScopeRef current = privateNameScope();
 1258 unsigned i = current.index() - 1;
 1259 while (i && !m_scopeStack[i].isPrivateNameScope())
 1260 i--;
 1261
 1262 if (!i)
 1263 return !current->hasUsedButUndeclaredPrivateNames();
 1264
 1265 current->copyUndeclaredPrivateNamesTo(m_scopeStack[i]);
 1266 return true;
 1267 }
 1268
11861269 ScopeRef closestParentOrdinaryFunctionNonLexicalScope()
11871270 {
11881271 unsigned i = m_scopeStack.size() - 1;

@@private:
14621545 {
14631546 return m_token.m_type == expected;
14641547 }
 1548
 1549 ALWAYS_INLINE bool matchAndUpdate(JSTokenType expected, const JSToken& token)
 1550 {
 1551 if (match(expected)) {
 1552 m_token = token;
 1553 return true;
 1554 }
 1555
 1556 return false;
 1557 }
14651558
14661559 ALWAYS_INLINE bool matchContextualKeyword(const Identifier& identifier)
14671560 {

@@private:
17151808
17161809 template <class TreeBuilder> ALWAYS_INLINE bool isSimpleAssignmentTarget(TreeBuilder&, TreeExpression);
17171810
 1811 ALWAYS_INLINE bool usePrivateName(const Identifier*);
 1812
17181813 ALWAYS_INLINE int isBinaryOperator(JSTokenType);
17191814 bool allowAutomaticSemicolon();
17201815

@@private:
18091904 FunctionParsePhase functionParsePhase { FunctionParsePhase::Body };
18101905 const Identifier* lastIdentifier { nullptr };
18111906 const Identifier* lastFunctionName { nullptr };
 1907 const Identifier* lastPrivateName { nullptr };
18121908 bool allowAwait { true };
18131909 bool isParsingClassFieldInitializer { false };
18141910 };

@@private:
19592055
19602056template <typename LexerType>
19612057template <class ParsedNode>
1962 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* instanceFieldLocations)
 2058std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* variablesUnderTDZ, const Vector<JSTextPosition>* instanceFieldLocations)
19632059{
19642060 int errLine;
19652061 String errMsg;

@@std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const I
19742070 ASSERT(m_source->startColumn() > OrdinalNumber::beforeFirst());
19752071 unsigned startColumn = m_source->startColumn().zeroBasedInt();
19762072
 2073 if (isEvalNode<ParsedNode>() && variablesUnderTDZ && variablesUnderTDZ->privateNamesSize()) {
 2074 currentScope()->setIsPrivateNameScope();
 2075 variablesUnderTDZ->copyPrivateNamesTo(currentScope()->lexicalVariables());
 2076 }
 2077
19772078 auto parseResult = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, instanceFieldLocations);
19782079
19792080 int lineNumber = m_lexer->lineNumber();

@@std::unique_ptr<ParsedNode> parse(
20582159 DerivedContextType derivedContextType = DerivedContextType::None,
20592160 EvalContextType evalContextType = EvalContextType::None,
20602161 DebuggerParseData* debuggerParseData = nullptr,
 2162 const VariableEnvironment* variablesUnderTDZ = nullptr,
20612163 const Vector<JSTextPosition>* instanceFieldLocations = nullptr,
20622164 bool isInsideOrdinaryFunction = false)
20632165{

@@std::unique_ptr<ParsedNode> parse(
20702172 std::unique_ptr<ParsedNode> result;
20712173 if (source.provider()->source().is8Bit()) {
20722174 Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction);
2073  result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, instanceFieldLocations);
 2175 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, variablesUnderTDZ, instanceFieldLocations);
20742176 if (positionBeforeLastNewline)
20752177 *positionBeforeLastNewline = parser.positionBeforeLastNewline();
20762178 if (builtinMode == JSParserBuiltinMode::Builtin) {

@@std::unique_ptr<ParsedNode> parse(
20832185 } else {
20842186 ASSERT_WITH_MESSAGE(defaultConstructorKindForTopLevelFunction == ConstructorKind::None, "BuiltinExecutables's special constructors should always use a 8-bit string");
20852187 Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction);
2086  result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, instanceFieldLocations);
 2188 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, variablesUnderTDZ, instanceFieldLocations);
20872189 if (positionBeforeLastNewline)
20882190 *positionBeforeLastNewline = parser.positionBeforeLastNewline();
20892191 }

Source/JavaScriptCore/parser/ParserTokens.h

@@enum JSTokenType {
114114 DOUBLE,
115115 BIGINT,
116116 IDENT,
 117 PRIVATENAME,
117118 STRING,
118119 TEMPLATE,
119120 REGEXP,

Source/JavaScriptCore/parser/SyntaxChecker.h

@@public:
7373 ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr, BigIntExpr,
7474 ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
7575 FunctionExpr, ClassExpr, SuperExpr, ImportExpr, BracketExpr, DotExpr, CallExpr,
76  NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr, OptionalChain,
 76 NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr, OptionalChain, PrivateDotExpr,
7777 ConditionalExpr, AssignmentExpr, TypeofExpr,
7878 DeleteExpr, ArrayLiteralExpr, BindingDestructuring, RestParameter,
7979 ArrayDestructuring, ObjectDestructuring, SourceElementsResult,

@@public:
180180 ExpressionType createBoolean(const JSTokenLocation&, bool) { return BoolExpr; }
181181 ExpressionType createNull(const JSTokenLocation&) { return NullExpr; }
182182 ExpressionType createBracketAccess(const JSTokenLocation&, ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
183  ExpressionType createDotAccess(const JSTokenLocation&, ExpressionType, const Identifier*, int, int, int) { return DotExpr; }
 183 ExpressionType createDotAccess(const JSTokenLocation&, ExpressionType, const Identifier*, DotType type, int, int, int) { return type == DotType::PrivateField ? PrivateDotExpr : DotExpr; }
184184 ExpressionType createRegExp(const JSTokenLocation&, const Identifier& pattern, const Identifier& flags, int) { return Yarr::hasError(Yarr::checkSyntax(pattern.string(), flags.string())) ? 0 : RegExpExpr; }
185185 ExpressionType createNewExpr(const JSTokenLocation&, ExpressionType, int, int, int, int) { return NewExpr; }
186186 ExpressionType createNewExpr(const JSTokenLocation&, ExpressionType, int, int) { return NewExpr; }

@@public:
403403
404404 bool isLocation(ExpressionType type)
405405 {
406  return type == ResolveExpr || type == DotExpr || type == BracketExpr;
 406 return type == ResolveExpr || type == DotExpr || type == PrivateDotExpr || type == BracketExpr;
 407 }
 408
 409 bool isPrivateLocation(ExpressionType type)
 410 {
 411 return type == PrivateDotExpr;
407412 }
408413
409414 bool isAssignmentLocation(ExpressionType type)

Source/JavaScriptCore/parser/VariableEnvironment.cpp

2929
3030namespace JSC {
3131
 32VariableEnvironment& VariableEnvironment::operator=(const VariableEnvironment& other)
 33{
 34 VariableEnvironment env(other);
 35 swap(env);
 36 return *this;
 37}
 38
3239void VariableEnvironment::markVariableAsCapturedIfDefined(const RefPtr<UniquedStringImpl>& identifier)
3340{
3441 auto findResult = m_map.find(identifier);

@@void VariableEnvironment::swap(VariableEnvironment& other)
8087{
8188 m_map.swap(other.m_map);
8289 m_isEverythingCaptured = other.m_isEverythingCaptured;
 90 m_rareData.swap(other.m_rareData);
8391}
8492
8593void VariableEnvironment::markVariableAsImported(const RefPtr<UniquedStringImpl>& identifier)

@@CompactVariableEnvironment::CompactVariableEnvironment(const VariableEnvironment
100108 : m_isEverythingCaptured(env.isEverythingCaptured())
101109{
102110 Vector<std::pair<UniquedStringImpl*, VariableEnvironmentEntry>, 32> sortedEntries;
103  sortedEntries.reserveInitialCapacity(env.size());
 111 sortedEntries.reserveInitialCapacity(env.mapSize());
104112 for (auto& pair : env)
105113 sortedEntries.append({ pair.key.get(), pair.value });
106114

Source/JavaScriptCore/parser/VariableEnvironment.h

2727
2828#include "Identifier.h"
2929#include <wtf/HashMap.h>
 30#include <wtf/HashSet.h>
 31#include <wtf/IteratorRange.h>
3032
3133namespace JSC {
3234

@@public:
4244 ALWAYS_INLINE bool isFunction() const { return m_bits & IsFunction; }
4345 ALWAYS_INLINE bool isParameter() const { return m_bits & IsParameter; }
4446 ALWAYS_INLINE bool isSloppyModeHoistingCandidate() const { return m_bits & IsSloppyModeHoistingCandidate; }
 47 ALWAYS_INLINE bool isPrivateName() const { return m_bits & IsPrivateName; }
4548
4649 ALWAYS_INLINE void setIsCaptured() { m_bits |= IsCaptured; }
4750 ALWAYS_INLINE void setIsConst() { m_bits |= IsConst; }

@@public:
5356 ALWAYS_INLINE void setIsFunction() { m_bits |= IsFunction; }
5457 ALWAYS_INLINE void setIsParameter() { m_bits |= IsParameter; }
5558 ALWAYS_INLINE void setIsSloppyModeHoistingCandidate() { m_bits |= IsSloppyModeHoistingCandidate; }
 59 ALWAYS_INLINE void setIsPrivateName() { m_bits |= IsPrivateName; }
5660
5761 ALWAYS_INLINE void clearIsVar() { m_bits &= ~IsVar; }
5862

@@private:
7478 IsImportedNamespace = 1 << 6,
7579 IsFunction = 1 << 7,
7680 IsParameter = 1 << 8,
77  IsSloppyModeHoistingCandidate = 1 << 9
 81 IsSloppyModeHoistingCandidate = 1 << 9,
 82 IsPrivateName = 1 << 10,
7883 };
7984 uint16_t m_bits { 0 };
8085};

@@struct VariableEnvironmentEntryHashTraits : HashTraits<VariableEnvironmentEntry>
8388 static constexpr bool needsDestruction = false;
8489};
8590
 91struct PrivateNameEntry {
 92public:
 93 PrivateNameEntry(uint16_t traits = 0) { m_bits = traits; }
 94
 95 ALWAYS_INLINE bool isUsed() const { return m_bits & IsUsed; }
 96 ALWAYS_INLINE bool isDeclared() const { return m_bits & IsDeclared; }
 97
 98 ALWAYS_INLINE void setIsUsed() { m_bits |= IsUsed; }
 99 ALWAYS_INLINE void setIsDeclared() { m_bits |= IsDeclared; }
 100
 101 uint16_t bits() const { return m_bits; }
 102
 103 bool operator==(const PrivateNameEntry& other) const
 104 {
 105 return m_bits == other.m_bits;
 106 }
 107
 108 enum Traits : uint16_t {
 109 IsUsed = 1 << 0,
 110 IsDeclared = 1 << 1,
 111 };
 112
 113private:
 114 uint16_t m_bits { 0 };
 115};
 116
 117struct PrivateNameEntryHashTraits : HashTraits<PrivateNameEntry> {
 118 static const bool needsDestruction = false;
 119};
 120
86121class VariableEnvironment {
87122private:
88123 typedef HashMap<PackedRefPtr<UniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> Map;
 124 typedef HashMap<PackedRefPtr<UniquedStringImpl>, PrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> PrivateNames;
89125public:
90  VariableEnvironment() = default;
91  VariableEnvironment(VariableEnvironment&& other) = default;
92  VariableEnvironment(const VariableEnvironment&) = default;
93  VariableEnvironment& operator=(const VariableEnvironment&) = default;
94  VariableEnvironment& operator=(VariableEnvironment&&) = default;
 126 VariableEnvironment() { }
 127 VariableEnvironment(VariableEnvironment&& other)
 128 : m_map(WTFMove(other.m_map))
 129 , m_isEverythingCaptured(other.m_isEverythingCaptured)
 130 , m_rareData(WTFMove(other.m_rareData))
 131 {
 132 }
 133 VariableEnvironment(const VariableEnvironment& other)
 134 : m_map(other.m_map)
 135 , m_isEverythingCaptured(other.m_isEverythingCaptured)
 136 , m_rareData(other.m_rareData ? WTF::makeUnique<VariableEnvironment::RareData>(*other.m_rareData) : nullptr)
 137 {
 138 }
 139 VariableEnvironment& operator=(const VariableEnvironment& other);
95140
96141 ALWAYS_INLINE Map::iterator begin() { return m_map.begin(); }
97142 ALWAYS_INLINE Map::iterator end() { return m_map.end(); }

@@public:
99144 ALWAYS_INLINE Map::const_iterator end() const { return m_map.end(); }
100145 ALWAYS_INLINE Map::AddResult add(const RefPtr<UniquedStringImpl>& identifier) { return m_map.add(identifier, VariableEnvironmentEntry()); }
101146 ALWAYS_INLINE Map::AddResult add(const Identifier& identifier) { return add(identifier.impl()); }
102  ALWAYS_INLINE unsigned size() const { return m_map.size(); }
 147 ALWAYS_INLINE unsigned size() const { return m_map.size() + privateNamesSize(); }
 148 ALWAYS_INLINE unsigned mapSize() const { return m_map.size(); }
103149 ALWAYS_INLINE bool contains(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.contains(identifier); }
104150 ALWAYS_INLINE bool remove(const RefPtr<UniquedStringImpl>& identifier) { return m_map.remove(identifier); }
105151 ALWAYS_INLINE Map::iterator find(const RefPtr<UniquedStringImpl>& identifier) { return m_map.find(identifier); }

@@public:
116162 bool isEverythingCaptured() const { return m_isEverythingCaptured; }
117163 bool isEmpty() const { return !m_map.size(); }
118164
 165 using PrivateNamesRange = WTF::IteratorRange<PrivateNames::iterator>;
 166
 167 ALWAYS_INLINE Map::AddResult declarePrivateName(const Identifier& identifier) { return declarePrivateName(identifier.impl()); }
 168 ALWAYS_INLINE void usePrivateName(const Identifier& identifier) { usePrivateName(identifier.impl()); }
 169
 170 Map::AddResult declarePrivateName(const RefPtr<UniquedStringImpl>& identifier)
 171 {
 172 auto& meta = getOrAddPrivateName(identifier.get());
 173 meta.setIsDeclared();
 174 auto entry = VariableEnvironmentEntry();
 175 entry.setIsPrivateName();
 176 entry.setIsConst();
 177 entry.setIsCaptured();
 178 return m_map.add(identifier, entry);
 179 }
 180 void usePrivateName(const RefPtr<UniquedStringImpl>& identifier)
 181 {
 182 auto& meta = getOrAddPrivateName(identifier.get());
 183 meta.setIsUsed();
 184 if (meta.isDeclared())
 185 find(identifier)->value.setIsCaptured();
 186 }
 187
 188 ALWAYS_INLINE PrivateNamesRange privateNames() const
 189 {
 190 // Use of the IteratorRange must be guarded to prevent ASSERT failures in checkValidity().
 191 ASSERT(privateNamesSize() > 0);
 192 return makeIteratorRange(m_rareData->m_privateNames.begin(), m_rareData->m_privateNames.end());
 193 }
 194
 195 ALWAYS_INLINE unsigned privateNamesSize() const
 196 {
 197 if (!m_rareData)
 198 return 0;
 199 return m_rareData->m_privateNames.size();
 200 }
 201
 202 ALWAYS_INLINE bool hasPrivateName(const Identifier& identifier)
 203 {
 204 if (!m_rareData)
 205 return false;
 206 return m_rareData->m_privateNames.contains(identifier.impl());
 207 }
 208
 209 ALWAYS_INLINE void copyPrivateNamesTo(VariableEnvironment& other) const
 210 {
 211 if (!m_rareData)
 212 return;
 213 if (!other.m_rareData)
 214 other.m_rareData = WTF::makeUnique<VariableEnvironment::RareData>();
 215 if (privateNamesSize() > 0) {
 216 for (auto entry : privateNames()) {
 217 if (!(entry.value.isUsed() && entry.value.isDeclared()))
 218 other.m_rareData->m_privateNames.add(entry.key, entry.value);
 219 }
 220 }
 221 }
 222
 223 ALWAYS_INLINE void copyUndeclaredPrivateNamesTo(VariableEnvironment& outer) const {
 224 // Used by the Parser to transfer recorded uses of PrivateNames from an
 225 // inner PrivateNameEnvironment into an outer one, in case a PNE is used
 226 // earlier in the source code than it is defined.
 227 if (privateNamesSize() > 0) {
 228 for (auto entry : privateNames()) {
 229 if (entry.value.isUsed() && !entry.value.isDeclared())
 230 outer.getOrAddPrivateName(entry.key.get()).setIsUsed();
 231 }
 232 }
 233 }
 234
 235 struct RareData {
 236 WTF_MAKE_STRUCT_FAST_ALLOCATED;
 237
 238 RareData() { }
 239 RareData(RareData&& other)
 240 : m_privateNames(WTFMove(other.m_privateNames))
 241 {
 242 }
 243 RareData(const RareData&) = default;
 244 RareData& operator=(const RareData&) = default;
 245 PrivateNames m_privateNames;
 246 };
 247
119248private:
120249 friend class CachedVariableEnvironment;
121250
122251 Map m_map;
123252 bool m_isEverythingCaptured { false };
 253
 254 PrivateNameEntry& getOrAddPrivateName(UniquedStringImpl* impl)
 255 {
 256 if (!m_rareData)
 257 m_rareData = WTF::makeUnique<VariableEnvironment::RareData>();
 258
 259 return m_rareData->m_privateNames.add(impl, PrivateNameEntry()).iterator->value;
 260 }
 261
 262 std::unique_ptr<VariableEnvironment::RareData> m_rareData;
124263};
125264
126265class CompactVariableEnvironment {

Source/JavaScriptCore/runtime/CachedTypes.cpp

@@public:
856856 else
857857 encode(encoder, { *source });
858858 }
 859
 860 SourceType<T>* decodeAsPtr(Decoder& decoder) const
 861 {
 862 RELEASE_ASSERT(!this->isEmpty());
 863 return this->template buffer<T>()->decode(decoder);
 864 }
859865};
860866
861867class CachedSimpleJumpTable : public CachedObject<UnlinkedSimpleJumpTable> {

@@private:
10031009 unsigned m_needsClassFieldInitializer : 1;
10041010};
10051011
 1012class CachedVariableEnvironmentRareData : public CachedObject<VariableEnvironment::RareData> {
 1013public:
 1014 void encode(Encoder& encoder, const VariableEnvironment::RareData& rareData)
 1015 {
 1016 m_privateNames.encode(encoder, rareData.m_privateNames);
 1017 }
 1018
 1019 void decode(Decoder& decoder, VariableEnvironment::RareData& rareData) const
 1020 {
 1021 m_privateNames.decode(decoder, rareData.m_privateNames);
 1022 }
 1023
 1024private:
 1025 CachedHashMap<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>, PrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> m_privateNames;
 1026};
 1027
10061028class CachedVariableEnvironment : public CachedObject<VariableEnvironment> {
10071029public:
10081030 void encode(Encoder& encoder, const VariableEnvironment& env)
10091031 {
10101032 m_isEverythingCaptured = env.m_isEverythingCaptured;
10111033 m_map.encode(encoder, env.m_map);
 1034 m_rareData.encode(encoder, env.m_rareData.get());
10121035 }
10131036
10141037 void decode(Decoder& decoder, VariableEnvironment& env) const
10151038 {
10161039 env.m_isEverythingCaptured = m_isEverythingCaptured;
10171040 m_map.decode(decoder, env.m_map);
 1041 if (!m_rareData.isEmpty()) {
 1042 env.m_rareData = WTF::makeUnique<VariableEnvironment::RareData>();
 1043 m_rareData->decode(decoder, *env.m_rareData);
 1044 }
10181045 }
10191046
10201047private:
10211048 bool m_isEverythingCaptured;
10221049 CachedHashMap<CachedRefPtr<CachedUniquedStringImpl, UniquedStringImpl, WTF::PackedPtrTraits<UniquedStringImpl>>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> m_map;
 1050 CachedPtr<CachedVariableEnvironmentRareData> m_rareData;
10231051};
10241052
10251053class CachedCompactVariableEnvironment : public CachedObject<CompactVariableEnvironment> {

@@private:
11471175 intptr_t m_bits;
11481176};
11491177
 1178class CachedSymbolTableRareData : public CachedObject<SymbolTable::SymbolTableRareData> {
 1179public:
 1180 void encode(Encoder& encoder, const SymbolTable::SymbolTableRareData& rareData)
 1181 {
 1182 m_privateNames.encode(encoder, rareData.m_privateNames);
 1183 }
 1184
 1185 void decode(Decoder& decoder, SymbolTable::SymbolTableRareData& rareData) const
 1186 {
 1187 m_privateNames.decode(decoder, rareData.m_privateNames);
 1188 }
 1189
 1190private:
 1191 CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, IdentifierRepHash> m_privateNames;
 1192};
 1193
11501194class CachedSymbolTable : public CachedObject<SymbolTable> {
11511195public:
11521196 void encode(Encoder& encoder, const SymbolTable& symbolTable)

@@public:
11571201 m_nestedLexicalScope = symbolTable.m_nestedLexicalScope;
11581202 m_scopeType = symbolTable.m_scopeType;
11591203 m_arguments.encode(encoder, symbolTable.m_arguments.get());
 1204 m_rareData.encode(encoder, symbolTable.m_rareData.get());
11601205 }
11611206
11621207 SymbolTable* decode(Decoder& decoder) const

@@public:
11701215 ScopedArgumentsTable* scopedArgumentsTable = m_arguments.decode(decoder);
11711216 if (scopedArgumentsTable)
11721217 symbolTable->m_arguments.set(decoder.vm(), symbolTable, scopedArgumentsTable);
 1218 if (!m_rareData.isEmpty()) {
 1219 symbolTable->m_rareData = WTF::makeUnique<SymbolTable::SymbolTableRareData>();
 1220 m_rareData->decode(decoder, *symbolTable->m_rareData);
 1221 }
 1222
11731223 return symbolTable;
11741224 }
11751225

@@private:
11801230 unsigned m_nestedLexicalScope : 1;
11811231 unsigned m_scopeType : 3;
11821232 CachedPtr<CachedScopedArgumentsTable> m_arguments;
 1233 CachedPtr<CachedSymbolTableRareData> m_rareData;
11831234};
11841235
11851236class CachedJSValue;

Source/JavaScriptCore/runtime/CodeCache.cpp

@@UnlinkedCodeBlockType* generateUnlinkedCodeBlockImpl(VM& vm, const SourceCode& s
7676 typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
7777 bool isInsideOrdinaryFunction = executable && executable->isInsideOrdinaryFunction();
7878 std::unique_ptr<RootNode> rootNode = parse<RootNode>(
79  vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, strictMode, scriptMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType, nullptr, nullptr, isInsideOrdinaryFunction);
 79 vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, strictMode, scriptMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType, nullptr, variablesUnderTDZ, nullptr, isInsideOrdinaryFunction);
8080 if (!rootNode)
8181 return nullptr;
8282

Source/JavaScriptCore/runtime/CommonIdentifiers.cpp

@@namespace JSC {
3030#define INITIALIZE_KEYWORD(name) , name##Keyword(Identifier::fromString(vm, #name))
3131#define INITIALIZE_PRIVATE_NAME(name) , name##PrivateName(m_builtinNames->name##PrivateName())
3232#define INITIALIZE_SYMBOL(name) , name##Symbol(m_builtinNames->name##Symbol())
 33#define INITIALIZE_PRIVATE_FIELD_NAME(name) , name##PrivateField(Identifier::fromString(vm, "#" #name))
3334
3435CommonIdentifiers::CommonIdentifiers(VM& vm)
3536 : nullIdentifier()

@@CommonIdentifiers::CommonIdentifiers(VM& vm)
4344 JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD)
4445 JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
4546 JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(INITIALIZE_SYMBOL)
 47 JSC_COMMON_IDENTIFIERS_EACH_PRIVATE_FIELD(INITIALIZE_PRIVATE_FIELD_NAME)
4648{
4749}
4850

Source/JavaScriptCore/runtime/CommonIdentifiers.h

209209 macro(writable) \
210210 macro(year)
211211
 212#define JSC_COMMON_IDENTIFIERS_EACH_PRIVATE_FIELD(macro) \
 213 macro(constructor)
 214
212215#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
213216 macro(await) \
214217 macro(break) \

@@namespace JSC {
323326 JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL)
324327#undef JSC_IDENTIFIER_DECLARE_PRIVATE_WELL_KNOWN_SYMBOL_GLOBAL
325328
 329#define JSC_IDENTIFIER_DECLARE_PRIVATE_FIELD_GLOBAL(name) const Identifier name##PrivateField;
 330 JSC_COMMON_IDENTIFIERS_EACH_PRIVATE_FIELD(JSC_IDENTIFIER_DECLARE_PRIVATE_FIELD_GLOBAL)
 331#undef JSC_IDENTIFIER_DECLARE_PRIVATE_FIELD_GLOBAL
 332
326333 // Callers of this method should make sure that identifiers given to this method
327334 // survive the lifetime of CommonIdentifiers and related VM.
328335 JS_EXPORT_PRIVATE void appendExternalName(const Identifier& publicName, const Identifier& privateName);

Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

@@SLOW_PATH_DECL(slow_path_get_by_val_with_this)
13331333 RETURN_PROFILED(baseValue.get(globalObject, property, slot));
13341334}
13351335
 1336SLOW_PATH_DECL(slow_path_get_private_name)
 1337{
 1338 BEGIN();
 1339
 1340 auto bytecode = pc->as<OpGetPrivateName>();
 1341 JSValue baseValue = GET_C(bytecode.m_base).jsValue();
 1342 JSValue subscript = GET_C(bytecode.m_property).jsValue();
 1343 ASSERT(subscript.isSymbol());
 1344
 1345 baseValue.requireObjectCoercible(globalObject);
 1346 CHECK_EXCEPTION();
 1347 auto property = subscript.toPropertyKey(globalObject);
 1348 CHECK_EXCEPTION();
 1349 ASSERT(property.isPrivateName());
 1350
 1351 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::GetOwnProperty);
 1352 asObject(baseValue)->getPrivateField(globalObject, property, slot);
 1353 CHECK_EXCEPTION();
 1354
 1355 RETURN_PROFILED(slot.getValue(globalObject, property));
 1356}
 1357
13361358SLOW_PATH_DECL(slow_path_put_by_id_with_this)
13371359{
13381360 BEGIN();

Source/JavaScriptCore/runtime/CommonSlowPaths.h

@@SLOW_PATH_HIDDEN_DECL(slow_path_create_async_generator);
275275SLOW_PATH_HIDDEN_DECL(slow_path_create_rest);
276276SLOW_PATH_HIDDEN_DECL(slow_path_get_by_id_with_this);
277277SLOW_PATH_HIDDEN_DECL(slow_path_get_by_val_with_this);
 278SLOW_PATH_HIDDEN_DECL(slow_path_get_private_name);
278279SLOW_PATH_HIDDEN_DECL(slow_path_put_by_id_with_this);
279280SLOW_PATH_HIDDEN_DECL(slow_path_put_by_val_with_this);
280281SLOW_PATH_HIDDEN_DECL(slow_path_define_data_property);

Source/JavaScriptCore/runtime/ExceptionHelpers.cpp

@@JSObject* createTDZError(JSGlobalObject* globalObject)
324324 return createReferenceError(globalObject, "Cannot access uninitialized variable.");
325325}
326326
 327JSObject* createInvalidPrivateNameError(JSGlobalObject* globalObject)
 328{
 329 return createTypeError(globalObject, makeString("Cannot access invalid private field"), defaultSourceAppender, TypeNothing);
 330}
 331
 332JSObject* createRedefinedPrivateNameError(JSGlobalObject* globalObject)
 333{
 334 return createTypeError(globalObject, makeString("Cannot redefine existing private field"), defaultSourceAppender, TypeNothing);
 335}
 336
327337Exception* throwOutOfMemoryError(JSGlobalObject* globalObject, ThrowScope& scope)
328338{
329339 return throwException(globalObject, scope, createOutOfMemoryError(globalObject));

Source/JavaScriptCore/runtime/ExceptionHelpers.h

@@JSObject* createInvalidInstanceofParameterErrorHasInstanceValueNotFunction(JSGlo
5353JSObject* createNotAConstructorError(JSGlobalObject*, JSValue);
5454JSObject* createNotAFunctionError(JSGlobalObject*, JSValue);
5555JSObject* createErrorForInvalidGlobalAssignment(JSGlobalObject*, const String&);
 56JSObject* createInvalidPrivateNameError(JSGlobalObject*);
 57JSObject* createRedefinedPrivateNameError(JSGlobalObject*);
5658String errorDescriptionForValue(JSGlobalObject*, JSValue);
5759
5860JS_EXPORT_PRIVATE Exception* throwOutOfMemoryError(JSGlobalObject*, ThrowScope&);

Source/JavaScriptCore/runtime/JSGlobalObject.cpp

@@static EncodedJSValue JSC_HOST_CALL hasOwnLengthProperty(JSGlobalObject* globalO
294294 RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(target->hasOwnProperty(globalObject, vm.propertyNames->length))));
295295}
296296
 297// FIXME: use a bytecode or intrinsic for creating a private symbol.
 298// https://bugs.webkit.org/show_bug.cgi?id=212782
 299static EncodedJSValue JSC_HOST_CALL createPrivateSymbol(JSGlobalObject* globalObject, CallFrame*)
 300{
 301 VM& vm = globalObject->vm();
 302 return JSValue::encode(Symbol::create(vm, PrivateSymbolImpl::createNullSymbol().get()));
 303}
 304
297305#if ASSERT_ENABLED
298306static EncodedJSValue JSC_HOST_CALL assertCall(JSGlobalObject* globalObject, CallFrame* callFrame)
299307{

@@capitalName ## Constructor* lowerName ## Constructor = featureFlag ? capitalName
12251233 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), globalFuncDateTimeFormat));
12261234 });
12271235
 1236 // PrivateSymbols / PrivateNames
 1237 m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::createPrivateSymbol)].initLater([] (const Initializer<JSCell>& init) {
 1238 init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 0, String(), createPrivateSymbol));
 1239 });
 1240
12281241#if ENABLE(WEBASSEMBLY) && ENABLE(WEBASSEMBLY_STREAMING_API)
12291242 // WebAssembly Streaming API
12301243 m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::webAssemblyCompileStreamingInternal)].initLater([] (const Initializer<JSCell>& init) {

Source/JavaScriptCore/runtime/JSObject.h

@@public:
180180 // being returned. Once this is fixed we should migrate code & remove this method.
181181 JS_EXPORT_PRIVATE bool getOwnPropertyDescriptor(JSGlobalObject*, PropertyName, PropertyDescriptor&);
182182
 183 static bool getPrivateFieldSlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
 184 inline bool getPrivateField(JSGlobalObject*, PropertyName, PropertySlot&);
 185 inline void putPrivateField(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
 186 inline void definePrivateField(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
 187
183188 unsigned getArrayLength() const
184189 {
185190 if (!hasIndexedProperties(indexingType()))

Source/JavaScriptCore/runtime/JSObjectInlines.h

@@inline JSValue JSObject::get(JSGlobalObject* globalObject, uint64_t propertyName
569569 return get(globalObject, Identifier::from(globalObject->vm(), propertyName));
570570}
571571
 572JSObject* createInvalidPrivateNameError(JSGlobalObject*);
 573JSObject* createRedefinedPrivateNameError(JSGlobalObject*);
 574
 575ALWAYS_INLINE bool JSObject::getPrivateFieldSlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
 576{
 577 ASSERT(propertyName.isPrivateName());
 578 VM& vm = getVM(globalObject);
 579 Structure* structure = object->structure(vm);
 580
 581 unsigned attributes;
 582 PropertyOffset offset = structure->get(vm, propertyName, attributes);
 583 if (offset == invalidOffset)
 584 return false;
 585
 586 JSValue value = object->getDirect(offset);
 587 ASSERT(value);
 588 if (value.isCell()) {
 589 JSCell* cell = value.asCell();
 590 JSType type = cell->type();
 591 UNUSED_PARAM(cell);
 592 ASSERT_UNUSED(type, type != GetterSetterType && type != CustomGetterSetterType);
 593 // FIXME: For now, private fields do not support getter/setter fields. Later on, we will need to fill in accessor metadata here,
 594 // as in JSObject::getOwnNonIndexPropertySlot()
 595 // https://bugs.webkit.org/show_bug.cgi?id=194435
 596 }
 597
 598 slot.setValue(object, attributes, value, offset);
 599 return true;
 600}
 601
 602inline bool JSObject::getPrivateField(JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
 603{
 604 VM& vm = getVM(globalObject);
 605 auto scope = DECLARE_THROW_SCOPE(vm);
 606 if (!JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) {
 607 throwException(globalObject, scope, createInvalidPrivateNameError(globalObject));
 608 RELEASE_AND_RETURN(scope, false);
 609 }
 610 EXCEPTION_ASSERT(!scope.exception());
 611 RELEASE_AND_RETURN(scope, true);
 612}
 613
 614inline void JSObject::putPrivateField(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& putSlot)
 615{
 616 VM& vm = getVM(globalObject);
 617 auto scope = DECLARE_THROW_SCOPE(vm);
 618 PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty);
 619 if (!JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) {
 620 throwException(globalObject, scope, createInvalidPrivateNameError(globalObject));
 621 RELEASE_AND_RETURN(scope, void());
 622 }
 623 EXCEPTION_ASSERT(!scope.exception());
 624
 625 scope.release();
 626 putDirect(vm, propertyName, value, putSlot);
 627}
 628
 629inline void JSObject::definePrivateField(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& putSlot)
 630{
 631 VM& vm = getVM(globalObject);
 632 auto scope = DECLARE_THROW_SCOPE(vm);
 633 PropertySlot slot(this, PropertySlot::InternalMethodType::HasProperty);
 634 if (JSObject::getPrivateFieldSlot(this, globalObject, propertyName, slot)) {
 635 throwException(globalObject, scope, createRedefinedPrivateNameError(globalObject));
 636 RELEASE_AND_RETURN(scope, void());
 637 }
 638 EXCEPTION_ASSERT(!scope.exception());
 639
 640 scope.release();
 641 putDirect(vm, propertyName, value, putSlot);
 642}
 643
572644} // namespace JSC

Source/JavaScriptCore/runtime/JSScope.cpp

@@void JSScope::collectClosureVariablesUnderTDZ(JSScope* scope, VariableEnvironmen
337337 ConcurrentJSLocker locker(symbolTable->m_lock);
338338 for (auto end = symbolTable->end(locker), iter = symbolTable->begin(locker); iter != end; ++iter)
339339 result.add(iter->key);
 340 if (symbolTable->hasPrivateNames()) {
 341 for (auto name : symbolTable->privateNames())
 342 result.usePrivateName(name);
 343 }
340344 }
341345}
342346

Source/JavaScriptCore/runtime/OptionsList.h

@@constexpr bool enableWebAssemblyStreamingApi = false;
510510 v(Bool, usePublicClassFields, true, Normal, "If true, the parser will understand public data fields inside classes.") \
511511 v(Bool, useRandomizingExecutableIslandAllocation, false, Normal, "For the arm64 ExecutableAllocator, if true, select which region to use randomly. This is useful for testing that jump islands work.") \
512512 v(Bool, exposeProfilersOnGlobalObject, false, Normal, "If true, we will expose functions to enable/disable both the sampling profiler and the super sampler") \
 513 v(Bool, usePrivateClassFields, false, Normal, "If true, the parser will understand private data fields inside classes.") \
513514
514515enum OptionEquivalence {
515516 SameOption,

Source/JavaScriptCore/runtime/SymbolTable.cpp

@@SymbolTable* SymbolTable::cloneScopePart(VM& vm)
181181 for (; iter != end; ++iter)
182182 result->m_rareData->m_uniqueTypeSetMap.set(iter->key, iter->value);
183183 }
 184
 185 {
 186 for (auto name : m_rareData->m_privateNames)
 187 result->m_rareData->m_privateNames.add(name);
 188 }
184189 }
185190
186191 return result;

Source/JavaScriptCore/runtime/SymbolTable.h

3838#include "Watchpoint.h"
3939#include <memory>
4040#include <wtf/HashTraits.h>
41 #include <wtf/text/UniquedStringImpl.h>
 41#include <wtf/text/SymbolImpl.h>
4242
4343namespace JSC {
4444

@@public:
450450 typedef HashMap<RefPtr<UniquedStringImpl>, RefPtr<TypeSet>, IdentifierRepHash> UniqueTypeSetMap;
451451 typedef HashMap<VarOffset, RefPtr<UniquedStringImpl>> OffsetToVariableMap;
452452 typedef Vector<SymbolTableEntry*> LocalToEntryVec;
 453 typedef HashSet<RefPtr<UniquedStringImpl>, IdentifierRepHash> PrivateNameSet;
 454 typedef WTF::IteratorRange<typename PrivateNameSet::iterator> PrivateNameIteratorRange;
453455
454456 template<typename CellType, SubspaceAccess>
455457 static IsoSubspace* subspaceFor(VM& vm)

@@public:
594596 ConcurrentJSLocker locker(m_lock);
595597 add(locker, key, std::forward<Entry>(entry));
596598 }
597 
 599
 600 bool hasPrivateNames() const { return m_rareData && m_rareData->m_privateNames.size(); }
 601 ALWAYS_INLINE PrivateNameIteratorRange privateNames()
 602 {
 603 // Use of the IteratorRange must be guarded to prevent ASSERT failures in checkValidity().
 604 ASSERT(hasPrivateNames());
 605 return makeIteratorRange(m_rareData->m_privateNames.begin(), m_rareData->m_privateNames.end());
 606 }
 607
 608 void addPrivateName(UniquedStringImpl* key)
 609 {
 610 ASSERT(key && !key->isSymbol());
 611 if (!m_rareData)
 612 m_rareData = WTF::makeUnique<SymbolTableRareData>();
 613
 614 ASSERT(!m_rareData->m_privateNames.contains(key));
 615 m_rareData->m_privateNames.add(key);
 616 }
 617
598618 template<typename Entry>
599619 void set(const ConcurrentJSLocker&, UniquedStringImpl* key, Entry&& entry)
600620 {

@@private:
729749 ScopeOffset m_maxScopeOffset;
730750public:
731751 mutable ConcurrentJSLock m_lock;
732 private:
733  unsigned m_usesNonStrictEval : 1;
734  unsigned m_nestedLexicalScope : 1; // Non-function LexicalScope.
735  unsigned m_scopeType : 3; // ScopeType
736 
 752
737753 struct SymbolTableRareData {
738754 WTF_MAKE_STRUCT_FAST_ALLOCATED;
739755 UniqueIDMap m_uniqueIDMap;
740756 OffsetToVariableMap m_offsetToVariableMap;
741757 UniqueTypeSetMap m_uniqueTypeSetMap;
742758 WriteBarrier<CodeBlock> m_codeBlock;
 759 PrivateNameSet m_privateNames;
743760 };
 761
 762private:
 763 unsigned m_usesNonStrictEval : 1;
 764 unsigned m_nestedLexicalScope : 1; // Non-function LexicalScope.
 765 unsigned m_scopeType : 3; // ScopeType
 766
744767 std::unique_ptr<SymbolTableRareData> m_rareData;
745768
746769 WriteBarrier<ScopedArgumentsTable> m_arguments;

JSTests/ChangeLog

 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 Expands upon the earlier public fields patch, adding a number of private
 9 field tests.
 10
 11 * stress/class-fields-private-as-function.js: Added.
 12 * stress/class-fields-private-cached-bytecode.js: Added.
 13 * stress/class-fields-private-freeze-out-of-line.js: Added.
 14 * stress/class-fields-private-freeze.js: Added.
 15 * stress/class-fields-private-on-proxy.js: Added.
 16 * stress/class-fields-private-out-of-line.js: Added.
 17 * stress/class-fields-private-prevent-extensions-out-of-line.js: Added.
 18 * stress/class-fields-private-prevent-extensions.js: Added.
 19 * stress/class-fields-private-seal-out-of-line.js: Added.
 20 * stress/class-fields-private-seal.js: Added.
 21 * stress/class-fields-private-use-eval.js: Added.
 22 * stress/class-fields-stress-instance.js:
 23 * stress/optional-chaining-and-private-fields.js: Added.
 24 * stress/private-name-access-in-computed-property.js: Added.
 25 * stress/put-by-val-direct-addprivate.js: Added.
 26 * stress/put-by-val-direct-putprivate.js: Added.
 27 * test262/config.yaml:
 28
1292020-06-04 Alexey Shvayka <shvaikalesh@gmail.com>
230
331 Update test262 to commit 290ceba31fea

JSTests/stress/class-fields-private-as-function.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3function assert(a, e) {
 4 if (a !== e)
 5 throw new Error("Expected: " + e + " but got: " + a);
 6}
 7
 8class C {
 9 #m = () => 25;
 10
 11 method() {
 12 return this.#m();
 13 }
 14}
 15
 16let c = new C();
 17assert(c.method(), 25);
 18

JSTests/stress/class-fields-private-cached-bytecode.js

 1//@ runBytecodeCache("--usePrivateClassFields=true")
 2
 3function assert(a, e) {
 4 if (a !== e)
 5 throw new Error("Expected: " + e + " but got: " + a);
 6}
 7
 8class C {
 9 #f = 3;
 10
 11 method() {
 12 return this.#f;
 13 }
 14}
 15
 16let c = new C();
 17assert(c.method(), 3);
 18

JSTests/stress/class-fields-private-freeze-out-of-line.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3let assert = Object.assign(
 4 function assert(expr, message = "") {
 5 if (expr == false)
 6 throw new Error(`Expected ${message || "expr"} to be true, but was ${expr}`);
 7 }, {
 8 equals(a, b) {
 9 if (a === b || (a === a && b === b) || (a !== a && b !== b))
 10 return;
 11
 12 throw new Error(`Expected ${a} to be ${b}`);
 13 }
 14});
 15
 16// The base class is declared in eval specifically so that it can add enough
 17// properties to the class to store private fields in out-of-line property storage.
 18let Base = eval(`(class Base {
 19 // Methods
 20 constructor() {
 21 // Define properties
 22 ${Array(200).map((_, i) => ` this.x${i} = ${i};\n`).join("")}
 23 }
 24})`);
 25
 26class PrivateFieldAfterPreventExtensions extends Base {
 27 #i = (Object.freeze(this), 42);
 28 #assert = (assert(Object.isFrozen(this), "Object.isFrozen(this)"), this.#i + 1);
 29
 30 get() { return this.#i; }
 31 set(i) { this.#i = i; }
 32}
 33
 34function test(i) {
 35 let c = new PrivateFieldAfterPreventExtensions;
 36 assert.equals(c.x150 === 150);
 37 c.x150 = 0.1;
 38 assert.equals(c.get(), 42);
 39 c.set(i);
 40 assert.equals(c.get(), i);
 41}
 42noInline(test);
 43
 44test(0);
 45test(1);
 46test(2);
 47for (var i = 0; i < 200; ++i)
 48 test(i);

JSTests/stress/class-fields-private-freeze.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3let assert = Object.assign(
 4 function assert(expr, message = "") {
 5 if (expr == false)
 6 throw new Error(`Expected ${message || "expr"} to be true, but was ${expr}`);
 7 }, {
 8 equals(a, b) {
 9 if (a === b || (a === a && b === b) || (a !== a && b !== b))
 10 return;
 11
 12 throw new Error(`Expected ${a} to be ${b}`);
 13 }
 14});
 15
 16class Base {
 17 constructor() {
 18 this.x = 1;
 19 }
 20}
 21
 22class PrivateFieldAfterPreventExtensions extends Base {
 23 #i = (Object.freeze(this), 42);
 24 #assert = (assert(Object.isFrozen(this), "Object.isFrozen(this)"), this.#i + 1);
 25
 26 get() { return this.#i; }
 27 set(i) { this.#i = i; }
 28}
 29
 30function test(i) {
 31 let c = new PrivateFieldAfterPreventExtensions;
 32 c.x = 0.1;
 33 assert.equals(c.get(), 42);
 34 c.set(i);
 35 assert.equals(c.get(), i);
 36}
 37noInline(test);
 38
 39test(0);
 40test(1);
 41test(2);
 42for (var i = 0; i < 200; ++i)
 43 test(i);

JSTests/stress/class-fields-private-on-proxy.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3function assert(a, e, m) {
 4 if (a !== e)
 5 throw new Error(m);
 6}
 7
 8function assertArrayContent(a, e) {
 9 assert(a.length, e.length, "Size of arrays doesn't match");
 10 for (var i = 0; i < a.length; i++)
 11 assert(a[i], e[i], "a[" + i + "] = " + a[i] + " but e[" + i + "] = " + e[i]);
 12}
 13
 14let arr = [];
 15
 16class ProxyBase {
 17 constructor() {
 18 return new Proxy(this, {
 19 get: function (obj, prop) {
 20 arr.push(prop);
 21 return obj[prop];
 22 }
 23 });
 24 }
 25}
 26
 27class Test extends ProxyBase {
 28 #f = 3;
 29 method() {
 30 return this.#f;
 31 }
 32}
 33
 34let t = new Test();
 35let r = t.method();
 36assert(r, 3, "Expected: 3 but got: " + r);
 37
 38assertArrayContent(arr, ['method']);
 39

JSTests/stress/class-fields-private-out-of-line.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3function assert(a, e) {
 4 if (a !== e)
 5 throw new Error("Expected: " + e + " but got: " + a);
 6}
 7
 8let klassSource = `
 9var C = class {
 10 assertOutOfLineValue() {
 11 assert(this.#f200, "foo");
 12 }
 13`;
 14
 15
 16for (let i = 0; i < 200; i++) {
 17 klassSource += " #f" + i + ";\n";
 18}
 19
 20klassSource += " #f200 = \"foo\";\n}";
 21
 22eval(klassSource);
 23
 24for (let i = 0; i < 2; i++) {
 25 let c = new C();
 26 c.assertOutOfLineValue();
 27}
 28

JSTests/stress/class-fields-private-prevent-extensions-out-of-line.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3let assert = Object.assign(
 4 function assert(expr, message = "") {
 5 if (expr == false)
 6 throw new Error(`Expected ${message || "expr"} to be true, but was ${expr}`);
 7 }, {
 8 false(expr, message = "") {
 9 if (expr == true)
 10 throw new Error(`Expected ${message || "expr"} to be false, but was ${expr}`)
 11 },
 12 equals(a, b) {
 13 if (a === b || (a === a && b === b) || (a !== a && b !== b))
 14 return;
 15
 16 throw new Error(`Expected ${a} to be ${b}`);
 17 }
 18});
 19
 20// The base class is declared in eval specifically so that it can add enough
 21// properties to the class to store private fields in out-of-line property storage.
 22let Base = eval(`(class Base {
 23 // Methods
 24 constructor() {
 25 // Define properties
 26 ${Array(200).map((_, i) => ` this.x${i} = ${i};\n`).join("")}
 27 }
 28})`);
 29
 30class PrivateFieldAfterPreventExtensions extends Base {
 31 #i = (Object.preventExtensions(this), 42);
 32 #assert = (assert.false(Object.isExtensible(this), "Object.isExtensible(this)"), this.#i + 1);
 33
 34 get() { return this.#i; }
 35 set(i) { this.#i = i; }
 36}
 37
 38function test(i) {
 39 let c = new PrivateFieldAfterPreventExtensions;
 40 assert.equals(c.x150 === 150);
 41 c.x150 = 0.1;
 42 assert.equals(c.get(), 42);
 43 c.set(i);
 44 assert.equals(c.get(), i);
 45}
 46noInline(test);
 47
 48test(0);
 49test(1);
 50test(2);
 51for (var i = 0; i < 200; ++i)
 52 test(i);

JSTests/stress/class-fields-private-prevent-extensions.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3let assert = Object.assign(
 4 function assert(expr, message = "") {
 5 if (expr == false)
 6 throw new Error(`Expected ${message || "expr"} to be true, but was ${expr}`);
 7 }, {
 8 false(expr, message = "") {
 9 if (expr == true)
 10 throw new Error(`Expected ${message || "expr"} to be false, but was ${expr}`)
 11 },
 12 equals(a, b) {
 13 if (a === b || (a === a && b === b) || (a !== a && b !== b))
 14 return;
 15
 16 throw new Error(`Expected ${a} to be ${b}`);
 17 }
 18});
 19
 20class Base {
 21 constructor() {
 22 this.x = 1;
 23 }
 24}
 25
 26class PrivateFieldAfterPreventExtensions extends Base {
 27 #i = (Object.preventExtensions(this), 42);
 28 #assert = (assert.false(Object.isExtensible(this), "Object.isExtensible(this)"), this.#i + 1);
 29
 30 get() { return this.#i; }
 31 set(i) { this.#i = i; }
 32}
 33
 34function test(i) {
 35 let c = new PrivateFieldAfterPreventExtensions;
 36 c.x = 0.1;
 37 assert.equals(c.get(), 42);
 38 c.set(i);
 39 assert.equals(c.get(), i);
 40}
 41noInline(test);
 42
 43test(0);
 44test(1);
 45test(2);
 46for (var i = 0; i < 200; ++i)
 47 test(i);

JSTests/stress/class-fields-private-seal-out-of-line.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3let assert = Object.assign(
 4 function assert(expr, message = "") {
 5 if (expr == false)
 6 throw new Error(`Expected ${message || "expr"} to be true, but was ${expr}`);
 7 }, {
 8 false(expr, message = "") {
 9 if (expr == true)
 10 throw new Error(`Expected ${message || "expr"} to be false, but was ${expr}`)
 11 },
 12 equals(a, b) {
 13 if (a === b || (a === a && b === b) || (a !== a && b !== b))
 14 return;
 15
 16 throw new Error(`Expected ${a} to be ${b}`);
 17 }
 18});
 19
 20// The base class is declared in eval specifically so that it can add enough
 21// properties to the class to store private fields in out-of-line property storage.
 22let Base = eval(`(class Base {
 23 // Methods
 24 constructor() {
 25 // Define properties
 26 ${Array(200).map((_, i) => ` this.x${i} = ${i};\n`).join("")}
 27 }
 28})`);
 29
 30class PrivateFieldAfterPreventExtensions extends Base {
 31 #i = (Object.seal(this), 42);
 32 #assert = (assert(Object.isSealed(this), "Object.isSealed(this)"), this.#i + 1);
 33
 34 get() { return this.#i; }
 35 set(i) { this.#i = i; }
 36}
 37
 38function test(i) {
 39 let c = new PrivateFieldAfterPreventExtensions;
 40 assert.equals(c.x150 === 150);
 41 c.x150 = 0.1;
 42 assert.equals(c.get(), 42);
 43 c.set(i);
 44 assert.equals(c.get(), i);
 45}
 46noInline(test);
 47
 48test(0);
 49test(1);
 50test(2);
 51for (var i = 0; i < 200; ++i)
 52 test(i);

JSTests/stress/class-fields-private-seal.js

 1//@ requireOptions("--usePrivateClassFields=1")
 2
 3let assert = Object.assign(
 4 function assert(expr, message = "") {
 5 if (expr == false)
 6 throw new Error(`Expected ${message || "expr"} to be true, but was ${expr}`);
 7 }, {
 8 equals(a, b) {
 9 if (a === b || (a === a && b === b) || (a !== a && b !== b))
 10 return;
 11
 12 throw new Error(`Expected ${a} to be ${b}`);
 13 }
 14});
 15
 16class Base {
 17 constructor() {
 18 this.x = 1;
 19 }
 20}
 21
 22class PrivateFieldAfterPreventExtensions extends Base {
 23 #i = (Object.seal(this), 42);
 24 #assert = (assert(Object.isSealed(this), "Object.isSealed(this)"), this.#i + 1);
 25
 26 get() { return this.#i; }
 27 set(i) { this.#i = i; }
 28}
 29
 30function test(i) {
 31 let c = new PrivateFieldAfterPreventExtensions;
 32 c.x = 0.1;
 33 assert.equals(c.get(), 42);
 34 c.set(i);
 35 assert.equals(c.get(), i);
 36}
 37noInline(test);
 38
 39test(0);
 40test(1);
 41test(2);
 42for (var i = 0; i < 200; ++i)
 43 test(i);

JSTests/stress/class-fields-private-use-eval.js

 1//@ requireOptions("--usePrivateClassFields=1", "--usePublicClassFields=1")
 2
 3function assert(a, message) {
 4 if (!a)
 5 throw new Error(message);
 6}
 7
 8let inst = new class {
 9 a = eval("(i) => i.#b");
 10
 11 #b = {};
 12};
 13
 14inst.a(inst).x = 1;
 15assert(inst.a(inst).x == 1);

JSTests/stress/class-fields-stress-instance.js

1 //@ requireOptions("--usePublicClassFields=true")
 1//@ requireOptions("--usePublicClassFields=true", "--usePrivateClassFields=true")
22
33class A {
44 a = 0;
55 b = 1;
 6 #c = 0;
 7 #d = 1;
68 e = function () { return 0; };
 9 #f = function() { return 1; };
710 ["g"] = 0;
811 h = eval("true");
 12 #i = eval("false");
913}
1014
1115for (var i = 0; i < 10000; i++)

JSTests/stress/optional-chaining-and-private-fields.js

 1//@ requireOptions("--usePrivateClassFields=true")
 2
 3let assert = {
 4 sameValue: (a, e) => {
 5 if (a !== e)
 6 throw new Error("Expected: " + e + " but got: " + a);
 7 },
 8
 9 throws: (expectedException, functor, m) => {
 10 try {
 11 functor();
 12 } catch(e) {
 13 if (!(e instanceof expectedException))
 14 throw new Error(m);
 15 }
 16 }
 17};
 18
 19(() => {
 20 class C {
 21 #field = 'test';
 22
 23 static access(o) {
 24 return o?.#field;
 25 }
 26 }
 27
 28 let c = new C;
 29 for (let i = 0; i < 100000; i++) {
 30 assert.sameValue(C.access(c), 'test');
 31 assert.sameValue(C.access(undefined), undefined);
 32 assert.sameValue(C.access(null), undefined);
 33 }
 34
 35 assert.throws(TypeError, () => {
 36 C.access({});
 37 }, "Object without private field should throw");
 38})();
 39
 40// Chained case
 41(() => {
 42 class C {
 43 #field = 'test';
 44
 45 static chainedAccess(o) {
 46 return o.private?.#field;
 47 }
 48 }
 49
 50 let c = new C;
 51 let o = {private: c};
 52 for (let i = 0; i < 100000; i++) {
 53 assert.sameValue(C.chainedAccess(o), 'test');
 54 assert.sameValue(C.chainedAccess({}), undefined);
 55 assert.sameValue(C.chainedAccess({private: null}), undefined);
 56 }
 57
 58 assert.throws(TypeError, () => {
 59 o.private = {};
 60 C.chainedAccess(o);
 61 }, "Object without private field should throw");
 62})();
 63
 64(() => {
 65 class C {
 66 #field;
 67
 68 setField(v) {
 69 this.#field = v;
 70 }
 71
 72 static access(o) {
 73 return o.#field?.property;
 74 }
 75 }
 76
 77 let c = new C;
 78 for (let i = 0; i < 100000; i++) {
 79 c.setField({property: 'test'});
 80 assert.sameValue(C.access(c), 'test');
 81
 82 c.setField(undefined);
 83 assert.sameValue(C.access(c), undefined);
 84
 85 c.setField(null);
 86 assert.sameValue(C.access(c), undefined);
 87 }
 88
 89 assert.throws(TypeError, () => {
 90 C.access({});
 91 }, "Object without private field should throw");
 92})();
 93

JSTests/stress/private-name-access-in-computed-property.js

 1//@ requireOptions("--usePublicClassFields=1", "--usePrivateClassFields=1")
 2
 3let assert = {
 4 throws: (expectedError, functor) => {
 5 try {
 6 functor();
 7 } catch(e) {
 8 if (!(e instanceof expectedError))
 9 throw new Error("Expected to throw: " + expectedError.name + " but throws: " + e.name);
 10 }
 11 }
 12}
 13
 14assert.throws(TypeError, () => {
 15 class Base {
 16 [{}.#x] = 1;
 17 #x = "foo";
 18 }
 19});
 20

JSTests/stress/put-by-val-direct-addprivate.js

 1// TODO: //@ requireOptions("--usePrivateClassFields=1") -- Currently, eager JIT is not supported for private field access.
 2//@ runDefault("--usePrivateClassFields=1")
 3//@ runNoJIT("--usePrivateClassFields=1")
 4//@ runNoLLInt("--usePrivateClassFields=1")
 5
 6// PrivateField "Create" access should throw if writing to a non-existent PrivateName.
 7let c, i = 0, threw = false;
 8class C {
 9 constructor() {
 10 return i < 29 ? this : c;
 11 }
 12}
 13
 14class CC extends C {
 15 #x = i++;
 16 x() { return this.#x; }
 17}
 18
 19c = new CC;
 20try {
 21 for (let j = 1; j < 50; ++j) {
 22 let x = new CC;
 23 if (x.x() !== j)
 24 throw new Error(`Expected x.x() to be ${j}, but found ${x.x()}`);
 25 }
 26} catch (e) {
 27 threw = true;
 28 if (i !== 30 || e.constructor !== TypeError) {
 29 throw e;
 30 }
 31}
 32
 33if (!threw)
 34 throw new Error("Expected TypeError, but no exception was thrown");

JSTests/stress/put-by-val-direct-putprivate.js

 1// FIXME: //@ requireOptions("--usePrivateClassFields=1") -- Currently, eager JIT is not supported for private field access. https://bugs.webkit.org/show_bug.cgi?id=212784
 2//@ runDefault("--usePrivateClassFields=1")
 3//@ runNoJIT("--usePrivateClassFields=1")
 4//@ runNoLLInt("--usePrivateClassFields=1")
 5
 6// PrivateField "Put" access should throw if writing to a non-existent PrivateName.
 7let c, i = 0, threw = false;
 8class C {
 9 #x;
 10 constructor() { return i < 30 ? this : { [Symbol.toStringTag]: "without #x" }; }
 11 static x(obj) { return obj.#x = i++; }
 12 get [Symbol.toStringTag]() { return "with #x" }
 13}
 14
 15try {
 16 for (let j = 0; j < 50; ++j) {
 17 let obj = new C;
 18 let result = C.x(obj);
 19 if (result !== j)
 20 throw new Error(`Expected C.x(${obj}) to be ${j}, but found ${result}`);
 21 }
 22} catch (e) {
 23 threw = true;
 24 // rval of AssignmentExpression is evaluated before PrivateFieldFind(#x, lref) is performed,
 25 // thus `i` has already been incremented.
 26 if (i !== 31 || e.constructor !== TypeError) {
 27 throw e;
 28 }
 29}
 30
 31if (!threw)
 32 throw new Error("Expected TypeError, but no exception was thrown");

JSTests/test262/config.yaml

@@flags:
66 Intl.RelativeTimeFormat: useIntlRelativeTimeFormat
77 WeakRef: useWeakRefs
88 class-fields-public: usePublicClassFields
 9 class-fields-private: usePrivateClassFields
910skip:
1011 features:
1112 - SharedArrayBuffer

@@skip:
1415 # https://bugs.webkit.org/show_bug.cgi?id=174931
1516 - regexp-lookbehind
1617
17  - class-fields-private
1818 - class-methods-private
1919 - class-static-fields-public
2020 - class-static-fields-private