Changeset 269922 in webkit
- Timestamp:
- Nov 17, 2020 1:37:39 PM (3 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r269831 r269922 1 2020-11-17 Xan López <xan@igalia.com> 2 3 [JSC] Add support for static public class fields 4 https://bugs.webkit.org/show_bug.cgi?id=194095 5 6 Reviewed by Yusuke Suzuki. 7 8 Enable static public fields, and import new stress tests from the 9 V8 project. Also split the support code into a separate file 10 (harmony-support.js) to avoid duplication. 11 12 * test262/config.yaml: enable static public fields. 13 * stress/class-fields-harmony.js: use the new support file. 14 * stress/class-fields-static-harmony.js: Added. 15 * stress/resources/harmony-support.js: Added. 16 1 17 2020-11-15 Sergey Rubanov <chi187@gmail.com> 2 18 -
trunk/JSTests/stress/class-fields-harmony.js
r269801 r269922 32 32 "use strict"; 33 33 34 function classOf(object) { 35 // Argument must not be null or undefined. 36 var string = Object.prototype.toString.call(object); 37 // String has format [object <ClassName>]. 38 return string.substring(8, string.length - 1); 39 } 40 41 /** 42 * Compares two objects for key/value equality. 43 * Returns true if they are equal, false otherwise. 44 */ 45 function deepObjectEquals(a, b) { 46 var aProps = Object.keys(a); 47 aProps.sort(); 48 var bProps = Object.keys(b); 49 bProps.sort(); 50 if (!deepEquals(aProps, bProps)) { 51 return false; 52 } 53 for (var i = 0; i < aProps.length; i++) { 54 if (!deepEquals(a[aProps[i]], b[aProps[i]])) { 55 return false; 56 } 57 } 58 return true; 59 } 60 61 /** 62 * Compares two JavaScript values for type and value equality. 63 * It checks internals of arrays and objects. 64 */ 65 function deepEquals(a, b) { 66 if (a === b) { 67 // Check for -0. 68 if (a === 0) return (1 / a) === (1 / b); 69 return true; 70 } 71 if (typeof a != typeof b) return false; 72 if (typeof a == 'number') return isNaN(a) && isNaN(b); 73 if (typeof a !== 'object' && typeof a !== 'function') return false; 74 // Neither a nor b is primitive. 75 var objectClass = classOf(a); 76 if (objectClass !== classOf(b)) return false; 77 if (objectClass === 'RegExp') { 78 // For RegExp, just compare pattern and flags using its toString. 79 return (a.toString() === b.toString()); 80 } 81 // Functions are only identical to themselves. 82 if (objectClass === 'Function') return false; 83 if (objectClass === 'Array') { 84 var elementCount = 0; 85 if (a.length != b.length) { 86 return false; 87 } 88 for (var i = 0; i < a.length; i++) { 89 if (!deepEquals(a[i], b[i])) return false; 90 } 91 return true; 92 } 93 if (objectClass == 'String' || objectClass == 'Number' || 94 objectClass == 'Boolean' || objectClass == 'Date') { 95 if (a.valueOf() !== b.valueOf()) return false; 96 } 97 return deepObjectEquals(a, b); 98 } 99 100 /** 101 * Throws an exception containing the user_message (if any) and the values. 102 */ 103 function fail(expected, found, user_message = '') { 104 // TODO(cira): Replace String with PrettyPrint for objects and arrays. 105 var message = 'Failure' + (user_message ? ' (' + user_message + ')' : '') + 106 ': expected <' + String(expected) + '>, found <' + String(found) + '>.'; 107 throw new Error(message); 108 } 109 110 /** 111 * Throws if obj is not of given type. 112 */ 113 function assertInstanceof(obj, type) { 114 if (!(obj instanceof type)) { 115 var actualTypeName = null; 116 var actualConstructor = Object.getPrototypeOf(obj).constructor; 117 if (typeof actualConstructor == "function") { 118 actualTypeName = actualConstructor.name || String(actualConstructor); 119 } 120 throw new Error('Object <' + obj + '> is not an instance of <' + 121 (type.name || type) + '>' + 122 (actualTypeName ? ' but of < ' + actualTypeName + '>' : '')); 123 } 124 } 125 126 /** 127 * Throws if obj is not the same as expected. 128 */ 129 function assertSame(expected, found, name_opt) { 130 if (found === expected) { 131 if (expected !== 0 || (1 / expected) === (1 / found)) 132 return; 133 } else if ((expected !== expected) && (found !== found)) { 134 return; 135 } 136 fail(expected, found, name_opt); 137 } 138 139 /** 140 * Throws if two variables have different types or values. 141 */ 142 143 function assertEquals(expected, found, user_message = '') { 144 if (!deepEquals(expected, found)) { 145 fail(expected, found, user_message); 146 } 147 } 148 149 /** 150 * Throws if two variables have equal types or values. 151 */ 152 153 function assertNotEquals(expected, found, user_message = '') { 154 if (deepEquals(expected, found)) { 155 fail(expected, found, user_message); 156 } 157 } 158 159 /** 160 * Throws if value is false. 161 */ 162 function assertTrue(value, user_message = '') { 163 assertEquals(true, value, user_message); 164 } 165 166 167 /** 168 * Throws if value is true. 169 */ 170 function assertFalse(value, user_message = '') { 171 assertEquals(false, value, user_message); 172 } 173 174 /** 175 * Runs code() and asserts that it throws the specified exception. 176 */ 177 function assertThrows(code, type_opt, cause_opt) { 178 try { 179 if (typeof code == 'function') { 180 code(); 181 } else { 182 eval(code); 183 } 184 } catch (e) { 185 if (typeof type_opt == 'function') { 186 assertInstanceof(e, type_opt); 187 } 188 if (arguments.length >= 3) { 189 assertEquals(cause_opt, e.type, 'thrown exception type mismatch'); 190 } 191 // Success. 192 return; 193 } 194 var expected = arguments.length >= 3 ? cause_opt : 195 typeof type_opt == 'function' ? type_opt : 'any exception'; 196 fail(expected, 'no exception', 'expected thrown exception'); 197 } 34 load("./resources/harmony-support.js"); 198 35 199 36 { -
trunk/JSTests/test262/config.yaml
r269720 r269922 6 6 class-fields-public: usePublicClassFields 7 7 class-fields-private: usePrivateClassFields 8 class-static-fields-public: usePublicStaticClassFields 8 9 Intl.DateTimeFormat-dayPeriod: useIntlDateTimeFormatDayPeriod 9 10 SharedArrayBuffer: useSharedArrayBuffer … … 18 19 - arbitrary-module-namespace-names 19 20 - class-methods-private 20 - class-static-fields-public21 21 - class-static-fields-private 22 22 - class-static-methods-private -
trunk/Source/JavaScriptCore/ChangeLog
r269832 r269922 1 2020-11-17 Xan López <xan@igalia.com> 2 3 [JSC] Add support for static public class fields 4 https://bugs.webkit.org/show_bug.cgi?id=194095 5 6 Reviewed by Yusuke Suzuki. 7 8 Add support for static public class fields. We can reuse most of 9 the existing machinery available for instance fields. Like 10 instance fields, static fields are initialized with a synthetic 11 function. This is done to allow us to trivially follow the scoping 12 rules in the spec. As it happens with instance fields this could 13 be inlined in a future patch. 14 15 A lot of small changes in many files are just a matter of doing 16 s/instance/class/ for variables related to class fields, which 17 before were assuming there are only instance fields implemented. 18 19 * bytecode/UnlinkedFunctionExecutable.cpp: 20 (JSC::generateUnlinkedFunctionCodeBlock): do s/instanceField/classField/. 21 * bytecode/UnlinkedFunctionExecutable.h: ditto. 22 * bytecompiler/BytecodeGenerator.cpp: 23 (JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction): ditto. 24 * bytecompiler/BytecodeGenerator.h: ditto, plus add a parameter 25 for static field locations in emitDefineClassElements. 26 * bytecompiler/NodesCodegen.cpp: 27 (JSC::PropertyListNode::emitBytecode): save static fields 28 locations when going through the property list. 29 (JSC::PropertyListNode::emitSaveComputedFieldName): consider 30 static fields here too. 31 (JSC::ClassExprNode::emitBytecode): call the initializer for 32 static fields as the very last action of the class creation. 33 * parser/ASTBuilder.h: 34 (JSC::ASTBuilder::createDefineField): field nodes can be static 35 too now. 36 * parser/NodeConstructors.h: 37 (JSC::DefineFieldNode::DefineFieldNode): ditto. 38 * parser/Nodes.h: ditto. 39 * parser/Parser.cpp: 40 (JSC::Parser<LexerType>::parseInner): s/instanceField/classField/ 41 (JSC::Parser<LexerType>::parseClass): consider static fields. 42 (JSC::Parser<LexerType>::parseInstanceFieldInitializerSourceElements): 43 s/instanceField/classField/, and consider static fields. 44 * parser/Parser.h: 45 (JSC::Parser<LexerType>::parse): s/instanceField/classField/ 46 (JSC::parse): ditto. 47 * runtime/JSFunction.cpp: 48 (JSC::JSFunction::setFunctionName): s/instanceField/classField/ 49 * runtime/OptionsList.h: add option to enable/disable static public fields. 50 1 51 2020-11-15 Yusuke Suzuki <ysuzuki@apple.com> 2 52 -
trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
r269115 r269922 57 57 JSParserScriptMode scriptMode = executable->scriptMode(); 58 58 ASSERT(isFunctionParseMode(executable->parseMode())); 59 Vector<JSTextPosition>* instanceFieldLocations = executable->instanceFieldLocations();59 Vector<JSTextPosition>* classFieldLocations = executable->classFieldLocations(); 60 60 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, nullptr, instanceFieldLocations);61 vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr, ConstructorKind::None, DerivedContextType::None, EvalContextType::None, nullptr, nullptr, classFieldLocations); 62 62 63 63 if (!function) { -
trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
r269115 r269922 210 210 String m_sourceMappingURLDirective; 211 211 Vector<CompactTDZEnvironmentMap::Handle> m_parentScopeTDZVariables; 212 Vector<JSTextPosition> m_ instanceFieldLocations;212 Vector<JSTextPosition> m_classFieldLocations; 213 213 }; 214 214 215 215 NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); } 216 216 217 Vector<JSTextPosition>* instanceFieldLocations() const217 Vector<JSTextPosition>* classFieldLocations() const 218 218 { 219 219 if (m_rareData) 220 return &m_rareData->m_ instanceFieldLocations;220 return &m_rareData->m_classFieldLocations; 221 221 return nullptr; 222 222 } 223 223 224 void set InstanceFieldLocations(Vector<JSTextPosition>&& instanceFieldLocations)225 { 226 if ( instanceFieldLocations.isEmpty())224 void setClassFieldLocations(Vector<JSTextPosition>&& classFieldLocations) 225 { 226 if (classFieldLocations.isEmpty()) 227 227 return; 228 ensureRareData().m_ instanceFieldLocations = WTFMove(instanceFieldLocations);228 ensureRareData().m_classFieldLocations = WTFMove(classFieldLocations); 229 229 } 230 230 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r269115 r269922 382 382 383 383 bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || codeBlock->usesEval(); 384 bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode:: InstanceFieldInitializerMode;384 bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode::ClassFieldInitializerMode; 385 385 386 386 if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) { … … 614 614 615 615 bool shouldCreateArgumensVariable = !haveParameterNamedArguments 616 && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode:: InstanceFieldInitializerMode).contains(m_codeBlock->parseMode());616 && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::ClassFieldInitializerMode).contains(m_codeBlock->parseMode()); 617 617 shouldCreateArgumentsVariableInParameterScope = shouldCreateArgumensVariable && !isSimpleParameterList; 618 618 // Do not create arguments variable in case of Arrow function. Value will be loaded from parent scope … … 3134 3134 } 3135 3135 3136 RegisterID* BytecodeGenerator::emitNew InstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived)3136 RegisterID* BytecodeGenerator::emitNewClassFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& classFieldLocations, bool isDerived) 3137 3137 { 3138 3138 DerivedContextType newDerivedContextType; … … 3147 3147 3148 3148 auto variablesUnderTDZ = getVariablesUnderTDZ(); 3149 SourceParseMode parseMode = SourceParseMode:: InstanceFieldInitializerMode;3149 SourceParseMode parseMode = SourceParseMode::ClassFieldInitializerMode; 3150 3150 ConstructAbility constructAbility = ConstructAbility::CannotConstruct; 3151 3151 … … 3154 3154 metadata.finishParsing(m_scopeNode->source(), Identifier(), FunctionMode::MethodDefinition); 3155 3155 auto initializer = UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), &metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(variablesUnderTDZ), newDerivedContextType, NeedsClassFieldInitializer::No); 3156 initializer->set InstanceFieldLocations(WTFMove(instanceFieldLocations));3156 initializer->setClassFieldLocations(WTFMove(classFieldLocations)); 3157 3157 3158 3158 unsigned index = m_codeBlock->addFunctionExpr(initializer); … … 4475 4475 RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment(const Identifier& identifier) 4476 4476 { 4477 ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Extends || m_codeType == EvalCode || m_codeBlock->parseMode() == SourceParseMode:: InstanceFieldInitializerMode);4477 ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Extends || m_codeType == EvalCode || m_codeBlock->parseMode() == SourceParseMode::ClassFieldInitializerMode); 4478 4478 4479 4479 return emitResolveScope(nullptr, variable(identifier, ThisResolutionType::Scoped)); -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
r269115 r269922 583 583 } 584 584 585 RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype, Vector<JSTextPosition>& instanceFieldLocations )585 RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype, Vector<JSTextPosition>& instanceFieldLocations, Vector<JSTextPosition>& staticFieldLocations) 586 586 { 587 587 ASSERT(constructor->refCount() && prototype->refCount()); … … 590 590 if (UNLIKELY(n->needsDebugHook())) 591 591 emitDebugHook(n); 592 return n->emitBytecode(*this, constructor, prototype, &instanceFieldLocations );592 return n->emitBytecode(*this, constructor, prototype, &instanceFieldLocations, &staticFieldLocations); 593 593 } 594 594 … … 777 777 RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode*); 778 778 RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource, NeedsClassFieldInitializer); 779 RegisterID* emitNew InstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived);779 RegisterID* emitNewClassFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& classFieldLocations, bool isDerived); 780 780 RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*); 781 781 RegisterID* emitNewMethodDefinition(RegisterID* dst, MethodDefinitionNode*); -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r269801 r269922 187 187 static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator) 188 188 { 189 if ((generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) && generator.parseMode() != SourceParseMode:: InstanceFieldInitializerMode) {189 if ((generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) && generator.parseMode() != SourceParseMode::ClassFieldInitializerMode) { 190 190 RegisterID* derivedConstructor = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment(); 191 191 return generator.emitGetById(generator.newTemporary(), derivedConstructor, generator.propertyNames().builtinNames().homeObjectPrivateName()); … … 578 578 } 579 579 580 RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype, Vector<JSTextPosition>* instanceFieldLocations )580 RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype, Vector<JSTextPosition>* instanceFieldLocations, Vector<JSTextPosition>* staticFieldLocations) 581 581 { 582 582 PropertyListNode* p = this; … … 593 593 ASSERT(instanceFieldLocations); 594 594 instanceFieldLocations->append(p->position()); 595 continue; 596 } 597 598 if (p->isStaticClassField()) { 599 ASSERT(staticFieldLocations); 600 staticFieldLocations->append(p->position()); 595 601 continue; 596 602 } … … 650 656 ASSERT(node->m_type & PropertyNode::Constant); 651 657 instanceFieldLocations->append(p->position()); 658 continue; 659 } 660 661 if (p->isStaticClassField()) { 662 ASSERT(staticFieldLocations); 663 staticFieldLocations->append(p->position()); 652 664 continue; 653 665 } … … 745 757 void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node) 746 758 { 747 // Private fields are handled in the synthetic instanceFieldInitializer function, not here.759 // Private fields are handled in a synthetic classFieldInitializer function, not here. 748 760 ASSERT(!(node.type() & PropertyNode::Private)); 749 761 … … 801 813 { 802 814 ASSERT(node.isComputedClassField()); 803 RefPtr<RegisterID> propertyExpr;804 815 805 816 // The 'name' refers to a synthetic private name in the class scope, where the property key is saved for later use. … … 808 819 ASSERT(!var.local()); 809 820 810 propertyExpr = generator.emitNode(node.m_expression); 811 RegisterID* propertyName = generator.emitToPropertyKey(generator.newTemporary(), propertyExpr.get()); 821 RefPtr<RegisterID> propertyExpr = generator.emitNode(node.m_expression); 822 RefPtr<RegisterID> propertyName = generator.emitToPropertyKey(generator.newTemporary(), propertyExpr.get()); 823 824 if (node.isStaticClassField()) { 825 Ref<Label> validPropertyNameLabel = generator.newLabel(); 826 RefPtr<RegisterID> prototypeString = generator.emitLoad(nullptr, JSValue(generator.addStringConstant(generator.propertyNames().prototype))); 827 generator.emitJumpIfFalse(generator.emitBinaryOp<OpStricteq>(generator.newTemporary(), prototypeString.get(), propertyName.get(), OperandTypes(ResultType::stringType(), ResultType::stringType())), validPropertyNameLabel.get()); 828 generator.emitThrowTypeError("Cannot declare a static field named 'prototype'"); 829 generator.emitLabel(validPropertyNameLabel.get()); 830 } 812 831 813 832 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); 814 generator.emitPutToScope(scope.get(), var, propertyName , ThrowIfNotFound, InitializationMode::ConstInitialization);833 generator.emitPutToScope(scope.get(), var, propertyName.get(), ThrowIfNotFound, InitializationMode::ConstInitialization); 815 834 } 816 835 … … 4947 4966 generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position); 4948 4967 4968 Vector<JSTextPosition> staticFieldLocations; 4949 4969 if (m_classElements) { 4950 4970 m_classElements->emitDeclarePrivateFieldNames(generator, generator.scopeRegister()); 4951 4971 4952 4972 Vector<JSTextPosition> instanceFieldLocations; 4953 generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get(), instanceFieldLocations );4973 generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get(), instanceFieldLocations, staticFieldLocations); 4954 4974 if (!instanceFieldLocations.isEmpty()) { 4955 RefPtr<RegisterID> instanceFieldInitializer = generator.emitNew InstanceFieldInitializerFunction(generator.newTemporary(), WTFMove(instanceFieldLocations), m_classHeritage);4975 RefPtr<RegisterID> instanceFieldInitializer = generator.emitNewClassFieldInitializerFunction(generator.newTemporary(), WTFMove(instanceFieldLocations), m_classHeritage); 4956 4976 4957 4977 // FIXME: Skip this if the initializer function isn't going to need a home object (no eval or super properties) … … 4963 4983 } 4964 4984 4965 if (m_needsLexicalScope) { 4966 if (!m_name.isNull()) { 4967 Variable classNameVar = generator.variable(m_name); 4968 RELEASE_ASSERT(classNameVar.isResolved()); 4969 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar); 4970 generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization); 4971 } 4985 if (m_needsLexicalScope && !m_name.isNull()) { 4986 Variable classNameVar = generator.variable(m_name); 4987 RELEASE_ASSERT(classNameVar.isResolved()); 4988 RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar); 4989 generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization); 4990 } 4991 4992 if (!staticFieldLocations.isEmpty()) { 4993 RefPtr<RegisterID> staticFieldInitializer = generator.emitNewClassFieldInitializerFunction(generator.newTemporary(), WTFMove(staticFieldLocations), m_classHeritage); 4994 // FIXME: Skip this if the initializer function isn't going to need a home object (no eval or super properties) 4995 // https://bugs.webkit.org/show_bug.cgi?id=196867 4996 emitPutHomeObject(generator, staticFieldInitializer.get(), constructor.get()); 4997 4998 CallArguments args(generator, nullptr); 4999 generator.move(args.thisRegister(), constructor.get()); 5000 generator.emitCall(generator.newTemporary(), staticFieldInitializer.get(), NoExpectedFunction, args, position(), position(), position(), DebuggableCall::No); 5001 } 5002 5003 if (m_needsLexicalScope) 4972 5004 generator.popLexicalScope(this); 4973 }4974 5005 4975 5006 return generator.move(generator.finalDestination(dst, constructor.get()), constructor.get()); -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r269115 r269922 118 118 119 119 EvalContextType evalContextType; 120 if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode:: InstanceFieldInitializerMode)120 if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::ClassFieldInitializerMode) 121 121 evalContextType = EvalContextType::InstanceFieldEvalContext; 122 122 else if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode())) -
trunk/Source/JavaScriptCore/parser/Nodes.h
r268323 r269922 739 739 bool isClassField() const { return isClassProperty() && !needsSuperBinding(); } 740 740 bool isInstanceClassField() const { return isInstanceClassProperty() && !needsSuperBinding(); } 741 bool isStaticClassField() const { return isStaticClassProperty() && !needsSuperBinding(); } 741 742 bool isOverriddenByDuplicate() const { return m_isOverriddenByDuplicate; } 742 743 bool isPrivate() const { return m_type & Private; } … … 783 784 bool hasInstanceFields() const; 784 785 786 bool isStaticClassField() const 787 { 788 return m_node->isStaticClassField(); 789 } 790 785 791 static bool shouldCreateLexicalScopeForClass(PropertyListNode*); 786 792 787 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector<JSTextPosition>* );793 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector<JSTextPosition>*, Vector<JSTextPosition>*); 788 794 789 795 void emitDeclarePrivateFieldNames(BytecodeGenerator&, RegisterID* scope); … … 792 798 RegisterID* emitBytecode(BytecodeGenerator& generator, RegisterID* dst = nullptr) final 793 799 { 794 return emitBytecode(generator, dst, nullptr, nullptr );800 return emitBytecode(generator, dst, nullptr, nullptr, nullptr); 795 801 } 796 802 void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&); -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r269801 r269922 210 210 211 211 template <typename LexerType> 212 Expected<typename Parser<LexerType>::ParseInnerResult, String> Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* instanceFieldLocations)212 Expected<typename Parser<LexerType>::ParseInnerResult, String> Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* classFieldLocations) 213 213 { 214 214 ASTBuilder context(const_cast<VM&>(m_vm), m_parserArena, const_cast<SourceCode*>(m_source)); … … 223 223 if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) 224 224 parameters = createGeneratorParameters(context, functionInfo.parameterCount); 225 else if (parseMode == SourceParseMode:: InstanceFieldInitializerMode)225 else if (parseMode == SourceParseMode::ClassFieldInitializerMode) 226 226 parameters = context.createFormalParameterList(); 227 227 else … … 257 257 else if (parsingContext == ParsingContext::FunctionConstructor) 258 258 sourceElements = parseSingleFunction(context, functionConstructorParametersEndPosition); 259 else if (parseMode == SourceParseMode:: InstanceFieldInitializerMode) {260 ASSERT( instanceFieldLocations && !instanceFieldLocations->isEmpty());261 sourceElements = parse InstanceFieldInitializerSourceElements(context, *instanceFieldLocations);259 else if (parseMode == SourceParseMode::ClassFieldInitializerMode) { 260 ASSERT(classFieldLocations && !classFieldLocations->isEmpty()); 261 sourceElements = parseClassFieldInitializerSourceElements(context, *classFieldLocations); 262 262 } else 263 263 sourceElements = parseSourceElements(context, CheckForStrictMode); … … 2179 2179 case SourceParseMode::ModuleAnalyzeMode: 2180 2180 case SourceParseMode::ModuleEvaluateMode: 2181 case SourceParseMode:: InstanceFieldInitializerMode:2181 case SourceParseMode::ClassFieldInitializerMode: 2182 2182 RELEASE_ASSERT_NOT_REACHED(); 2183 2183 return ""; … … 2221 2221 case SourceParseMode::ModuleAnalyzeMode: 2222 2222 case SourceParseMode::ModuleEvaluateMode: 2223 case SourceParseMode:: InstanceFieldInitializerMode:2223 case SourceParseMode::ClassFieldInitializerMode: 2224 2224 RELEASE_ASSERT_NOT_REACHED(); 2225 2225 return ""; … … 2839 2839 2840 2840 static constexpr ASCIILiteral instanceComputedNamePrefix { "instanceComputedName"_s }; 2841 static constexpr ASCIILiteral staticComputedNamePrefix { "staticComputedName"_s }; 2841 2842 2842 2843 template <typename LexerType> … … 2882 2883 TreePropertyList classElements = 0; 2883 2884 TreePropertyList classElementsTail = 0; 2884 unsigned numComputedFields = 0; 2885 unsigned nextInstanceComputedFieldID = 0; 2886 unsigned nextStaticComputedFieldID = 0; 2885 2887 while (!match(CLOSEBRACE)) { 2886 2888 if (match(SEMICOLON)) { … … 2991 2993 property = parseGetterSetter(context, type, methodStart, ConstructorKind::None, tag); 2992 2994 failIfFalse(property, "Cannot parse this method"); 2993 } else if (Options::usePublicClassFields() && !match(OPENPAREN) && tag == ClassElementTag::Instance&& parseMode == SourceParseMode::MethodMode) {2995 } else if (Options::usePublicClassFields() && !match(OPENPAREN) && (tag == ClassElementTag::Instance || Options::usePublicStaticClassFields()) && parseMode == SourceParseMode::MethodMode) { 2994 2996 ASSERT(!isGetter && !isSetter); 2995 2997 if (ident) { 2996 2998 semanticFailIfTrue(*ident == propertyNames.constructor, "Cannot declare class field named 'constructor'"); 2997 2999 semanticFailIfTrue(*ident == propertyNames.constructorPrivateField, "Cannot declare private class field named '#constructor'"); 3000 if (tag == ClassElementTag::Static) 3001 semanticFailIfTrue(*ident == propertyNames.prototype, "Cannot declare a static field named 'prototype'"); 2998 3002 } 2999 3003 3000 3004 if (computedPropertyName) { 3001 ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, numComputedFields++); 3005 if (tag == ClassElementTag::Instance) 3006 ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, nextInstanceComputedFieldID++); 3007 else 3008 ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, staticComputedNamePrefix, nextStaticComputedFieldID++); 3002 3009 DeclarationResultMask declarationResult = classScope->declareLexicalVariable(ident, true); 3003 3010 ASSERT_UNUSED(declarationResult, declarationResult == DeclarationResult::Valid); … … 3066 3073 3067 3074 template <typename LexerType> 3068 template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parse InstanceFieldInitializerSourceElements(TreeBuilder& context, const Vector<JSTextPosition>& instanceFieldLocations)3075 template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseClassFieldInitializerSourceElements(TreeBuilder& context, const Vector<JSTextPosition>& classFieldLocations) 3069 3076 { 3070 3077 TreeSourceElements sourceElements = context.createSourceElements(); … … 3072 3079 3073 3080 unsigned numComputedFields = 0; 3074 for (auto location : instanceFieldLocations) { 3081 for (auto location : classFieldLocations) { 3082 // This loop will either parse only static fields or only 3083 // instance fields, but never a mix; we could make it slightly 3084 // smarter about parsing given that fact, but it's probably 3085 // not worth the hassle, so begin each iteration without 3086 // knowing which kind the next field will be. 3087 bool isStaticField = false; 3075 3088 // We don't need to worry about hasLineTerminatorBeforeToken 3076 3089 // on class fields, so we set this value to false. … … 3081 3094 const Identifier* ident = nullptr; 3082 3095 DefineFieldNode::Type type = DefineFieldNode::Type::Name; 3083 switch (m_token.m_type) { 3084 case PRIVATENAME: 3085 type = DefineFieldNode::Type::PrivateName; 3086 FALLTHROUGH; 3087 case STRING: 3088 case IDENT: 3089 namedKeyword: 3090 ident = m_token.m_data.ident; 3091 ASSERT(ident); 3096 3097 if (match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm.propertyNames->staticKeyword) { 3098 auto* staticIdentifier = m_token.m_data.ident; 3099 ASSERT(staticIdentifier); 3092 3100 next(); 3093 break; 3094 case BIGINT: 3095 ident = &m_parserArena.identifierArena().makeBigIntDecimalIdentifier(const_cast<VM&>(m_vm), *m_token.m_data.bigIntString, m_token.m_data.radix); 3096 ASSERT(ident); 3097 next(); 3098 break; 3099 case DOUBLE: 3100 case INTEGER: 3101 ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM&>(m_vm), m_token.m_data.doubleValue); 3102 ASSERT(ident); 3103 next(); 3104 break; 3105 case OPENBRACKET: { 3106 next(); 3107 TreeExpression computedPropertyName = parseAssignmentExpression(context); 3108 failIfFalse(computedPropertyName, "Cannot parse computed property name"); 3109 handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name"); 3110 ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, numComputedFields++); 3111 type = DefineFieldNode::Type::ComputedName; 3112 break; 3113 } 3114 default: 3115 if (m_token.m_type & KeywordTokenFlag) 3116 goto namedKeyword; 3117 failDueToUnexpectedToken(); 3101 if (match(SEMICOLON) || match (EQUAL) || match(CLOSEBRACE) || m_lexer->hasLineTerminatorBeforeToken()) 3102 ident = staticIdentifier; 3103 else 3104 isStaticField = true; 3105 } 3106 3107 if (!ident) { 3108 switch (m_token.m_type) { 3109 case PRIVATENAME: 3110 type = DefineFieldNode::Type::PrivateName; 3111 FALLTHROUGH; 3112 case STRING: 3113 case IDENT: 3114 namedKeyword: 3115 ident = m_token.m_data.ident; 3116 ASSERT(ident); 3117 next(); 3118 break; 3119 case BIGINT: 3120 ident = &m_parserArena.identifierArena().makeBigIntDecimalIdentifier(const_cast<VM&>(m_vm), *m_token.m_data.bigIntString, m_token.m_data.radix); 3121 ASSERT(ident); 3122 next(); 3123 break; 3124 case DOUBLE: 3125 case INTEGER: 3126 ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM&>(m_vm), m_token.m_data.doubleValue); 3127 ASSERT(ident); 3128 next(); 3129 break; 3130 case OPENBRACKET: { 3131 next(); 3132 TreeExpression computedPropertyName = parseAssignmentExpression(context); 3133 failIfFalse(computedPropertyName, "Cannot parse computed property name"); 3134 handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name"); 3135 ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, 3136 isStaticField ? staticComputedNamePrefix : instanceComputedNamePrefix, 3137 numComputedFields++); 3138 type = DefineFieldNode::Type::ComputedName; 3139 break; 3140 } 3141 default: 3142 if (m_token.m_type & KeywordTokenFlag) 3143 goto namedKeyword; 3144 failDueToUnexpectedToken(); 3145 } 3118 3146 } 3119 3147 -
trunk/Source/JavaScriptCore/parser/Parser.h
r269115 r269922 261 261 case SourceParseMode::SetterMode: 262 262 case SourceParseMode::MethodMode: 263 case SourceParseMode:: InstanceFieldInitializerMode:263 case SourceParseMode::ClassFieldInitializerMode: 264 264 setIsFunction(); 265 265 break; … … 1713 1713 template <class TreeBuilder> TreeSourceElements parseAsyncGeneratorFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode); 1714 1714 template <class TreeBuilder> TreeSourceElements parseSingleFunction(TreeBuilder&, Optional<int> functionConstructorParametersEndPosition); 1715 template <class TreeBuilder> TreeSourceElements parse InstanceFieldInitializerSourceElements(TreeBuilder&, const Vector<JSTextPosition>&);1715 template <class TreeBuilder> TreeSourceElements parseClassFieldInitializerSourceElements(TreeBuilder&, const Vector<JSTextPosition>&); 1716 1716 template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength); 1717 1717 template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = nullptr); … … 2054 2054 template <typename LexerType> 2055 2055 template <class ParsedNode> 2056 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* parentScopePrivateNames, const Vector<JSTextPosition>* instanceFieldLocations)2056 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* parentScopePrivateNames, const Vector<JSTextPosition>* classFieldLocations) 2057 2057 { 2058 2058 int errLine; … … 2074 2074 } 2075 2075 2076 auto parseResult = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, instanceFieldLocations);2076 auto parseResult = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, classFieldLocations); 2077 2077 2078 2078 int lineNumber = m_lexer->lineNumber(); … … 2159 2159 DebuggerParseData* debuggerParseData = nullptr, 2160 2160 const VariableEnvironment* parentScopePrivateNames = nullptr, 2161 const Vector<JSTextPosition>* instanceFieldLocations = nullptr,2161 const Vector<JSTextPosition>* classFieldLocations = nullptr, 2162 2162 bool isInsideOrdinaryFunction = false) 2163 2163 { … … 2171 2171 if (source.provider()->source().is8Bit()) { 2172 2172 Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction); 2173 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, instanceFieldLocations);2173 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, classFieldLocations); 2174 2174 if (positionBeforeLastNewline) 2175 2175 *positionBeforeLastNewline = parser.positionBeforeLastNewline(); … … 2184 2184 ASSERT_WITH_MESSAGE(defaultConstructorKindForTopLevelFunction == ConstructorKind::None, "BuiltinExecutables's special constructors should always use a 8-bit string"); 2185 2185 Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction); 2186 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, instanceFieldLocations);2186 result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, classFieldLocations); 2187 2187 if (positionBeforeLastNewline) 2188 2188 *positionBeforeLastNewline = parser.positionBeforeLastNewline(); -
trunk/Source/JavaScriptCore/parser/ParserModes.h
r268323 r269922 67 67 AsyncGeneratorWrapperMethodMode = 17, 68 68 GeneratorWrapperMethodMode = 18, 69 InstanceFieldInitializerMode= 19,69 ClassFieldInitializerMode = 19, 70 70 }; 71 71 … … 117 117 SourceParseMode::AsyncGeneratorWrapperFunctionMode, 118 118 SourceParseMode::AsyncGeneratorWrapperMethodMode, 119 SourceParseMode:: InstanceFieldInitializerMode).contains(parseMode);119 SourceParseMode::ClassFieldInitializerMode).contains(parseMode); 120 120 } 121 121 -
trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
r267594 r269922 111 111 112 112 case SourceParseMode::ArrowFunctionMode: 113 case SourceParseMode:: InstanceFieldInitializerMode:113 case SourceParseMode::ClassFieldInitializerMode: 114 114 functionHeader = ""; 115 115 break; -
trunk/Source/JavaScriptCore/runtime/JSFunction.cpp
r267727 r269922 422 422 case SourceParseMode::AsyncGeneratorWrapperMethodMode: 423 423 case SourceParseMode::GeneratorWrapperMethodMode: 424 case SourceParseMode:: InstanceFieldInitializerMode:424 case SourceParseMode::ClassFieldInitializerMode: 425 425 if (!function->jsExecutable()->isInStrictContext()) 426 426 return JSValue::encode(caller); -
trunk/Source/JavaScriptCore/runtime/OptionsList.h
r269706 r269922 526 526 v(Bool, exposeCustomSettersOnGlobalObjectForTesting, false, Normal, nullptr) \ 527 527 v(Bool, useJITCage, canUseJITCage(), Normal, nullptr) \ 528 v(Bool, usePublicStaticClassFields, false, Normal, "If true, the parser will understand public static data fields inside classes.") \ 528 529 529 530 enum OptionEquivalence {
Note: See TracChangeset
for help on using the changeset viewer.