WebKit Bugzilla
Attachment 373050 Details for
Bug 194434
: [ESNext] Implement private methods
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
private_methods.diff (text/plain), 122.68 KB, created by
Caio Lima
on 2019-06-27 13:48:10 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Caio Lima
Created:
2019-06-27 13:48:10 PDT
Size:
122.68 KB
patch
obsolete
>diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog >index e40c0506f01..22863a621b5 100644 >--- a/JSTests/ChangeLog >+++ b/JSTests/ChangeLog >@@ -1,3 +1,65 @@ >+2019-06-27 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext] Implement private methods >+ https://bugs.webkit.org/show_bug.cgi?id=194434 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * stress/private-brand-installed-after-super-call-from-eval.js: Added. >+ (assert): >+ (A): >+ (C.prototype.method): >+ (C): >+ (C.prototype.baseAccess): >+ * stress/private-method-brand-check.js: Added. >+ (assert): >+ (C.prototype.m): >+ (C.prototype.method): >+ (C): >+ (try.C.prototype.m): >+ (try.C): >+ (catch): >+ * stress/private-method-comparison.js: Added. >+ (let.assert.sameValue): >+ (let.assert.throws): >+ (C.prototype.m): >+ (C.prototype.getPrivateMethod): >+ (C): >+ * stress/private-method-extends-brand-check.js: Added. >+ (assert): >+ (Base.prototype.mBase): >+ (Base.prototype.methodBase): >+ (Base): >+ (C.prototype.m): >+ (C.prototype.method): >+ (C): >+ (catch): >+ * stress/private-method-get-and-call.js: Added. >+ (let.assert.sameValue): >+ (let.assert.throws): >+ (C.prototype.m): >+ (C.prototype.getPrivateMethod): >+ (C): >+ * stress/private-method-nested-class.js: Added. >+ (assert): >+ (C): >+ (prototype.mBase): >+ (catch): >+ (prototype.method): >+ (C.prototype.m): >+ (prototype.m): >+ * stress/private-methods-on-proxy.js: Added. >+ (assert): >+ (assertArrayContent): >+ (prototype.m): >+ (prototype.method): >+ * stress/private-names-available-on-direct-eval.js: Added. >+ (let.assert.sameValue): >+ (C.prototype.m): >+ (C.prototype.callMethodFromEval): >+ (C): >+ * test262/config.yaml: >+ > 2018-11-02 Xan López <xan@igalia.com> > > [JSC] Add support for class fields >diff --git a/JSTests/stress/private-brand-installed-after-super-call-from-arrow-function.js b/JSTests/stress/private-brand-installed-after-super-call-from-arrow-function.js >new file mode 100644 >index 00000000000..63c805cfece >--- /dev/null >+++ b/JSTests/stress/private-brand-installed-after-super-call-from-arrow-function.js >@@ -0,0 +1,27 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+class A {} >+ >+class C extends A { >+ #method() { >+ return "base"; >+ } >+ >+ constructor() { >+ let init = () => super(); >+ init(); >+ } >+ >+ baseAccess() { >+ return this.#method(); >+ } >+} >+ >+let c = new C(); >+assert(c.baseAccess(), "base"); >+ >diff --git a/JSTests/stress/private-brand-installed-after-super-call-from-eval.js b/JSTests/stress/private-brand-installed-after-super-call-from-eval.js >new file mode 100644 >index 00000000000..0fd34252e7f >--- /dev/null >+++ b/JSTests/stress/private-brand-installed-after-super-call-from-eval.js >@@ -0,0 +1,26 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+class A {} >+ >+class C extends A { >+ #method() { >+ return "base"; >+ } >+ >+ constructor() { >+ eval("super()"); >+ } >+ >+ baseAccess() { >+ return this.#method(); >+ } >+} >+ >+let c = new C(); >+assert(c.baseAccess(), "base"); >+ >diff --git a/JSTests/stress/private-method-brand-check.js b/JSTests/stress/private-method-brand-check.js >new file mode 100644 >index 00000000000..593abb3fbe5 >--- /dev/null >+++ b/JSTests/stress/private-method-brand-check.js >@@ -0,0 +1,33 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+class C { >+ #m() { >+ return this.#f; >+ } >+ >+ method() { >+ return this.#m(); >+ } >+ >+ #f = 4; >+} >+ >+let c = new C(); >+assert(c.method(), 4); >+ >+try { >+ class C { >+ #m() { return 3; } >+ } >+ >+ let o = new C(); >+ c.method.call(o); >+} catch (e) { >+ assert(e instanceof TypeError, true); >+} >+ >diff --git a/JSTests/stress/private-method-comparison.js b/JSTests/stress/private-method-comparison.js >new file mode 100644 >index 00000000000..c05501ae889 >--- /dev/null >+++ b/JSTests/stress/private-method-comparison.js >@@ -0,0 +1,31 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+let assert = { >+ sameValue: function (lhs, rhs) { >+ if (lhs !== rhs) >+ throw new Error("Expected: " + lhs + " bug got: " + rhs); >+ }, >+ >+ throws: function (expectedError, op) { >+ try { >+ op(); >+ } catch(e) { >+ if (!(e instanceof expectedError)) >+ throw new Error("Expected to throw: " + expectedError + " but threw: " + e); >+ } >+ } >+}; >+ >+class C { >+ #m() { return 'test262'; } >+ >+ getPrivateMethod() { >+ return this.#m; >+ } >+} >+ >+let c1 = new C(); >+let c2 = new C(); >+ >+assert.sameValue(c1.getPrivateMethod(), c2.getPrivateMethod()); >+ >diff --git a/JSTests/stress/private-method-extends-brand-check.js b/JSTests/stress/private-method-extends-brand-check.js >new file mode 100644 >index 00000000000..747efc3f9a9 >--- /dev/null >+++ b/JSTests/stress/private-method-extends-brand-check.js >@@ -0,0 +1,41 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+class Base { >+ #mBase() { >+ return 4; >+ } >+ >+ methodBase() { >+ return this.#mBase(); >+ } >+} >+ >+class C extends Base { >+ #m() { >+ return this.#f; >+ } >+ >+ method() { >+ return this.#m(); >+ } >+ >+ #f = 15; >+} >+ >+let c = new C(); >+assert(c.method(), 15); >+assert(c.methodBase(), 4); >+ >+let base = new Base (); >+assert(base.methodBase(), 4); >+try { >+ c.method.call(base); >+} catch (e) { >+ assert(e instanceof TypeError, true); >+} >+ >diff --git a/JSTests/stress/private-method-get-and-call.js b/JSTests/stress/private-method-get-and-call.js >new file mode 100644 >index 00000000000..cf8d2c14e32 >--- /dev/null >+++ b/JSTests/stress/private-method-get-and-call.js >@@ -0,0 +1,33 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+let assert = { >+ sameValue: function (lhs, rhs) { >+ if (lhs !== rhs) >+ throw new Error("Expected: " + lhs + " bug got: " + rhs); >+ }, >+ >+ throws: function (expectedError, op) { >+ try { >+ op(); >+ } catch(e) { >+ if (!(e instanceof expectedError)) >+ throw new Error("Expected to throw: " + expectedError + " but threw: " + e); >+ } >+ } >+}; >+ >+class C { >+ #m() { return this._v; } >+ >+ getPrivateMethod() { >+ return this.#m; >+ } >+} >+ >+let c = new C(); >+ >+let o1 = {_v: 'test262'}; >+let o2 = {_v: 'foo'}; >+assert.sameValue(c.getPrivateMethod().call(o1), 'test262'); >+assert.sameValue(c.getPrivateMethod().call(o2), 'foo'); >+ >diff --git a/JSTests/stress/private-method-nested-class.js b/JSTests/stress/private-method-nested-class.js >new file mode 100644 >index 00000000000..e6c9948c1b3 >--- /dev/null >+++ b/JSTests/stress/private-method-nested-class.js >@@ -0,0 +1,68 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+function assert(a, e) { >+ if (a !== e) >+ throw new Error("Expected: " + e + " but got: " + a); >+} >+ >+(() => { >+ class Base { >+ C = class { >+ method() { >+ return this.#mBase(); >+ } >+ } >+ >+ #mBase() { >+ return 4; >+ } >+ } >+ >+ let base = new Base(); >+ let c = new base.C(); >+ assert(c.method.call(base), 4); >+ >+ try { >+ c.method(); >+ } catch (e) { >+ assert(e instanceof TypeError, true); >+ } >+})(); >+ >+// Test shadow methods >+ >+(() => { >+ class Base { >+ method() { >+ return this.#m(); >+ } >+ >+ C = class { >+ method(o) { >+ return o.#m(); >+ } >+ >+ #m() { >+ return this.foo; >+ } >+ >+ foo = 4; >+ }; >+ >+ #m() { >+ return "foo"; >+ } >+ } >+ >+ let base = new Base(); >+ let c = new base.C(); >+ assert(c.method(c), 4); >+ assert(base.method(), "foo"); >+ >+ try { >+ c.method(base); >+ } catch (e) { >+ assert(e instanceof TypeError, true); >+ } >+})(); >+ >diff --git a/JSTests/stress/private-methods-on-proxy.js b/JSTests/stress/private-methods-on-proxy.js >new file mode 100644 >index 00000000000..aeb89b106a8 >--- /dev/null >+++ b/JSTests/stress/private-methods-on-proxy.js >@@ -0,0 +1,42 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+function assert(a, e, m) { >+ if (a !== e) >+ throw new Error(m); >+} >+ >+function assertArrayContent(a, e) { >+ assert(a.length, e.length, "Size of arrays doesn't match"); >+ for (var i = 0; i < a.length; i++) >+ assert(a[i], e[i], "a[" + i + "] = " + a[i] + " but e[" + i + "] = " + e[i]); >+} >+ >+let arr = []; >+ >+class ProxyBase { >+ constructor() { >+ return new Proxy(this, { >+ get: function (obj, prop) { >+ arr.push(prop); >+ return obj[prop]; >+ } >+ }); >+ } >+} >+ >+class Test extends ProxyBase { >+ #m() { >+ return 3; >+ } >+ >+ method() { >+ return this.#m(); >+ } >+} >+ >+let t = new Test(); >+let r = t.method(); >+assert(r, 3, "Expected: 3 but got: " + r); >+ >+assertArrayContent(arr, ['method']); >+ >diff --git a/JSTests/stress/private-names-available-on-direct-eval.js b/JSTests/stress/private-names-available-on-direct-eval.js >new file mode 100644 >index 00000000000..e2707210dac >--- /dev/null >+++ b/JSTests/stress/private-names-available-on-direct-eval.js >@@ -0,0 +1,23 @@ >+//@ run("--useClassFields=true --usePrivateMethods=true") >+ >+let assert = { >+ sameValue: function (lhs, rhs) { >+ if (lhs !== rhs) >+ throw new Error("Expected: " + rhs + " bug got: " + lhs); >+ } >+}; >+ >+(function () { >+ class C { >+ #m() { return 'test'; } >+ >+ callMethodFromEval() { >+ let self = this; >+ return eval('self.#m()'); >+ } >+ } >+ >+ let c = new C(); >+ assert.sameValue(c.callMethodFromEval(), 'test'); >+})(); >+ >diff --git a/JSTests/test262/config.yaml b/JSTests/test262/config.yaml >index 8a5a99b2078..139904866da 100644 >--- a/JSTests/test262/config.yaml >+++ b/JSTests/test262/config.yaml >@@ -14,7 +14,6 @@ skip: > - async-iteration > # https://bugs.webkit.org/show_bug.cgi?id=174931 > - regexp-lookbehind >- - class-methods-private > - class-static-fields-public > - class-static-fields-private > - class-static-methods-private >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 12f458c3069..e1c446d53ea 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,294 @@ >+2019-06-27 Caio Lima <ticaiolima@gmail.com> >+ >+ [ESNext] Implement private methods >+ https://bugs.webkit.org/show_bug.cgi?id=194434 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch is adding support to private methods following the >+ specification on https://tc39.es/proposal-private-methods/. >+ This is introducing a new way to declare private methods on >+ class syntax. Private methods are only accessible within >+ classes they were declared, and only can be called from >+ objects that are instance of these classes. >+ To guarantee such rules, the proposal presents the concept of >+ Brand Check. During class evaluation, if a private method is present, >+ a `brand` is installed in this class. Every instance of such class >+ then gets this brand installed during `[[Construct]]` operation. It >+ means that an object can have multiple brands (e.g when there is also >+ private methods declared on super class). Before accessing a private >+ method, there is a check to validate if the target of the call has the >+ brand of callee method. >+ The brand check mechanism is implemented using a `@privateBrand` >+ stored on class scope. Here is a representation of how this mechanism >+ works: >+ >+ ``` >+ class C { >+ #m() { return 3; } >+ method() { return this.#m(); } >+ } >+ >+ let c = new C(); >+ console.log(c.method()); // prints 3 >+ ``` >+ >+ Generated bytecode for the following representation: >+ ``` >+ { >+ const @privateBrand = @createPrivateSymbol(); >+ const #m = function () { return 3; } >+ C.prototype.method = function() { >+ @checkPrivateBrand(this, @privateBrand0)); >+ return #m.call(this); >+ } >+ C = function() { >+ @putDirectByVal(this, @privateBrand, @privateBrand); >+ } >+ } >+ >+ let c = new C(); >+ console.log(c.method()); // prints 3 >+ ``` >+ >+ Both "@privateBrand" and "@createPrivateSymbol" are internal private >+ names and can't be defined by user code or observed by proxies. >+ The "@checkPrivateBrand" represents a new bytecode operation >+ introduced to perform brand check semantics. This new bytecode >+ performs a [[GetOwnProperty]] directly into target object, so we can >+ properly support private brands installed on Proxy objects. >+ It could also be implemented as a `get_by_val_direct`, however we >+ decided to make more specific bytecode, since this would be the only >+ use case for this bytecode. Whenever a new use case appear, we can >+ generalize `check_private_brand` to use `get_by_val_direct`. >+ >+ Using op_check_private_brand, we can do following optimizations: >+ 1. Support IC on LLInt, since once stored in a structure, the >+ private brand is never removed. >+ 2. Remove redundant checks on DFG/FTL layers. >+ >+ To properly store the private brand of a class on all Objects, >+ including Proxies, we use "@putDirectByVal". This intruction puts >+ value on Object's properties without executing [[Put]] semantics. >+ With this design, we avoid allocating a field for every instance >+ of a class, since private methods are stored on class >+ lexical scope. Every object will have to allocate its private >+ brand list. This design inserts no overhead on objects and classes >+ without private methods/accessor. >+ >+ Resolving correct brand check: >+ >+ In the case of shadowing or nested scope, we need to emit brand >+ checks to the right private brand. See code below: >+ >+ ``` >+ class C { >+ #m() { return 3; } >+ method() { return this.#m();} >+ >+ A = class { >+ #m2() { return 3; } >+ foo(o) { return this.#m(); } >+ } >+ } >+ ``` >+ >+ The call of "#m" in `foo` refers to "C.#m". In such case, we need to >+ check C's private brand, instead of A's private brand. >+ To perform the proper check we first resolve scope of "#m" and then >+ check the private brand of this scope (the scope where the private >+ method and brand are stored is the same). >+ So the bytecode to lookup the right brand is: >+ >+ ``` >+ resolve_scope loc10, "#m" >+ get_from_scope loc11, loc10, "@privateBrand" >+ check_private_brand this, loc11 >+ get_from_scope loc11, loc10, "#m" >+ // setup call frame >+ call loc11, ... >+ // ... >+ ``` >+ >+ * builtins/BuiltinExecutables.cpp: >+ (JSC::BuiltinExecutables::createDefaultConstructor): >+ (JSC::BuiltinExecutables::createExecutable): >+ * builtins/BuiltinExecutables.h: >+ >+ We are adding a new parameter `PrivateBrandRequirement` to propagate >+ when a default constructor needs to emit code to setup private brand >+ on instances. >+ >+ * builtins/BuiltinNames.h: >+ >+ Adding `@createPrivateSymbol` and `@privateBrand`. >+ `@createPrivateSymbol` is used as a function to enable us allocate >+ PrivateSymbols at execution time. `@privateBrand` is the name we use >+ to store private brand on class's scope. >+ >+ * bytecode/BytecodeList.rb: >+ * bytecode/BytecodeUseDef.h: >+ (JSC::computeUsesForBytecodeOffset): >+ (JSC::computeDefsForBytecodeOffset): >+ * bytecode/ExecutableInfo.h: >+ (JSC::ExecutableInfo::ExecutableInfo): >+ (JSC::ExecutableInfo::privateBrandRequirement const): >+ * bytecode/UnlinkedCodeBlock.cpp: >+ (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): >+ * bytecode/UnlinkedCodeBlock.h: >+ (JSC::UnlinkedCodeBlock::privateBrandRequirement const): >+ * bytecode/UnlinkedFunctionExecutable.cpp: >+ (JSC::generateUnlinkedFunctionCodeBlock): >+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): >+ * bytecode/UnlinkedFunctionExecutable.h: >+ * bytecompiler/BytecodeGenerator.cpp: >+ (JSC::BytecodeGenerator::BytecodeGenerator): >+ >+ We changed BytecodeGenerator for FunctionNode and EvalNode to >+ propagate parentScope VariableEnvironment. These environments stores >+ private name entries that are visible into the scope of the >+ function/eval in addition to TDZ variables. >+ This is required to identify the kind of access a private name is >+ referring to, since it can be a private field or a private method. >+ Given this change, we changed the name of VariableEnvironment >+ from `parentScopeTDZVariables` to `parentScopeVariableEnvironment`. >+ >+ (JSC::BytecodeGenerator::instantiateLexicalVariables): >+ (JSC::BytecodeGenerator::emitCheckPrivateBrand): >+ (JSC::BytecodeGenerator::emitCreatePrivateBrand): >+ >+ The process to create a private brand is as follows: >+ 1. Create a PrivateSymbol using `@createPrivateSymbol`. >+ 2. Store this symbol into a given scope (i.e class lexical scope) >+ on `@privateBrand` variable. >+ >+ (JSC::BytecodeGenerator::emitInstallPrivateBrand): >+ (JSC::BytecodeGenerator::emitGetPrivateBrand): >+ >+ This operation lookup for `@privateBrand` from a given scope. >+ >+ (JSC::BytecodeGenerator::isPrivateMethod): >+ (JSC::BytecodeGenerator::pushPrivateAccessNames): >+ (JSC::BytecodeGenerator::popPrivateAccessNames): >+ (JSC::BytecodeGenerator::getAvailablePrivateAccessNames): >+ (JSC::BytecodeGenerator::getVariablesUnderTDZ): >+ (JSC::BytecodeGenerator::emitNewDefaultConstructor): >+ (JSC::BytecodeGenerator::emitNewInstanceFieldInitializerFunction): >+ * bytecompiler/BytecodeGenerator.h: >+ >+ We added `m_privateNamesStack` to BytecodeGenerator to represent the >+ scope chain of available private names while generating bytecode. >+ >+ (JSC::BytecodeGenerator::privateBrandRequirement const): >+ (JSC::BytecodeGenerator::makeFunction): >+ >+ This change is required to properly propagate PrivateBrandRequirement >+ to arrow functions that can potentially call super(). >+ >+ * bytecompiler/NodesCodegen.cpp: >+ (JSC::PropertyListNode::emitPutConstantProperty): >+ (JSC::BaseDotNode::emitGetPropertyValue): >+ >+ Adding support to properly access private method. Since we store >+ private methods on class lexical scope, we need a different set of >+ instructions to access a private method instead of using >+ `get_private_field`. >+ >+ (JSC::BaseDotNode::emitPutProperty): >+ >+ In the case of we trying to write in a private method, we need to >+ throw a TypeError according to specification >+ (https://tc39.es/proposal-private-methods/#sec-privatefieldset). >+ >+ (JSC::FunctionCallValueNode::emitBytecode): >+ (JSC::ClassExprNode::emitBytecode): >+ * debugger/DebuggerCallFrame.cpp: >+ (JSC::DebuggerCallFrame::evaluateWithScopeExtension): >+ * dfg/DFGCapabilities.cpp: >+ (JSC::DFG::capabilityLevel): >+ * interpreter/Interpreter.cpp: >+ (JSC::eval): >+ * jit/JIT.cpp: >+ (JSC::JIT::privateCompileMainPass): >+ (JSC::JIT::privateCompileSlowCases): >+ * jit/JIT.h: >+ * jit/JITOpcodes.cpp: >+ (JSC::JIT::emit_op_check_private_brand): >+ * llint/LowLevelInterpreter64.asm: >+ * parser/Lexer.cpp: >+ (JSC::Lexer<UChar>::parseIdentifier): >+ * parser/NodeConstructors.h: >+ (JSC::PropertyNode::PropertyNode): >+ * parser/Nodes.cpp: >+ (JSC::FunctionMetadataNode::FunctionMetadataNode): >+ * parser/Nodes.h: >+ * parser/Parser.cpp: >+ (JSC::Parser<LexerType>::parseClass): >+ * parser/Parser.h: >+ (JSC::Scope::declarePrivateMethod): >+ * parser/ParserModes.h: >+ * parser/VariableEnvironment.cpp: >+ (JSC::VariableEnvironment::markPrivateNameAsDeclared): >+ (JSC::VariableEnvironment::declarePrivateMethod): >+ (JSC::VariableEnvironment::declarePrivateName): >+ (JSC::CompactVariableEnvironment::CompactVariableEnvironment): >+ (JSC::CompactVariableEnvironment::operator== const): >+ (JSC::CompactVariableEnvironment::toVariableEnvironment const): >+ >+ We added support to CompactVariableEnvironment also store private >+ names. >+ >+ * parser/VariableEnvironment.h: >+ (JSC::PrivateNameEntry::isMethod const): >+ (JSC::PrivateNameEntry::isPrivateAccess const): >+ (JSC::VariableEnvironment::addPrivateName): >+ (JSC::VariableEnvironment::declarePrivateMethod): >+ (JSC::VariableEnvironment::hasPrivateAccess const): >+ * runtime/CachedTypes.cpp: >+ (JSC::CachedPrivateNameEntry::encode): >+ (JSC::CachedPrivateNameEntry::decode const): >+ (JSC::CachedSymbolTable::decode const): >+ (JSC::CachedFunctionExecutableRareData::encode): >+ (JSC::CachedFunctionExecutableRareData::decode const): >+ (JSC::CachedFunctionExecutable::privateBrandRequirement const): >+ (JSC::CachedCodeBlock::privateBrandRequirement const): >+ (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): >+ (JSC::CachedFunctionExecutable::encode): >+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): >+ (JSC::CachedCodeBlock<CodeBlockType>::encode): >+ * runtime/CodeCache.cpp: >+ (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): >+ * runtime/CodeCache.h: >+ (JSC::privateBrandRequirement): >+ (JSC::privateBrandRequirement<DirectEvalExecutable>): >+ (JSC::generateUnlinkedCodeBlockImpl): >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::SLOW_PATH_DECL): >+ * runtime/CommonSlowPaths.h: >+ * runtime/DirectEvalExecutable.cpp: >+ (JSC::DirectEvalExecutable::create): >+ (JSC::DirectEvalExecutable::DirectEvalExecutable): >+ * runtime/DirectEvalExecutable.h: >+ * runtime/EvalExecutable.h: >+ (JSC::EvalExecutable::executableInfo const): >+ (JSC::EvalExecutable::privateBrandRequirement const): >+ * runtime/JSGlobalObject.cpp: >+ (JSC::createPrivateSymbol): >+ (JSC::JSGlobalObject::init): >+ * runtime/JSScope.cpp: >+ (JSC::JSScope::collectClosureVariablesUnderTDZ): >+ * runtime/JSSymbolTableObject.h: >+ (JSC::JSSymbolTableObject::setSymbolTable): >+ * runtime/ModuleProgramExecutable.h: >+ * runtime/Options.h: >+ * runtime/ProgramExecutable.h: >+ * runtime/Symbol.cpp: >+ (JSC::Symbol::createPrivate): >+ * runtime/Symbol.h: >+ * runtime/SymbolTable.cpp: >+ (JSC::SymbolTable::cloneScopePart): >+ * runtime/SymbolTable.h: >+ > 2018-11-02 Xan López <xan@igalia.com> > > [JSC] Add support for class fields >diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp >index c8c5a100182..b81497ed67f 100644 >--- a/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp >+++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp >@@ -58,14 +58,14 @@ SourceCode BuiltinExecutables::defaultConstructorSourceCode(ConstructorKind cons > return SourceCode(); > } > >-UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name, ClassFieldsInitializer classFieldsInitializer) >+UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement) > { > switch (constructorKind) { > case ConstructorKind::None: > break; > case ConstructorKind::Base: > case ConstructorKind::Extends: >- return createExecutable(m_vm, defaultConstructorSourceCode(constructorKind), name, constructorKind, ConstructAbility::CanConstruct, classFieldsInitializer); >+ return createExecutable(m_vm, defaultConstructorSourceCode(constructorKind), name, constructorKind, ConstructAbility::CanConstruct, classFieldsInitializer, privateBrandRequirement); > } > ASSERT_NOT_REACHED(); > return nullptr; >@@ -81,7 +81,7 @@ UnlinkedFunctionExecutable* createBuiltinExecutable(VM& vm, const SourceCode& co > return BuiltinExecutables::createExecutable(vm, code, name, ConstructorKind::None, constructAbility, ClassFieldsInitializer::NotNeeded); > } > >-UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility, ClassFieldsInitializer classFieldsInitializer) >+UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement) > { > // FIXME: Can we just make MetaData computation be constexpr and have the compiler do this for us? > // https://bugs.webkit.org/show_bug.cgi?id=193272 >@@ -254,7 +254,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const S > } > } > >- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, classFieldsInitializer, isBuiltinDefaultClassConstructor); >+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, classFieldsInitializer, privateBrandRequirement, isBuiltinDefaultClassConstructor); > return functionExecutable; > } > >diff --git a/Source/JavaScriptCore/builtins/BuiltinExecutables.h b/Source/JavaScriptCore/builtins/BuiltinExecutables.h >index 174c4b19fc2..2f3d130a27a 100644 >--- a/Source/JavaScriptCore/builtins/BuiltinExecutables.h >+++ b/Source/JavaScriptCore/builtins/BuiltinExecutables.h >@@ -58,10 +58,10 @@ SourceCode name##Source(); > #undef EXPOSE_BUILTIN_EXECUTABLES > > static SourceCode defaultConstructorSourceCode(ConstructorKind); >- UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name, ClassFieldsInitializer); >- >- static UnlinkedFunctionExecutable* createExecutable(VM&, const SourceCode&, const Identifier&, ConstructorKind, ConstructAbility, ClassFieldsInitializer); >+ UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name, ClassFieldsInitializer, PrivateBrandRequirement); > >+ static UnlinkedFunctionExecutable* createExecutable(VM&, const SourceCode&, const Identifier&, ConstructorKind, ConstructAbility, ClassFieldsInitializer, PrivateBrandRequirement = PrivateBrandRequirement::None); >+ > void finalizeUnconditionally(); > > private: >diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h >index da37f1e6d36..56c246e7c2a 100644 >--- a/Source/JavaScriptCore/builtins/BuiltinNames.h >+++ b/Source/JavaScriptCore/builtins/BuiltinNames.h >@@ -72,6 +72,7 @@ namespace JSC { > macro(getOwnPropertyNames) \ > macro(ownKeys) \ > macro(Set) \ >+ macro(createPrivateSymbol) \ > macro(typedArrayLength) \ > macro(typedArraySort) \ > macro(typedArrayGetOriginalConstructor) \ >@@ -179,6 +180,7 @@ namespace JSC { > macro(meta) \ > macro(webAssemblyCompileStreamingInternal) \ > macro(webAssemblyInstantiateStreamingInternal) \ >+ macro(privateBrand) \ > macro(instanceFieldInitializer) > > namespace Symbols { >diff --git a/Source/JavaScriptCore/bytecode/BytecodeList.rb b/Source/JavaScriptCore/bytecode/BytecodeList.rb >index 0ea3f71e3a9..e7f78c8d9c7 100644 >--- a/Source/JavaScriptCore/bytecode/BytecodeList.rb >+++ b/Source/JavaScriptCore/bytecode/BytecodeList.rb >@@ -503,6 +503,12 @@ op :get_by_val, > arrayProfile: ArrayProfile, > } > >+op :check_private_brand, >+ args: { >+ base: VirtualRegister, >+ brand: VirtualRegister, >+ } >+ > op :put_by_val, > args: { > base: VirtualRegister, >diff --git a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h >index 124f29710d6..5a02eed2259 100644 >--- a/Source/JavaScriptCore/bytecode/BytecodeUseDef.h >+++ b/Source/JavaScriptCore/bytecode/BytecodeUseDef.h >@@ -256,6 +256,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins > USES(OpAddPrivateField, base, value, scope) > USES(OpGetPrivateField, base, scope) > USES(OpPutPrivateField, base, value, scope) >+ USES(OpCheckPrivateBrand, base, brand) > > case op_new_array_with_spread: > handleNewArrayLike(instruction->as<OpNewArrayWithSpread>()); >@@ -357,6 +358,7 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, const Ins > case op_super_sampler_end: > case op_add_private_field: > case op_put_private_field: >+ case op_check_private_brand: > #define LLINT_HELPER_OPCODES(opcode, length) case opcode: > FOR_EACH_LLINT_OPCODE_EXTENSION(LLINT_HELPER_OPCODES); > #undef LLINT_HELPER_OPCODES >diff --git a/Source/JavaScriptCore/bytecode/ExecutableInfo.h b/Source/JavaScriptCore/bytecode/ExecutableInfo.h >index 46594da0cb4..f8d64b55dca 100644 >--- a/Source/JavaScriptCore/bytecode/ExecutableInfo.h >+++ b/Source/JavaScriptCore/bytecode/ExecutableInfo.h >@@ -36,10 +36,11 @@ enum class ClassFieldsInitializer : uint8_t { NotNeeded, Needed }; > // FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized. > // https://bugs.webkit.org/show_bug.cgi?id=151547 > struct ExecutableInfo { >- ExecutableInfo(bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, JSParserScriptMode scriptMode, SuperBinding superBinding, SourceParseMode parseMode, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, bool isArrowFunctionContext, bool isClassContext, EvalContextType evalContextType) >+ ExecutableInfo(bool usesEval, bool isStrictMode, bool isConstructor, PrivateBrandRequirement privateBrandRequirement, bool isBuiltinFunction, ConstructorKind constructorKind, JSParserScriptMode scriptMode, SuperBinding superBinding, SourceParseMode parseMode, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, bool isArrowFunctionContext, bool isClassContext, EvalContextType evalContextType) > : m_usesEval(usesEval) > , m_isStrictMode(isStrictMode) > , m_isConstructor(isConstructor) >+ , m_privateBrandRequirement(static_cast<unsigned>(privateBrandRequirement)) > , m_isBuiltinFunction(isBuiltinFunction) > , m_constructorKind(static_cast<unsigned>(constructorKind)) > , m_superBinding(static_cast<unsigned>(superBinding)) >@@ -59,6 +60,7 @@ struct ExecutableInfo { > bool usesEval() const { return m_usesEval; } > bool isStrictMode() const { return m_isStrictMode; } > bool isConstructor() const { return m_isConstructor; } >+ PrivateBrandRequirement privateBrandRequirement() const { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); } > bool isBuiltinFunction() const { return m_isBuiltinFunction; } > ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); } > SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); } >@@ -74,6 +76,7 @@ private: > unsigned m_usesEval : 1; > unsigned m_isStrictMode : 1; > unsigned m_isConstructor : 1; >+ unsigned m_privateBrandRequirement : 1; > unsigned m_isBuiltinFunction : 1; > unsigned m_constructorKind : 2; > unsigned m_superBinding : 1; >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp >index 14e62fb9f8a..99a9dc5688e 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp >+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp >@@ -69,6 +69,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code > , m_constructorKind(static_cast<unsigned>(info.constructorKind())) > , m_derivedContextType(static_cast<unsigned>(info.derivedContextType())) > , m_classFieldsInitializer(static_cast<unsigned>(info.classFieldsInitializer())) >+ , m_privateBrandRequirement(static_cast<unsigned>(info.privateBrandRequirement())) > , m_evalContextType(static_cast<unsigned>(info.evalContextType())) > , m_codeType(static_cast<unsigned>(codeType)) > , m_didOptimize(static_cast<unsigned>(MixedTriState)) >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >index e1544ccf06e..00409738cbf 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h >@@ -116,6 +116,7 @@ public: > enum { CallFunction, ApplyFunction }; > > bool isConstructor() const { return m_isConstructor; } >+ PrivateBrandRequirement privateBrandRequirement() const { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); } > bool isStrictMode() const { return m_isStrictMode; } > bool usesEval() const { return m_usesEval; } > SourceParseMode parseMode() const { return m_parseMode; } >@@ -430,6 +431,7 @@ private: > unsigned m_constructorKind : 2; > unsigned m_derivedContextType : 2; > unsigned m_classFieldsInitializer : 1; >+ unsigned m_privateBrandRequirement : 1; > unsigned m_evalContextType : 2; > unsigned m_codeType : 2; > unsigned m_didOptimize : 2; >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >index f25a9ff430b..d97e897c526 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >@@ -72,10 +72,10 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock( > > bool isClassContext = executable->superBinding() == SuperBinding::Needed; > >- UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode, ExecutableInfo(function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), scriptMode, executable->superBinding(), parseMode, executable->derivedContextType(), executable->classFieldsInitializer(), false, isClassContext, EvalContextType::FunctionEvalContext), codeGenerationMode); >+ UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode, ExecutableInfo(function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, executable->privateBrandRequirement(), functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), scriptMode, executable->superBinding(), parseMode, executable->derivedContextType(), executable->classFieldsInitializer(), false, isClassContext, EvalContextType::FunctionEvalContext), codeGenerationMode); > >- VariableEnvironment parentScopeTDZVariables = executable->parentScopeTDZVariables(); >- error = BytecodeGenerator::generate(vm, function.get(), source, result, codeGenerationMode, &parentScopeTDZVariables); >+ VariableEnvironment parentScopeVariableEnvironment = executable->parentScopeVariableEnvironment(); >+ error = BytecodeGenerator::generate(vm, function.get(), source, result, codeGenerationMode, &parentScopeVariableEnvironment); > > if (error.isValid()) > return nullptr; >@@ -83,7 +83,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock( > return result; > } > >-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, bool isBuiltinDefaultClassConstructor) >+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeVariableEnvironment, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement, bool isBuiltinDefaultClassConstructor) > : Base(*vm, structure) > , m_firstLineOffset(node->firstLine() - parentSource.firstLine().oneBasedInt()) > , m_isInStrictContext(node->isInStrictContext()) >@@ -101,6 +101,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct > , m_superBinding(static_cast<unsigned>(node->superBinding())) > , m_parametersStartOffset(node->parametersStart()) > , m_classFieldsInitializer(static_cast<unsigned>(classFieldsInitializer)) >+ , m_privateBrandRequirement(static_cast<unsigned>(privateBrandRequirement)) > , m_isCached(false) > , m_typeProfilingStartOffset(node->functionKeywordStart()) > , m_typeProfilingEndOffset(node->startStartOffset() + node->source().length() - 1) >@@ -123,12 +124,13 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct > ASSERT(m_scriptMode == static_cast<unsigned>(scriptMode)); > ASSERT(m_superBinding == static_cast<unsigned>(node->superBinding())); > ASSERT(m_derivedContextType == static_cast<unsigned>(derivedContextType)); >+ ASSERT(m_privateBrandRequirement == static_cast<unsigned>(privateBrandRequirement)); > ASSERT(!(m_isBuiltinDefaultClassConstructor && constructorKind() == ConstructorKind::None)); > ASSERT(!m_classFieldsInitializer || (isClassConstructorFunction() || derivedContextType == DerivedContextType::DerivedConstructorContext)); > if (!node->classSource().isNull()) > setClassSource(node->classSource()); >- if (parentScopeTDZVariables) >- ensureRareData().m_parentScopeTDZVariables = WTFMove(*parentScopeTDZVariables); >+ if (parentScopeVariableEnvironment) >+ ensureRareData().m_parentScopeVariableEnvironment = WTFMove(*parentScopeVariableEnvironment); > } > > UnlinkedFunctionExecutable::~UnlinkedFunctionExecutable() >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >index 742da2f0e1d..b2772d26fc3 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >@@ -69,10 +69,10 @@ public: > return &vm.unlinkedFunctionExecutableSpace.space; > } > >- static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, bool isBuiltinDefaultClassConstructor = false) >+ static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeVariableEnvironment, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement, bool isBuiltinDefaultClassConstructor = false) > { > UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap)) >- UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, classFieldsInitializer, isBuiltinDefaultClassConstructor); >+ UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeVariableEnvironment), derivedContextType, classFieldsInitializer, privateBrandRequirement, isBuiltinDefaultClassConstructor); > instance->finishCreation(*vm); > return instance; > } >@@ -142,6 +142,8 @@ public: > CodeFeatures features() const { return m_features; } > bool hasCapturedVariables() const { return m_hasCapturedVariables; } > >+ PrivateBrandRequirement privateBrandRequirement() const { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); } >+ > static const bool needsDestruction = true; > static void destroy(JSCell*); > >@@ -157,11 +159,11 @@ public: > return !m_rareData->m_classSource.isNull(); > } > >- VariableEnvironment parentScopeTDZVariables() const >+ VariableEnvironment parentScopeVariableEnvironment() const > { >- if (!m_rareData || !m_rareData->m_parentScopeTDZVariables) >+ if (!m_rareData || !m_rareData->m_parentScopeVariableEnvironment) > return VariableEnvironment(); >- return m_rareData->m_parentScopeTDZVariables.environment().toVariableEnvironment(); >+ return m_rareData->m_parentScopeVariableEnvironment.environment().toVariableEnvironment(); > } > > bool isArrowFunction() const { return isArrowFunctionParseMode(parseMode()); } >@@ -197,7 +199,7 @@ public: > SourceCode m_classSource; > String m_sourceURLDirective; > String m_sourceMappingURLDirective; >- CompactVariableMap::Handle m_parentScopeTDZVariables; >+ CompactVariableMap::Handle m_parentScopeVariableEnvironment; > Vector<JSTextPosition> m_instanceFieldLocations; > }; > >@@ -218,7 +220,7 @@ public: > } > > private: >- UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>, JSC::DerivedContextType, JSC::ClassFieldsInitializer, bool isBuiltinDefaultClassConstructor); >+ UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>, JSC::DerivedContextType, JSC::ClassFieldsInitializer, PrivateBrandRequirement, bool isBuiltinDefaultClassConstructor); > UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&); > > void decodeCachedCodeBlocks(VM&); >@@ -246,6 +248,7 @@ private: > unsigned m_superBinding : 1; > unsigned m_parametersStartOffset : 31; > unsigned m_classFieldsInitializer : 1; >+ unsigned m_privateBrandRequirement : 1; > unsigned m_isCached : 1; > unsigned m_typeProfilingStartOffset; > unsigned m_typeProfilingEndOffset; >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >index d31c711868e..bd5798af7aa 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp >@@ -328,7 +328,7 @@ ParserError BytecodeGenerator::generate() > return ParserError(ParserError::ErrorNone); > } > >-BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables) >+BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeVariableEnvironment) > : m_codeGenerationMode(codeGenerationMode) > , m_scopeNode(programNode) > , m_codeBlock(vm, codeBlock) >@@ -337,7 +337,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP > , m_vm(&vm) > , m_needsToUpdateArrowFunctionContext(programNode->usesArrowFunction() || programNode->usesEval()) > { >- ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size()); >+ ASSERT_UNUSED(parentScopeVariableEnvironment, !parentScopeVariableEnvironment->size()); > > for (auto& constantRegister : m_linkTimeConstantRegisters) > constantRegister = nullptr; >@@ -374,7 +374,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP > } > } > >-BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables) >+BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, UnlinkedFunctionCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeVariableEnvironment) > : m_codeGenerationMode(codeGenerationMode) > , m_scopeNode(functionNode) > , m_codeBlock(vm, codeBlock) >@@ -393,6 +393,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke > { > for (auto& constantRegister : m_linkTimeConstantRegisters) > constantRegister = nullptr; >+ >+ pushPrivateAccessNames(*parentScopeVariableEnvironment); > > allocateCalleeSaveSpace(); > >@@ -736,8 +738,13 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke > } else > emitCreateThis(&m_thisRegister); > >- if (Options::useClassFields() && constructorKind() == ConstructorKind::Base) >+ if (Options::useClassFields() && constructorKind() == ConstructorKind::Base) { >+ bool shouldEmitPrivateBrand = privateBrandRequirement() == PrivateBrandRequirement::Needed; >+ if (shouldEmitPrivateBrand) >+ emitInstallPrivateBrand(&m_thisRegister); >+ > emitInstanceFieldInitializationIfNeeded(&m_thisRegister, &m_calleeRegister, m_scopeNode->position(), m_scopeNode->position(), m_scopeNode->position()); >+ } > } else if (constructorKind() != ConstructorKind::None) > emitThrowTypeError("Cannot call a class constructor without |new|"); > else { >@@ -787,7 +794,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke > > // All "addVar()"s needs to happen before "initializeDefaultParameterValuesAndSetupFunctionScopeStack()" is called > // because a function's default parameter ExpressionNodes will use temporary registers. >- pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ); >+ pushTDZVariables(*parentScopeVariableEnvironment, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ); > > Ref<Label> catchLabel = newLabel(); > TryData* tryFormalParametersData = nullptr; >@@ -855,7 +862,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke > pushLexicalScope(m_scopeNode, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, shouldInitializeBlockScopedFunctions); > } > >-BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables) >+BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeVariableEnvironment) > : m_codeGenerationMode(codeGenerationMode) > , m_scopeNode(evalNode) > , m_codeBlock(vm, codeBlock) >@@ -873,7 +880,8 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod > > m_codeBlock->setNumParameters(1); > >- pushTDZVariables(*parentScopeTDZVariables, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ); >+ pushPrivateAccessNames(*parentScopeVariableEnvironment); >+ pushTDZVariables(*parentScopeVariableEnvironment, TDZCheckOptimization::DoNotOptimize, TDZRequirement::UnderTDZ); > > emitEnter(); > >@@ -918,7 +926,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod > pushLexicalScope(m_scopeNode, TDZCheckOptimization::Optimize, NestedScopeType::IsNotNested, nullptr, shouldInitializeBlockScopedFunctions); > } > >-BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeTDZVariables) >+BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNode, UnlinkedModuleProgramCodeBlock* codeBlock, OptionSet<CodeGenerationMode> codeGenerationMode, const VariableEnvironment* parentScopeVariableEnvironment) > : m_codeGenerationMode(codeGenerationMode) > , m_scopeNode(moduleProgramNode) > , m_codeBlock(vm, codeBlock) >@@ -928,7 +936,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNod > , m_usesNonStrictEval(false) > , m_needsToUpdateArrowFunctionContext(moduleProgramNode->usesArrowFunction() || moduleProgramNode->usesEval()) > { >- ASSERT_UNUSED(parentScopeTDZVariables, !parentScopeTDZVariables->size()); >+ ASSERT_UNUSED(parentScopeVariableEnvironment, !parentScopeVariableEnvironment->size()); > > for (auto& constantRegister : m_linkTimeConstantRegisters) > constantRegister = nullptr; >@@ -1965,7 +1973,7 @@ bool BytecodeGenerator::instantiateLexicalVariables(const VariableEnvironment& l > if (lexicalVariables.privateNamesSize()) { > for (const auto& privateName : lexicalVariables.privateNames()) { > if (privateName.value.isDeclared()) >- symbolTable->addPrivateName(privateName.key.get()); >+ symbolTable->addPrivateName(privateName.key, privateName.value); > } > > hasCapturedVariables = true; >@@ -2802,6 +2810,11 @@ void BytecodeGenerator::emitPrivateFieldAdd(RegisterID* base, const Identifier& > OpAddPrivateField::emit(this, base, addConstant(name), value, scopeRegister()); > } > >+void BytecodeGenerator::emitCheckPrivateBrand(RegisterID* base, RegisterID* brand) >+{ >+ OpCheckPrivateBrand::emit(this, base, brand); >+} >+ > RegisterID* BytecodeGenerator::emitPrivateFieldGet(RegisterID* dst, RegisterID* base, const Identifier& name) > { > m_codeBlock->addPropertyAccessInstruction(instructions().size()); >@@ -2809,6 +2822,37 @@ RegisterID* BytecodeGenerator::emitPrivateFieldGet(RegisterID* dst, RegisterID* > return dst; > } > >+void BytecodeGenerator::emitCreatePrivateBrand(RegisterID* scope, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd) >+{ >+ auto symbolVar = variable(propertyNames().builtinNames().createPrivateSymbolPrivateName()); >+ >+ RegisterID* symbolScope = newTemporary(); >+ symbolScope = emitResolveScope(symbolScope, symbolVar); >+ RefPtr<RegisterID> symbolFunction = emitGetFromScope(newTemporary(), symbolScope, symbolVar, ThrowIfNotFound); >+ >+ CallArguments args(*this, nullptr); >+ emitLoad(args.thisRegister(), jsUndefined()); >+ RefPtr<RegisterID> newSymbol = emitCall(newTemporary(), symbolFunction.get(), NoExpectedFunction, args, divot, divotStart, divotEnd, DebuggableCall::No); >+ >+ Variable privateBrandVar = variable(propertyNames().builtinNames().privateBrandPrivateName()); >+ >+ emitPutToScope(scope, privateBrandVar, newSymbol.get(), DoNotThrowIfNotFound, InitializationMode::Initialization); >+} >+ >+void BytecodeGenerator::emitInstallPrivateBrand(RegisterID* target) >+{ >+ Variable privateBrandVar = variable(propertyNames().builtinNames().privateBrandPrivateName()); >+ RefPtr<RegisterID> privateBrandVarScope = emitResolveScope(nullptr, privateBrandVar); >+ RegisterID* privateBrandSymbol = emitGetPrivateBrand(newTemporary(), privateBrandVarScope.get()); >+ emitDirectPutByVal(target, privateBrandSymbol, privateBrandSymbol); >+} >+ >+RegisterID* BytecodeGenerator::emitGetPrivateBrand(RegisterID* dst, RegisterID* scope) >+{ >+ Variable privateBrandVar = variable(propertyNames().builtinNames().privateBrandPrivateName()); >+ return emitGetFromScope(dst, scope, privateBrandVar, ThrowIfNotFound); >+} >+ > RegisterID* BytecodeGenerator::emitPrivateFieldSet(RegisterID* base, const Identifier& name, RegisterID* value) > { > m_codeBlock->addPropertyAccessInstruction(instructions().size()); >@@ -2910,6 +2954,38 @@ void BytecodeGenerator::liftTDZCheckIfPossible(const Variable& variable) > } > } > >+bool BytecodeGenerator::isPrivateMethod(const Identifier& ident) >+{ >+ for (unsigned i = m_privateNamesStack.size(); i--; ) { >+ auto& map = m_privateNamesStack[i]; >+ auto it = map.find(ident.impl()); >+ if (it != map.end()) >+ return it->value.isMethod(); >+ } >+ >+ return false; >+} >+ >+void BytecodeGenerator::pushPrivateAccessNames(const VariableEnvironment& environment) >+{ >+ if (!environment.privateNamesSize()) >+ return; >+ >+ VariableEnvironment::PrivateNames privateNamesMap; >+ for (const auto& entry : environment.privateNames()) >+ privateNamesMap.add(entry.key, entry.value); >+ >+ m_privateNamesStack.append(WTFMove(privateNamesMap)); >+} >+ >+void BytecodeGenerator::popPrivateAccessNames() >+{ >+ if (!m_privateNamesStack.size()) >+ return; >+ >+ m_privateNamesStack.removeLast(); >+} >+ > void BytecodeGenerator::pushTDZVariables(const VariableEnvironment& environment, TDZCheckOptimization optimization, TDZRequirement requirement) > { > if (!environment.size()) >@@ -2932,6 +3008,24 @@ void BytecodeGenerator::pushTDZVariables(const VariableEnvironment& environment, > m_cachedVariablesUnderTDZ = { }; > } > >+void BytecodeGenerator::getAvailablePrivateAccessNames(VariableEnvironment& result) >+{ >+ SmallPtrSet<UniquedStringImpl*, 16> excludedNames; >+ for (unsigned i = m_privateNamesStack.size(); i--; ) { >+ auto& map = m_privateNamesStack[i]; >+ for (auto& entry : map) { >+ if (entry.value.isPrivateAccess()) { >+ if (!excludedNames.contains(entry.key.get())) { >+ auto addResult = result.addPrivateName(entry.key); >+ addResult.iterator->value = entry.value; >+ excludedNames.add(entry.key.get()); >+ } >+ } else >+ excludedNames.add(entry.key.get()); >+ } >+ } >+} >+ > Optional<CompactVariableMap::Handle> BytecodeGenerator::getVariablesUnderTDZ() > { > if (m_cachedVariablesUnderTDZ) { >@@ -2965,6 +3059,8 @@ Optional<CompactVariableMap::Handle> BytecodeGenerator::getVariablesUnderTDZ() > } > } > >+ getAvailablePrivateAccessNames(environment); >+ > m_cachedVariablesUnderTDZ = m_vm->m_compactVariableMap->get(environment); > m_hasCachedVariablesUnderTDZ = !environment.isEmpty(); > if (!m_hasCachedVariablesUnderTDZ) >@@ -3146,9 +3242,9 @@ RegisterID* BytecodeGenerator::emitNewMethodDefinition(RegisterID* dst, MethodDe > } > > RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name, >- const Identifier& ecmaName, const SourceCode& classSource, ClassFieldsInitializer classFieldsInitializer) >+ const Identifier& ecmaName, const SourceCode& classSource, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement) > { >- UnlinkedFunctionExecutable* executable = m_vm->builtinExecutables()->createDefaultConstructor(constructorKind, name, classFieldsInitializer); >+ UnlinkedFunctionExecutable* executable = m_vm->builtinExecutables()->createDefaultConstructor(constructorKind, name, classFieldsInitializer, privateBrandRequirement); > executable->setInvalidTypeProfilingOffsets(); > executable->setEcmaName(ecmaName); > executable->setClassSource(classSource); >@@ -3178,7 +3274,7 @@ RegisterID* BytecodeGenerator::emitNewInstanceFieldInitializerFunction(RegisterI > const bool alwaysStrictInClass = true; > FunctionMetadataNode metadata(parserArena(), JSTokenLocation(), JSTokenLocation(), 0, 0, 0, 0, 0, alwaysStrictInClass, ConstructorKind::None, superBinding, 0, parseMode, false); > metadata.finishParsing(m_scopeNode->source(), Identifier(), FunctionMode::MethodDefinition); >- auto initializer = UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), &metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, ClassFieldsInitializer::NotNeeded); >+ auto initializer = UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), &metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, ClassFieldsInitializer::NotNeeded, PrivateBrandRequirement::None); > initializer->setInstanceFieldLocations(WTFMove(instanceFieldLocations)); > > unsigned index = m_codeBlock->addFunctionExpr(initializer); >diff --git a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >index d32fb68e06e..4fabe6364a1 100644 >--- a/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >+++ b/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h >@@ -389,6 +389,7 @@ namespace JSC { > bool needsToUpdateArrowFunctionContext() const { return m_needsToUpdateArrowFunctionContext; } > bool usesEval() const { return m_scopeNode->usesEval(); } > bool usesThis() const { return m_scopeNode->usesThis(); } >+ PrivateBrandRequirement privateBrandRequirement() const { return m_codeBlock->privateBrandRequirement(); } > ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); } > SuperBinding superBinding() const { return m_codeBlock->superBinding(); } > JSParserScriptMode scriptMode() const { return m_codeBlock->scriptMode(); } >@@ -737,7 +738,7 @@ namespace JSC { > > RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*); > RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode*); >- RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource, ClassFieldsInitializer); >+ RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource, ClassFieldsInitializer, PrivateBrandRequirement); > RegisterID* emitNewInstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived); > RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*); > RegisterID* emitNewMethodDefinition(RegisterID* dst, MethodDefinitionNode*); >@@ -783,6 +784,11 @@ namespace JSC { > RegisterID* emitPrivateFieldGet(RegisterID* dst, RegisterID* base, const Identifier& name); > RegisterID* emitPrivateFieldSet(RegisterID* base, const Identifier& name, RegisterID* value); > >+ void emitCreatePrivateBrand(RegisterID* dst, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd); >+ void emitInstallPrivateBrand(RegisterID* target); >+ RegisterID* emitGetPrivateBrand(RegisterID* dst, RegisterID* scope); >+ void emitCheckPrivateBrand(RegisterID* base, RegisterID* brand); >+ > void emitSuperSamplerBegin(); > void emitSuperSamplerEnd(); > >@@ -1123,6 +1129,7 @@ namespace JSC { > { > DerivedContextType newDerivedContextType = DerivedContextType::None; > >+ PrivateBrandRequirement privateBrandRequirement = metadata->privateBrandRequirement(); > ClassFieldsInitializer classFieldsInitializer = metadata->classFieldsInitializer(); > if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::AsyncArrowFunctionBodyMode).contains(metadata->parseMode())) { > if (constructorKind() == ConstructorKind::Extends || isDerivedConstructorContext()) { >@@ -1142,10 +1149,11 @@ namespace JSC { > if (parseMode == SourceParseMode::MethodMode && metadata->constructorKind() != ConstructorKind::None) > constructAbility = ConstructAbility::CanConstruct; > >- return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, classFieldsInitializer); >+ return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, classFieldsInitializer, privateBrandRequirement); > } > > Optional<CompactVariableMap::Handle> getVariablesUnderTDZ(); >+ void getAvailablePrivateAccessNames(VariableEnvironment&); > > RegisterID* emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd, DebuggableCall); > template<typename CallOp> >@@ -1208,6 +1216,11 @@ namespace JSC { > m_lastInstruction = prevLastInstruction; > } > >+ bool isPrivateMethod(const Identifier&); >+ >+ void pushPrivateAccessNames(const VariableEnvironment&); >+ void popPrivateAccessNames(); >+ > private: > InstructionStreamWriter m_writer; > >@@ -1222,6 +1235,7 @@ namespace JSC { > Vector<LexicalScopeStackEntry> m_lexicalScopeStack; > > Vector<TDZMap> m_TDZStack; >+ Vector<VariableEnvironment::PrivateNames> m_privateNamesStack; > Optional<size_t> m_varScopeLexicalScopeStackIndex; > void pushTDZVariables(const VariableEnvironment&, TDZCheckOptimization, TDZRequirement); > >diff --git a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >index dce588c95d6..927a6cadc0f 100644 >--- a/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >+++ b/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp >@@ -706,6 +706,13 @@ void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, Reg > > if (node.isClassProperty()) { > ASSERT(node.needsSuperBinding()); >+ >+ if (node.type() & PropertyNode::PrivateMethod) { >+ Variable var = generator.variable(*node.name()); >+ generator.emitPutToScope(generator.scopeRegister(), var, value.get(), DoNotThrowIfNotFound, InitializationMode::ConstInitialization); >+ return; >+ } >+ > RefPtr<RegisterID> propertyNameRegister; > if (node.name()) > propertyNameRegister = generator.emitLoad(nullptr, *node.name()); >@@ -811,8 +818,19 @@ RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register > > RegisterID* BaseDotNode::emitGetPropertyValue(BytecodeGenerator& generator, RegisterID* dst, RegisterID* base, RefPtr<RegisterID>& thisValue) > { >- if (isPrivateName()) >+ if (isPrivateName()) { >+ if (generator.isPrivateMethod(identifier())) { >+ Variable var = generator.variable(identifier()); >+ RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); >+ >+ RegisterID* privateBrandSymbol = generator.emitGetPrivateBrand(generator.newTemporary(), scope.get()); >+ generator.emitCheckPrivateBrand(base, privateBrandSymbol); >+ >+ return generator.emitGetFromScope(dst, scope.get(), var, ThrowIfNotFound); >+ } >+ > return generator.emitPrivateFieldGet(dst, base, identifier()); >+ } > > if (m_base->isSuperNode()) { > if (!thisValue) >@@ -831,8 +849,20 @@ RegisterID* BaseDotNode::emitGetPropertyValue(BytecodeGenerator& generator, Regi > > RegisterID* BaseDotNode::emitPutProperty(BytecodeGenerator& generator, RegisterID* base, RegisterID* value, RefPtr<RegisterID>& thisValue) > { >- if (isPrivateName()) >+ if (isPrivateName()) { >+ auto identifierName = identifier(); >+ if (generator.isPrivateMethod(identifierName)) { >+ Variable var = generator.variable(identifierName); >+ RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var); >+ >+ RegisterID* privateBrandSymbol = generator.emitGetPrivateBrand(generator.newTemporary(), scope.get()); >+ generator.emitCheckPrivateBrand(base, privateBrandSymbol); >+ >+ generator.emitThrowTypeError("Trying to access a not defined private setter"); >+ } >+ > return generator.emitPrivateFieldSet(base, m_ident, value); >+ } > > if (m_base->isSuperNode()) { > if (!thisValue) >@@ -971,10 +1001,12 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re > > // Initialize instance fields after super-call. > if (Options::useClassFields()) { >+ if (generator.privateBrandRequirement() == PrivateBrandRequirement::Needed) >+ generator.emitInstallPrivateBrand(generator.thisRegister()); >+ > func = generator.emitLoadDerivedConstructor(); > generator.emitInstanceFieldInitializationIfNeeded(generator.thisRegister(), func.get(), divot(), divotStart(), divotEnd()); > } >- > return ret; > } > RefPtr<RegisterID> func = generator.emitNode(m_expr); >@@ -4082,6 +4114,13 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID > if (m_needsLexicalScope) > generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested); > >+ bool hasPrivateNames = !!m_lexicalVariables.privateNamesSize(); >+ bool shouldEmitPrivateBrand = m_lexicalVariables.hasPrivateAccess(); >+ if (hasPrivateNames) >+ generator.pushPrivateAccessNames(m_lexicalVariables); >+ if (shouldEmitPrivateBrand) >+ generator.emitCreatePrivateBrand(generator.scopeRegister(), m_position, m_position, m_position); >+ > RefPtr<RegisterID> superclass; > if (m_classHeritage) { > superclass = generator.newTemporary(); >@@ -4092,7 +4131,7 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID > bool needsHomeObject = false; > > bool hasInstanceFields = this->hasInstanceFields(); >- >+ PrivateBrandRequirement privateBrandRequirement = shouldEmitPrivateBrand ? PrivateBrandRequirement::Needed : PrivateBrandRequirement::None; > if (m_constructorExpression) { > ASSERT(m_constructorExpression->isFuncExprNode()); > FunctionMetadataNode* metadata = static_cast<FuncExprNode*>(m_constructorExpression)->metadata(); >@@ -4100,10 +4139,11 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID > metadata->setClassSource(m_classSource); > if (hasInstanceFields) > metadata->setClassFieldsInitializer(ClassFieldsInitializer::Needed); >+ metadata->setPrivateBrandRequirement(privateBrandRequirement); > constructor = generator.emitNode(constructor.get(), m_constructorExpression); > needsHomeObject = m_classHeritage || metadata->superBinding() == SuperBinding::Needed; > } else >- constructor = generator.emitNewDefaultConstructor(constructor.get(), m_classHeritage ? ConstructorKind::Extends : ConstructorKind::Base, m_name, ecmaName(), m_classSource, static_cast<ClassFieldsInitializer>(hasInstanceFields)); >+ constructor = generator.emitNewDefaultConstructor(constructor.get(), m_classHeritage ? ConstructorKind::Extends : ConstructorKind::Base, m_name, ecmaName(), m_classSource, static_cast<ClassFieldsInitializer>(hasInstanceFields), privateBrandRequirement); > > const auto& propertyNames = generator.propertyNames(); > RefPtr<RegisterID> prototype = generator.emitNewObject(generator.newTemporary()); >@@ -4173,6 +4213,9 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID > generator.popLexicalScope(this); > } > >+ if (hasPrivateNames) >+ generator.popPrivateAccessNames(); >+ > return generator.move(generator.finalDestination(dst, constructor.get()), constructor.get()); > } > >diff --git a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp >index 6179acc5ec9..ab1123e3ec1 100644 >--- a/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp >+++ b/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp >@@ -247,7 +247,7 @@ JSValue DebuggerCallFrame::evaluateWithScopeExtension(const String& script, JSOb > VariableEnvironment variablesUnderTDZ; > JSScope::collectClosureVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ); > >- auto* eval = DirectEvalExecutable::create(callFrame, makeSource(script, callFrame->callerSourceOrigin()), codeBlock->isStrictMode(), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->classFieldsInitializer(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ); >+ auto* eval = DirectEvalExecutable::create(callFrame, makeSource(script, callFrame->callerSourceOrigin()), codeBlock->isStrictMode(), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->classFieldsInitializer(), codeBlock->unlinkedCodeBlock()->privateBrandRequirement(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ); > if (UNLIKELY(catchScope.exception())) { > exception = catchScope.exception(); > catchScope.clearException(); >diff --git a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp >index 85c5ac22132..0ce391eac36 100644 >--- a/Source/JavaScriptCore/dfg/DFGCapabilities.cpp >+++ b/Source/JavaScriptCore/dfg/DFGCapabilities.cpp >@@ -285,6 +285,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const I > case op_add_private_field: // FIXME: add JIT support for private field ops. https://bugs.webkit.org/show_bug.cgi?id=195619 > case op_get_private_field: > case op_put_private_field: >+ case op_check_private_brand: > case op_to_property_key: > case llint_program_prologue: > case llint_eval_prologue: >diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp >index a75d1bec009..391aca31f3e 100644 >--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp >+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp >@@ -166,7 +166,7 @@ JSValue eval(CallFrame* callFrame) > > VariableEnvironment variablesUnderTDZ; > JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ); >- eval = DirectEvalExecutable::create(callFrame, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, callerUnlinkedCodeBlock->classFieldsInitializer(), isArrowFunctionContext, evalContextType, &variablesUnderTDZ); >+ eval = DirectEvalExecutable::create(callFrame, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, callerUnlinkedCodeBlock->classFieldsInitializer(), callerUnlinkedCodeBlock->privateBrandRequirement(), isArrowFunctionContext, evalContextType, &variablesUnderTDZ); > EXCEPTION_ASSERT(!!scope.exception() == !eval); > if (!eval) > return jsUndefined(); >diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp >index 35cdeb1d29c..57d6ce0c863 100644 >--- a/Source/JavaScriptCore/jit/JIT.cpp >+++ b/Source/JavaScriptCore/jit/JIT.cpp >@@ -423,6 +423,7 @@ void JIT::privateCompileMainPass() > DEFINE_OP(op_add_private_field) > DEFINE_OP(op_put_private_field) > DEFINE_OP(op_to_property_key) >+ DEFINE_OP(op_check_private_brand) > > DEFINE_OP(op_ret) > DEFINE_OP(op_rshift) >@@ -592,6 +593,7 @@ void JIT::privateCompileSlowCases() > DEFINE_SLOWCASE_SLOW_OP(get_private_field) > DEFINE_SLOWCASE_SLOW_OP(put_private_field) > DEFINE_SLOWCASE_SLOW_OP(to_property_key) >+ DEFINE_SLOWCASE_SLOW_OP(check_private_brand) > > default: > RELEASE_ASSERT_NOT_REACHED(); >diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h >index ddffdac1a1c..de88a0ef0c1 100644 >--- a/Source/JavaScriptCore/jit/JIT.h >+++ b/Source/JavaScriptCore/jit/JIT.h >@@ -638,6 +638,7 @@ namespace JSC { > void emit_op_get_private_field(const Instruction*); > void emit_op_put_private_field(const Instruction*); > void emit_op_to_property_key(const Instruction*); >+ void emit_op_check_private_brand(const Instruction*); > > void emitSlow_op_add(const Instruction*, Vector<SlowCaseEntry>::iterator&); > void emitSlow_op_call(const Instruction*, Vector<SlowCaseEntry>::iterator&); >diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp >index 89ac3c43633..b046e48a684 100644 >--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp >+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp >@@ -1578,6 +1578,10 @@ void JIT::emit_op_to_property_key(const Instruction*) > { > addSlowCase(jump()); > } >+void JIT::emit_op_check_private_brand(const Instruction*) >+{ >+ addSlowCase(jump()); >+} > > } // namespace JSC > >diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >index 8dc3b2124ca..01b489de303 100644 >--- a/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm >@@ -2643,6 +2643,10 @@ llintOpWithMetadata(op_add_private_field, OpAddPrivateField, macro (size, get, d > dispatch() > end) > >+llintOp(op_check_private_brand, OpCheckPrivateBrand, macro (size, get, dispatch) >+ callSlowPath(_slow_path_check_private_brand) >+ dispatch() >+end) > > llintOpWithMetadata(op_get_private_field, OpGetPrivateField, macro (size, get, dispatch, metadata, return) > get(m_base, t0) >diff --git a/Source/JavaScriptCore/parser/Lexer.cpp b/Source/JavaScriptCore/parser/Lexer.cpp >index e3be096d894..880564e485d 100644 >--- a/Source/JavaScriptCore/parser/Lexer.cpp >+++ b/Source/JavaScriptCore/parser/Lexer.cpp >@@ -1083,20 +1083,21 @@ template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::p > } else > tokenData->ident = nullptr; > >+ auto identType = isPrivateName ? PRIVATENAME : IDENT; > if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateIdentifier) { > ASSERT(shouldCreateIdentifier); > if (remaining < maxTokenLength) { > const HashTableValue* entry = JSC::mainTable.entry(*ident); > ASSERT((remaining < maxTokenLength) || !entry); > if (!entry) >- return IDENT; >+ return identType; > JSTokenType token = static_cast<JSTokenType>(entry->lexerValue()); >- return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT; >+ return (token != RESERVED_IF_STRICT) || strictMode ? token : identType; > } >- return IDENT; >+ return identType; > } > >- return IDENT; >+ return identType; > } > > template<typename CharacterType> template<bool shouldCreateIdentifier> JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode) >diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h >index f86e1a6d292..fb5224f77b8 100644 >--- a/Source/JavaScriptCore/parser/NodeConstructors.h >+++ b/Source/JavaScriptCore/parser/NodeConstructors.h >@@ -253,7 +253,7 @@ namespace JSC { > , m_type(type) > , m_needsSuperBinding(superBinding == SuperBinding::Needed) > , m_putType(putType) >- , m_isPrivate(!!(type & Private)) >+ , m_isPrivate(!!(type & (PrivateField | PrivateMethod))) > , m_classElementTag(static_cast<unsigned>(tag)) > , m_isOverriddenByDuplicate(false) > { >@@ -266,7 +266,7 @@ namespace JSC { > , m_type(type) > , m_needsSuperBinding(superBinding == SuperBinding::Needed) > , m_putType(putType) >- , m_isPrivate(!!(type & Private)) >+ , m_isPrivate(!!(type & (PrivateField | PrivateMethod))) > , m_classElementTag(static_cast<unsigned>(tag)) > , m_isOverriddenByDuplicate(false) > { >@@ -279,7 +279,7 @@ namespace JSC { > , m_type(type) > , m_needsSuperBinding(superBinding == SuperBinding::Needed) > , m_putType(putType) >- , m_isPrivate(!!(type & Private)) >+ , m_isPrivate(!!(type & (PrivateField | PrivateMethod))) > , m_classElementTag(static_cast<unsigned>(tag)) > , m_isOverriddenByDuplicate(false) > { >@@ -292,7 +292,7 @@ namespace JSC { > , m_type(type) > , m_needsSuperBinding(superBinding == SuperBinding::Needed) > , m_putType(putType) >- , m_isPrivate(!!(type & Private)) >+ , m_isPrivate(!!(type & (PrivateField | PrivateMethod))) > , m_classElementTag(static_cast<unsigned>(tag)) > , m_isOverriddenByDuplicate(false) > { >diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp >index e64b6232c15..534c302905d 100644 >--- a/Source/JavaScriptCore/parser/Nodes.cpp >+++ b/Source/JavaScriptCore/parser/Nodes.cpp >@@ -200,6 +200,7 @@ FunctionMetadataNode::FunctionMetadataNode( > , m_constructorKind(static_cast<unsigned>(constructorKind)) > , m_classFieldsInitializer(static_cast<unsigned>(ClassFieldsInitializer::NotNeeded)) > , m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression) >+ , m_privateBrandRequirement(static_cast<unsigned>(PrivateBrandRequirement::None)) > , m_parseMode(mode) > , m_startColumn(startColumn) > , m_endColumn(endColumn) >@@ -224,6 +225,7 @@ FunctionMetadataNode::FunctionMetadataNode( > , m_constructorKind(static_cast<unsigned>(constructorKind)) > , m_classFieldsInitializer(static_cast<unsigned>(ClassFieldsInitializer::NotNeeded)) > , m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression) >+ , m_privateBrandRequirement(static_cast<unsigned>(PrivateBrandRequirement::None)) > , m_parseMode(mode) > , m_startColumn(startColumn) > , m_endColumn(endColumn) >diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h >index 3ca42f8bbaa..0210fa7f22f 100644 >--- a/Source/JavaScriptCore/parser/Nodes.h >+++ b/Source/JavaScriptCore/parser/Nodes.h >@@ -707,7 +707,7 @@ namespace JSC { > enum class ClassElementTag : uint8_t { No, Instance, Static, LastTag }; > class PropertyNode final : public ParserArenaFreeable { > public: >- enum Type : uint8_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, Private = 64 }; >+ enum Type : uint8_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, PrivateField = 64, PrivateMethod = 128 }; > enum PutType : uint8_t { Unknown, KnownDirect }; > > PropertyNode(const Identifier&, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag); >@@ -737,7 +737,7 @@ namespace JSC { > const Identifier* m_name; > ExpressionNode* m_expression; > ExpressionNode* m_assign; >- unsigned m_type : 7; >+ unsigned m_type; > unsigned m_needsSuperBinding : 1; > unsigned m_putType : 1; > unsigned m_isPrivate : 1; >@@ -2042,6 +2042,9 @@ namespace JSC { > void setEcmaName(const Identifier& ecmaName) { m_ecmaName = ecmaName; } > const Identifier& ecmaName() { return m_ident.isEmpty() ? m_ecmaName : m_ident; } > >+ void setPrivateBrandRequirement(PrivateBrandRequirement privateBrandRequirement) { m_privateBrandRequirement = static_cast<unsigned>(privateBrandRequirement); } >+ PrivateBrandRequirement privateBrandRequirement() { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); } >+ > FunctionMode functionMode() { return m_functionMode; } > > int functionNameStart() const { return m_functionNameStart; } >@@ -2086,6 +2089,7 @@ namespace JSC { > unsigned m_constructorKind : 2; > unsigned m_classFieldsInitializer : 1; > unsigned m_isArrowFunctionBodyExpression : 1; >+ unsigned m_privateBrandRequirement : 1; > SourceParseMode m_parseMode; > FunctionMode m_functionMode; > Identifier m_ident; >diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp >index 7de1dc1746f..a2947f5a01f 100644 >--- a/Source/JavaScriptCore/parser/Parser.cpp >+++ b/Source/JavaScriptCore/parser/Parser.cpp >@@ -2950,15 +2950,20 @@ parseMethod: > break; > case PRIVATENAME: { > ASSERT(Options::useClassFields()); >- JSToken token = m_token; > ident = m_token.m_data.ident; > failIfTrue(tag == ClassElementTag::Static, "Static class element cannot be private"); > failIfTrue(isGetter || isSetter, "Cannot parse class method with private name"); > ASSERT(ident); > next(); >- failIfTrue(matchAndUpdate(OPENPAREN, token), "Cannot parse class method with private name"); >+ if (Options::usePrivateMethods() && match(OPENPAREN)) { >+ semanticFailIfTrue(classScope->declarePrivateMethod(*ident) & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare private method twice"); >+ type = static_cast<PropertyNode::Type>(type | PropertyNode::PrivateMethod); >+ break; >+ } >+ >+ failIfTrue(match(OPENPAREN), "Cannot parse class method with private name"); > semanticFailIfTrue(classScope->declarePrivateName(*ident) & DeclarationResult::InvalidDuplicateDeclaration, "Cannot declare private field twice"); >- type = static_cast<PropertyNode::Type>(type | PropertyNode::Private); >+ type = static_cast<PropertyNode::Type>(type | PropertyNode::PrivateField); > break; > } > default: >diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h >index 801b842792c..9d968951f2c 100644 >--- a/Source/JavaScriptCore/parser/Parser.h >+++ b/Source/JavaScriptCore/parser/Parser.h >@@ -505,6 +505,27 @@ public: > m_lexicalVariables.usePrivateName(ident); > } > >+ DeclarationResultMask declarePrivateMethod(const Identifier& ident) >+ { >+ ASSERT(m_allowsLexicalDeclarations); >+ DeclarationResultMask result = DeclarationResult::Valid; >+ bool addResult = m_lexicalVariables.declarePrivateMethod(ident); >+ >+ if (!addResult) { >+ result |= DeclarationResult::InvalidDuplicateDeclaration; >+ return result; >+ } >+ >+ // We declare it since we store private methods on class >+ // scope. >+ DeclarationResultMask declarationResult = declareLexicalVariable(&ident, false); >+ ASSERT_UNUSED(declarationResult, declarationResult == DeclarationResult::Valid); >+ useVariable(&ident, false); >+ addClosedVariableCandidateUnconditionally(ident.impl()); >+ >+ return result; >+ } >+ > DeclarationResultMask declarePrivateName(const Identifier& ident) > { > ASSERT(m_allowsLexicalDeclarations); >diff --git a/Source/JavaScriptCore/parser/ParserModes.h b/Source/JavaScriptCore/parser/ParserModes.h >index 5d5882c7571..391d8090f07 100644 >--- a/Source/JavaScriptCore/parser/ParserModes.h >+++ b/Source/JavaScriptCore/parser/ParserModes.h >@@ -37,6 +37,8 @@ enum class JSParserScriptMode { Classic, Module }; > enum class ConstructorKind { None, Base, Extends }; > enum class SuperBinding { Needed, NotNeeded }; > >+enum class PrivateBrandRequirement { None, Needed }; >+ > enum class CodeGenerationMode : uint8_t { > Debugger = 1 << 0, > TypeProfiler = 1 << 1, >diff --git a/Source/JavaScriptCore/parser/VariableEnvironment.cpp b/Source/JavaScriptCore/parser/VariableEnvironment.cpp >index e32e9263df2..8ca89536379 100644 >--- a/Source/JavaScriptCore/parser/VariableEnvironment.cpp >+++ b/Source/JavaScriptCore/parser/VariableEnvironment.cpp >@@ -107,7 +107,21 @@ void VariableEnvironment::markVariableAsExported(const RefPtr<UniquedStringImpl> > findResult->value.setIsExported(); > } > >-bool VariableEnvironment::declarePrivateName(const RefPtr<UniquedStringImpl>& identifier) >+void VariableEnvironment::markPrivateNameAsDeclared(const Identifier& identifier) >+{ >+ if (!m_rareData) >+ return; >+ auto findResult = m_rareData->m_privateNames.find(identifier.impl()); >+ RELEASE_ASSERT(findResult != m_rareData->m_privateNames.end()); >+ findResult->value.setIsDeclared(); >+} >+ >+bool VariableEnvironment::declarePrivateMethod(const RefPtr<UniquedStringImpl>& identifier) >+{ >+ return declarePrivateName(identifier, PrivateNameEntry::Traits::IsMethod); >+} >+ >+bool VariableEnvironment::declarePrivateName(const RefPtr<UniquedStringImpl>& identifier, PrivateNameEntry::Traits addionalTraits) > { > if (!m_rareData) > m_rareData = std::make_unique<VariableEnvironmentRareData>(); >@@ -115,18 +129,17 @@ bool VariableEnvironment::declarePrivateName(const RefPtr<UniquedStringImpl>& id > auto findResult = m_rareData->m_privateNames.find(identifier); > > if (findResult == m_rareData->m_privateNames.end()) { >- PrivateNameEntry entry(PrivateNameEntry::Traits::IsDeclared); >+ PrivateNameEntry entry(PrivateNameEntry::Traits::IsDeclared | addionalTraits); > > auto addResult = m_rareData->m_privateNames.add(identifier, entry); > return addResult.isNewEntry; > } > >- > if (findResult->value.isDeclared()) > return false; // Error: declaring a duplicate private name. > > // it was previously used, mark it as declared. >- PrivateNameEntry entry(PrivateNameEntry::Traits::IsDeclared | PrivateNameEntry::Traits::IsUsed); >+ PrivateNameEntry entry(PrivateNameEntry::Traits::IsDeclared | PrivateNameEntry::Traits::IsUsed | addionalTraits); > auto addResult = m_rareData->m_privateNames.set(identifier, entry); > return !addResult.isNewEntry; > } >@@ -159,6 +172,25 @@ CompactVariableEnvironment::CompactVariableEnvironment(const VariableEnvironment > }); > > m_hash = 0; >+ if (env.privateNamesSize()) { >+ Vector<std::pair<UniquedStringImpl*, PrivateNameEntry>, 16> sortedPrivateEntries; >+ sortedPrivateEntries.reserveInitialCapacity(env.privateNamesSize()); >+ for (const auto& entries : env.privateNames()) >+ sortedPrivateEntries.append({entries.key.get(), entries.value}); >+ >+ std::sort(sortedPrivateEntries.begin(), sortedPrivateEntries.end(), [] (const auto& a, const auto& b) { >+ return a.first < b.first; >+ }); >+ >+ m_privateAccessNames.reserveInitialCapacity(env.privateNamesSize()); >+ for (const auto& pair : sortedPrivateEntries) { >+ m_privateAccessNames.append(pair.first); >+ m_privateNameMetadata.append(pair.second); >+ m_hash ^= pair.first->hash(); >+ m_hash += pair.second.bits(); >+ } >+ } >+ > m_variables.reserveInitialCapacity(sortedEntries.size()); > m_variableMetadata.reserveInitialCapacity(sortedEntries.size()); > for (const auto& pair : sortedEntries) { >@@ -182,6 +214,10 @@ bool CompactVariableEnvironment::operator==(const CompactVariableEnvironment& ot > return false; > if (m_variableMetadata != other.m_variableMetadata) > return false; >+ if (m_privateAccessNames != other.m_privateAccessNames) >+ return false; >+ if (m_privateNameMetadata != other.m_privateNameMetadata) >+ return false; > return true; > } > >@@ -195,6 +231,12 @@ VariableEnvironment CompactVariableEnvironment::toVariableEnvironment() const > addResult.iterator->value = m_variableMetadata[i]; > } > >+ for (size_t i = 0; i < m_privateAccessNames.size(); i++) { >+ auto addResult = result.addPrivateName(m_privateAccessNames[i]); >+ ASSERT(addResult.isNewEntry); >+ addResult.iterator->value = m_privateNameMetadata[i]; >+ } >+ > if (m_isEverythingCaptured) > result.markAllVariablesAsCaptured(); > >diff --git a/Source/JavaScriptCore/parser/VariableEnvironment.h b/Source/JavaScriptCore/parser/VariableEnvironment.h >index 58f1a0b5623..906d33099ae 100644 >--- a/Source/JavaScriptCore/parser/VariableEnvironment.h >+++ b/Source/JavaScriptCore/parser/VariableEnvironment.h >@@ -86,11 +86,16 @@ struct VariableEnvironmentEntryHashTraits : HashTraits<VariableEnvironmentEntry> > }; > > struct PrivateNameEntry { >+ friend class CachedPrivateNameEntry; >+ > public: > PrivateNameEntry(uint16_t traits = 0) { m_bits = traits; } > > ALWAYS_INLINE bool isUsed() const { return m_bits & IsUsed; } > ALWAYS_INLINE bool isDeclared() const { return m_bits & IsDeclared; } >+ ALWAYS_INLINE bool isMethod() const { return m_bits & IsMethod; } >+ >+ bool isPrivateAccess() const { return isMethod(); } > > ALWAYS_INLINE void setIsUsed() { m_bits |= IsUsed; } > ALWAYS_INLINE void setIsDeclared() { m_bits |= IsDeclared; } >@@ -103,8 +108,10 @@ public: > } > > enum Traits : uint16_t { >+ None = 0, > IsUsed = 1 << 0, > IsDeclared = 1 << 1, >+ IsMethod = 1 << 2, > }; > > private: >@@ -118,8 +125,10 @@ struct PrivateNameEntryHashTraits : HashTraits<PrivateNameEntry> { > class VariableEnvironment { > private: > typedef HashMap<RefPtr<UniquedStringImpl>, VariableEnvironmentEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, VariableEnvironmentEntryHashTraits> Map; >- typedef HashMap<RefPtr<UniquedStringImpl>, PrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> PrivateNames; >+ > public: >+ typedef HashMap<RefPtr<UniquedStringImpl>, PrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> PrivateNames; >+ > VariableEnvironment() > { } > VariableEnvironment(VariableEnvironment&& other) >@@ -140,6 +149,16 @@ public: > ALWAYS_INLINE Map::const_iterator end() const { return m_map.end(); } > ALWAYS_INLINE Map::AddResult add(const RefPtr<UniquedStringImpl>& identifier) { return m_map.add(identifier, VariableEnvironmentEntry()); } > ALWAYS_INLINE Map::AddResult add(const Identifier& identifier) { return add(identifier.impl()); } >+ >+ ALWAYS_INLINE PrivateNames::AddResult addPrivateName(const Identifier& identifier) { return addPrivateName(identifier.impl()); } >+ ALWAYS_INLINE PrivateNames::AddResult addPrivateName(const RefPtr<UniquedStringImpl>& identifier) >+ { >+ if (!m_rareData) >+ m_rareData = std::make_unique<VariableEnvironmentRareData>(); >+ >+ return m_rareData->m_privateNames.add(identifier, PrivateNameEntry()); >+ } >+ > ALWAYS_INLINE unsigned size() const { return m_map.size() + privateNamesSize(); } > ALWAYS_INLINE unsigned mapSize() const { return m_map.size(); } > ALWAYS_INLINE bool contains(const RefPtr<UniquedStringImpl>& identifier) const { return m_map.contains(identifier); } >@@ -160,8 +179,13 @@ public: > > typedef WTF::IteratorRange<PrivateNames::iterator> PrivateNamesRange; > >+ void markPrivateNameAsDeclared(const Identifier&); >+ >+ bool declarePrivateMethod(const Identifier& identifier) { return declarePrivateMethod(identifier.impl()); } >+ bool declarePrivateMethod(const RefPtr<UniquedStringImpl>& identifier); >+ > bool declarePrivateName(const Identifier& identifier) { return declarePrivateName(identifier.impl()); } >- bool declarePrivateName(const RefPtr<UniquedStringImpl>& identifier); >+ bool declarePrivateName(const RefPtr<UniquedStringImpl>& identifier, PrivateNameEntry::Traits addionalTraits = PrivateNameEntry::Traits::None); > void usePrivateName(const RefPtr<UniquedStringImpl>& identifier); > ALWAYS_INLINE void usePrivateName(const Identifier& identifier) > { >@@ -181,6 +205,19 @@ public: > return m_rareData->m_privateNames.size(); > } > >+ ALWAYS_INLINE bool hasPrivateAccess() const >+ { >+ if (!m_rareData) >+ return false; >+ >+ for (auto entry : privateNames()) { >+ if (entry.value.isPrivateAccess()) >+ return true; >+ } >+ >+ return false; >+ } >+ > ALWAYS_INLINE bool hasPrivateName(const Identifier& identifier) > { > if (!m_rareData) >@@ -263,6 +300,9 @@ private: > > Vector<RefPtr<UniquedStringImpl>> m_variables; > Vector<VariableEnvironmentEntry> m_variableMetadata; >+ Vector<RefPtr<UniquedStringImpl>> m_privateAccessNames; >+ Vector<PrivateNameEntry> m_privateNameMetadata; >+ > unsigned m_hash; > bool m_isEverythingCaptured; > }; >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp >index 885e42fc8c1..59995bcb631 100644 >--- a/Source/JavaScriptCore/runtime/CachedTypes.cpp >+++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp >@@ -1114,6 +1114,22 @@ private: > intptr_t m_bits; > }; > >+class CachedPrivateNameEntry : public CachedObject<PrivateNameEntry> { >+public: >+ void encode(Encoder&, const PrivateNameEntry& privateNameEntry) >+ { >+ m_bits = privateNameEntry.m_bits; >+ } >+ >+ void decode(Decoder&, PrivateNameEntry& privateNameEntry) const >+ { >+ privateNameEntry.m_bits = m_bits; >+ } >+ >+private: >+ uint16_t m_bits; >+}; >+ > class CachedSymbolTableRareData : public CachedObject<SymbolTable::SymbolTableRareData> { > public: > void encode(Encoder& encoder, const SymbolTable::SymbolTableRareData& rareData) >@@ -1129,7 +1145,7 @@ public: > } > > private: >- CachedHashSet<CachedRefPtr<CachedUniquedStringImpl>, StringRepHash> m_privateNames; >+ CachedHashMap<CachedRefPtr<CachedUniquedStringImpl>, CachedPrivateNameEntry, IdentifierRepHash, HashTraits<RefPtr<UniquedStringImpl>>, PrivateNameEntryHashTraits> m_privateNames; > }; > > class CachedSymbolTable : public CachedObject<SymbolTable> { >@@ -1153,8 +1169,10 @@ public: > symbolTable->m_usesNonStrictEval = m_usesNonStrictEval; > symbolTable->m_nestedLexicalScope = m_nestedLexicalScope; > symbolTable->m_scopeType = m_scopeType; >- std::unique_ptr<SymbolTable::SymbolTableRareData> rareData(m_rareData.decodeAsPtr(decoder)); >- symbolTable->m_rareData = WTFMove(rareData); >+ if (!m_rareData.isEmpty()) { >+ std::unique_ptr<SymbolTable::SymbolTableRareData> rareData(m_rareData.decodeAsPtr(decoder)); >+ symbolTable->m_rareData = WTFMove(rareData); >+ } > ScopedArgumentsTable* scopedArgumentsTable = m_arguments.decode(decoder); > if (scopedArgumentsTable) > symbolTable->m_arguments.set(decoder.vm(), symbolTable, scopedArgumentsTable); >@@ -1681,21 +1699,21 @@ public: > void encode(Encoder& encoder, const UnlinkedFunctionExecutable::RareData& rareData) > { > m_classSource.encode(encoder, rareData.m_classSource); >- m_parentScopeTDZVariables.encode(encoder, rareData.m_parentScopeTDZVariables); >+ m_parentScopeVariableEnvironment.encode(encoder, rareData.m_parentScopeVariableEnvironment); > } > > UnlinkedFunctionExecutable::RareData* decode(Decoder& decoder) const > { > UnlinkedFunctionExecutable::RareData* rareData = new UnlinkedFunctionExecutable::RareData { }; > m_classSource.decode(decoder, rareData->m_classSource); >- auto parentScopeTDZVariables = m_parentScopeTDZVariables.decode(decoder); >- rareData->m_parentScopeTDZVariables = WTFMove(parentScopeTDZVariables); >+ auto parentScopeVariableEnvironment = m_parentScopeVariableEnvironment.decode(decoder); >+ rareData->m_parentScopeVariableEnvironment = WTFMove(parentScopeVariableEnvironment); > return rareData; > } > > private: > CachedSourceCodeWithoutProvider m_classSource; >- CachedCompactVariableMapHandle m_parentScopeTDZVariables; >+ CachedCompactVariableMapHandle m_parentScopeVariableEnvironment; > }; > > class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> { >@@ -1731,6 +1749,7 @@ public: > unsigned superBinding() const { return m_superBinding; } > unsigned derivedContextType() const { return m_derivedContextType; } > unsigned classFieldsInitializer() const { return m_classFieldsInitializer; } >+ unsigned privateBrandRequirement() const { return m_privateBrandRequirement; } > > Identifier name(Decoder& decoder) const { return m_name.decode(decoder); } > Identifier ecmaName(Decoder& decoder) const { return m_ecmaName.decode(decoder); } >@@ -1765,6 +1784,7 @@ private: > unsigned m_functionMode : 2; // FunctionMode > unsigned m_derivedContextType: 2; > unsigned m_classFieldsInitializer : 1; >+ unsigned m_privateBrandRequirement : 1; > > CachedPtr<CachedFunctionExecutableRareData> m_rareData; > >@@ -1818,6 +1838,7 @@ public: > unsigned constructorKind() const { return m_constructorKind; } > unsigned derivedContextType() const { return m_derivedContextType; } > unsigned classFieldsInitializer() const { return m_classFieldsInitializer; } >+ unsigned privateBrandRequirement() const { return m_privateBrandRequirement; } > unsigned evalContextType() const { return m_evalContextType; } > unsigned hasTailCalls() const { return m_hasTailCalls; } > unsigned lineCount() const { return m_lineCount; } >@@ -1851,6 +1872,7 @@ private: > unsigned m_constructorKind : 2; > unsigned m_derivedContextType : 2; > unsigned m_classFieldsInitializer : 1; >+ unsigned m_privateBrandRequirement : 1; > unsigned m_evalContextType : 2; > unsigned m_hasTailCalls : 1; > unsigned m_codeType : 2; >@@ -2049,6 +2071,7 @@ ALWAYS_INLINE UnlinkedCodeBlock::UnlinkedCodeBlock(Decoder& decoder, Structure* > , m_constructorKind(cachedCodeBlock.constructorKind()) > , m_derivedContextType(cachedCodeBlock.derivedContextType()) > , m_classFieldsInitializer(cachedCodeBlock.classFieldsInitializer()) >+ , m_privateBrandRequirement(cachedCodeBlock.privateBrandRequirement()) > , m_evalContextType(cachedCodeBlock.evalContextType()) > , m_codeType(cachedCodeBlock.codeType()) > >@@ -2136,6 +2159,7 @@ ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const Unli > m_superBinding = executable.m_superBinding; > m_derivedContextType = executable.m_derivedContextType; > m_classFieldsInitializer = executable.m_classFieldsInitializer; >+ m_privateBrandRequirement = executable.m_privateBrandRequirement; > > m_rareData.encode(encoder, executable.m_rareData.get()); > >@@ -2174,6 +2198,7 @@ ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& de > , m_superBinding(cachedExecutable.superBinding()) > , m_parametersStartOffset(cachedExecutable.parametersStartOffset()) > , m_classFieldsInitializer(cachedExecutable.classFieldsInitializer()) >+ , m_privateBrandRequirement(cachedExecutable.privateBrandRequirement()) > , m_isCached(false) > , m_typeProfilingStartOffset(cachedExecutable.typeProfilingStartOffset()) > , m_typeProfilingEndOffset(cachedExecutable.typeProfilingEndOffset()) >@@ -2239,6 +2264,7 @@ ALWAYS_INLINE void CachedCodeBlock<CodeBlockType>::encode(Encoder& encoder, cons > m_constructorKind = codeBlock.m_constructorKind; > m_derivedContextType = codeBlock.m_derivedContextType; > m_classFieldsInitializer = codeBlock.m_classFieldsInitializer; >+ m_privateBrandRequirement = codeBlock.m_privateBrandRequirement; > m_evalContextType = codeBlock.m_evalContextType; > m_lineCount = codeBlock.m_lineCount; > m_endColumn = codeBlock.m_endColumn; >diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp >index 5b3c424ef7c..6c40c1aa875 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.cpp >+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp >@@ -151,7 +151,7 @@ UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& v > // The Function constructor only has access to global variables, so no variables will be under TDZ unless they're > // in the global lexical environment, which we always TDZ check accesses from. > ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode()); >- UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, ClassFieldsInitializer::NotNeeded); >+ UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, ClassFieldsInitializer::NotNeeded, PrivateBrandRequirement::None); > > if (!source.provider()->sourceURLDirective().isNull()) > functionExecutable->setSourceURLDirective(source.provider()->sourceURLDirective()); >diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h >index c26bb40c63c..a39fe370e75 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.h >+++ b/Source/JavaScriptCore/runtime/CodeCache.h >@@ -271,6 +271,18 @@ inline ClassFieldsInitializer classFieldsInitializer<DirectEvalExecutable>(Direc > return executable->classFieldsInitializer(); > } > >+template <class ExecutableType> >+inline PrivateBrandRequirement privateBrandRequirement(ExecutableType*) >+{ >+ return PrivateBrandRequirement::None; >+} >+ >+template <> >+inline PrivateBrandRequirement privateBrandRequirement<DirectEvalExecutable>(DirectEvalExecutable* executable) >+{ >+ return executable->privateBrandRequirement(); >+} >+ > template <class UnlinkedCodeBlockType, class ExecutableType = ScriptExecutable> > UnlinkedCodeBlockType* generateUnlinkedCodeBlockImpl(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, OptionSet<CodeGenerationMode> codeGenerationMode, ParserError& error, EvalContextType evalContextType, DerivedContextType derivedContextType, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ, ExecutableType* executable = nullptr) > { >@@ -291,7 +303,7 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlockImpl(VM& vm, const SourceCode& s > > bool usesEval = rootNode->features() & EvalFeature; > bool isStrictMode = rootNode->features() & StrictModeFeature; >- ExecutableInfo executableInfo(usesEval, isStrictMode, false, false, ConstructorKind::None, scriptMode, SuperBinding::NotNeeded, CacheTypes<UnlinkedCodeBlockType>::parseMode, derivedContextType, classFieldsInitializer(executable), isArrowFunctionContext, false, evalContextType); >+ ExecutableInfo executableInfo(usesEval, isStrictMode, false, privateBrandRequirement(executable), false, ConstructorKind::None, scriptMode, SuperBinding::NotNeeded, CacheTypes<UnlinkedCodeBlockType>::parseMode, derivedContextType, classFieldsInitializer(executable), isArrowFunctionContext, false, evalContextType); > > UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executableInfo, codeGenerationMode); > unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), lineCount, unlinkedEndColumn); >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >index c7b5274dc21..2db8ef85a81 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >@@ -1577,4 +1577,29 @@ SLOW_PATH_DECL(slow_path_put_private_field) > END(); > } > >+SLOW_PATH_DECL(slow_path_check_private_brand) >+{ >+ BEGIN(); >+ auto bytecode = pc->as<OpCheckPrivateBrand>(); >+ >+ JSValue baseValue = GET(bytecode.m_base).jsValue(); >+ if (!baseValue.isObject()) >+ THROW(createTypeError(exec, "Invalid access to a private member."_s)); >+ JSValue brand = GET_C(bytecode.m_brand).jsValue(); >+ ASSERT(brand.isSymbol()); >+ >+ baseValue.requireObjectCoercible(exec); >+ CHECK_EXCEPTION(); >+ auto property = brand.toPropertyKey(exec); >+ CHECK_EXCEPTION(); >+ >+ ASSERT(property.isPrivateName()); >+ PropertySlot slot(baseValue, PropertySlot::PropertySlot::InternalMethodType::VMInquiry); >+ bool found = JSObject::getOwnPropertySlot(asObject(baseValue), exec, property, slot); >+ if (!found) >+ THROW(createTypeError(exec, "Invalid access to a private member."_s)); >+ >+ END(); >+} >+ > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h >index 9ded7017b9c..e39a62ea0c0 100644 >--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h >+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h >@@ -398,6 +398,7 @@ SLOW_PATH_HIDDEN_DECL(slow_path_spread); > SLOW_PATH_HIDDEN_DECL(slow_path_add_private_field); > SLOW_PATH_HIDDEN_DECL(slow_path_get_private_field); > SLOW_PATH_HIDDEN_DECL(slow_path_put_private_field); >+SLOW_PATH_HIDDEN_DECL(slow_path_check_private_brand); > > using SlowPathFunction = SlowPathReturnType(SLOW_PATH *)(ExecState*, const Instruction*); > >diff --git a/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp b/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp >index a88d31963fd..1af62f42623 100644 >--- a/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp >+++ b/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp >@@ -35,7 +35,7 @@ > > namespace JSC { > >-DirectEvalExecutable* DirectEvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, bool isArrowFunctionContext, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ) >+DirectEvalExecutable* DirectEvalExecutable::create(ExecState* exec, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement, bool isArrowFunctionContext, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ) > { > VM& vm = exec->vm(); > auto scope = DECLARE_THROW_SCOPE(vm); >@@ -46,7 +46,7 @@ DirectEvalExecutable* DirectEvalExecutable::create(ExecState* exec, const Source > return 0; > } > >- auto* executable = new (NotNull, allocateCell<DirectEvalExecutable>(vm.heap)) DirectEvalExecutable(exec, source, isInStrictContext, derivedContextType, classFieldsInitializer, isArrowFunctionContext, evalContextType); >+ auto* executable = new (NotNull, allocateCell<DirectEvalExecutable>(vm.heap)) DirectEvalExecutable(exec, source, isInStrictContext, derivedContextType, classFieldsInitializer, privateBrandRequirement, isArrowFunctionContext, evalContextType); > executable->finishCreation(vm); > > ParserError error; >@@ -70,11 +70,12 @@ DirectEvalExecutable* DirectEvalExecutable::create(ExecState* exec, const Source > return executable; > } > >-DirectEvalExecutable::DirectEvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, bool isArrowFunctionContext, EvalContextType evalContextType) >+DirectEvalExecutable::DirectEvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, ClassFieldsInitializer classFieldsInitializer, PrivateBrandRequirement privateBrandRequirement, bool isArrowFunctionContext, EvalContextType evalContextType) > : EvalExecutable(exec, source, inStrictContext, derivedContextType, isArrowFunctionContext, evalContextType) > { >- ASSERT(classFieldsInitializer == ClassFieldsInitializer::NotNeeded || derivedContextType == DerivedContextType::DerivedConstructorContext); >+ ASSERT((classFieldsInitializer == ClassFieldsInitializer::NotNeeded && privateBrandRequirement == PrivateBrandRequirement::None) || derivedContextType == DerivedContextType::DerivedConstructorContext); > m_classFieldsInitializer = static_cast<unsigned>(classFieldsInitializer); >+ m_privateBrandRequirement = static_cast<unsigned>(privateBrandRequirement); > } > > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/DirectEvalExecutable.h b/Source/JavaScriptCore/runtime/DirectEvalExecutable.h >index 35208a7e6b5..51b67b577f9 100644 >--- a/Source/JavaScriptCore/runtime/DirectEvalExecutable.h >+++ b/Source/JavaScriptCore/runtime/DirectEvalExecutable.h >@@ -31,10 +31,10 @@ namespace JSC { > > class DirectEvalExecutable final : public EvalExecutable { > public: >- static DirectEvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, DerivedContextType, ClassFieldsInitializer, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*); >+ static DirectEvalExecutable* create(ExecState*, const SourceCode&, bool isInStrictContext, DerivedContextType, ClassFieldsInitializer, PrivateBrandRequirement, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*); > > private: >- DirectEvalExecutable(ExecState*, const SourceCode&, bool inStrictContext, DerivedContextType, ClassFieldsInitializer, bool isArrowFunctionContext, EvalContextType); >+ DirectEvalExecutable(ExecState*, const SourceCode&, bool inStrictContext, DerivedContextType, ClassFieldsInitializer, PrivateBrandRequirement, bool isArrowFunctionContext, EvalContextType); > }; > > static_assert(sizeof(DirectEvalExecutable) == sizeof(EvalExecutable), ""); >diff --git a/Source/JavaScriptCore/runtime/EvalExecutable.h b/Source/JavaScriptCore/runtime/EvalExecutable.h >index 7fbea7b7c05..4325af32dc1 100644 >--- a/Source/JavaScriptCore/runtime/EvalExecutable.h >+++ b/Source/JavaScriptCore/runtime/EvalExecutable.h >@@ -62,13 +62,14 @@ public: > > DECLARE_INFO; > >- ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), classFieldsInitializer(), isArrowFunctionContext(), false, evalContextType()); } >+ ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, PrivateBrandRequirement::None, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), classFieldsInitializer(), isArrowFunctionContext(), false, evalContextType()); } > > unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); } > unsigned numFunctionHoistingCandidates() { return m_unlinkedEvalCodeBlock->numFunctionHoistingCandidates(); } > unsigned numTopLevelFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); } > bool allowDirectEvalCache() const { return m_unlinkedEvalCodeBlock->allowDirectEvalCache(); } > ClassFieldsInitializer classFieldsInitializer() const { return static_cast<ClassFieldsInitializer>(m_classFieldsInitializer); } >+ PrivateBrandRequirement privateBrandRequirement() const { return static_cast<PrivateBrandRequirement>(m_privateBrandRequirement); } > TemplateObjectMap& ensureTemplateObjectMap(VM&); > > protected: >@@ -81,6 +82,7 @@ protected: > static void visitChildren(JSCell*, SlotVisitor&); > > unsigned m_classFieldsInitializer : 1; >+ unsigned m_privateBrandRequirement : 1; > > WriteBarrier<ExecutableToCodeBlockEdge> m_evalCodeBlock; > WriteBarrier<UnlinkedEvalCodeBlock> m_unlinkedEvalCodeBlock; >diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp >index 3c045364491..d13f9fcf13f 100644 >--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp >+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp >@@ -268,6 +268,12 @@ static EncodedJSValue JSC_HOST_CALL hasOwnLengthProperty(ExecState* exec) > return JSValue::encode(jsBoolean(target->hasOwnProperty(exec, vm.propertyNames->length))); > } > >+static EncodedJSValue JSC_HOST_CALL createPrivateSymbol(ExecState* exec) >+{ >+ VM& vm = exec->vm(); >+ return JSValue::encode(Symbol::create(vm, PrivateSymbolImpl::createNullSymbol())); >+} >+ > #if !ASSERT_DISABLED > static EncodedJSValue JSC_HOST_CALL assertCall(ExecState* exec) > { >@@ -1028,6 +1034,9 @@ putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Construct > GlobalPropertyInfo(vm.propertyNames->builtinNames().makeBoundFunctionPrivateName(), JSFunction::create(vm, this, 5, String(), makeBoundFunction), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), > GlobalPropertyInfo(vm.propertyNames->builtinNames().hasOwnLengthPropertyPrivateName(), JSFunction::create(vm, this, 1, String(), hasOwnLengthProperty), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), > >+ // PrivateSymbol creation >+ GlobalPropertyInfo(vm.propertyNames->builtinNames().createPrivateSymbolPrivateName(), JSFunction::create(vm, this, 0, String(), createPrivateSymbol), PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), >+ > // Map and Set helpers. > GlobalPropertyInfo(vm.propertyNames->builtinNames().mapBucketHeadPrivateName(), privateFuncMapBucketHead, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), > GlobalPropertyInfo(vm.propertyNames->builtinNames().mapBucketNextPrivateName(), privateFuncMapBucketNext, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly), >diff --git a/Source/JavaScriptCore/runtime/JSScope.cpp b/Source/JavaScriptCore/runtime/JSScope.cpp >index ed2a9a2a6b0..9171dbaac3a 100644 >--- a/Source/JavaScriptCore/runtime/JSScope.cpp >+++ b/Source/JavaScriptCore/runtime/JSScope.cpp >@@ -341,8 +341,13 @@ void JSScope::collectClosureVariablesUnderTDZ(JSScope* scope, VariableEnvironmen > result.add(iter->key); > if (symbolTable->hasPrivateNames()) { > auto privateNames = symbolTable->privateNames(); >- for (auto end = privateNames.end(), iter = privateNames.begin(); iter != end; ++iter) >- result.usePrivateName(*iter); >+ for (auto end = privateNames.end(), iter = privateNames.begin(); iter != end; ++iter) { >+ if (iter->value.isPrivateAccess()) { >+ auto addResult = result.addPrivateName(iter->key); >+ addResult.iterator->value = iter->value; >+ } else >+ result.usePrivateName(iter->key); >+ } > } > } > } >diff --git a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h >index 8872b88da53..e8f0a05498d 100644 >--- a/Source/JavaScriptCore/runtime/JSSymbolTableObject.h >+++ b/Source/JavaScriptCore/runtime/JSSymbolTableObject.h >@@ -42,7 +42,7 @@ public: > static const unsigned StructureFlags = Base::StructureFlags | OverridesGetPropertyNames; > > SymbolTable* symbolTable() const { return m_symbolTable.get(); } >- >+ > JS_EXPORT_PRIVATE static bool deleteProperty(JSCell*, ExecState*, PropertyName); > JS_EXPORT_PRIVATE static void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode); > >@@ -81,8 +81,8 @@ protected: > m_symbolTable.set(vm, this, symbolTable); > if (symbolTable->hasPrivateNames()) { > m_rareData = std::make_unique<JSSymbolTableObjectRareData>(); >- for (auto key : symbolTable->privateNames()) >- m_rareData->m_privateNames.set(key.get(), PrivateSymbolImpl::create(*key.get())); >+ for (auto entry : symbolTable->privateNames()) >+ m_rareData->m_privateNames.set(entry.key.get(), PrivateSymbolImpl::create(*entry.key.get())); > } > } > >diff --git a/Source/JavaScriptCore/runtime/ModuleProgramExecutable.h b/Source/JavaScriptCore/runtime/ModuleProgramExecutable.h >index 859e1c1d2e1..0103678592c 100644 >--- a/Source/JavaScriptCore/runtime/ModuleProgramExecutable.h >+++ b/Source/JavaScriptCore/runtime/ModuleProgramExecutable.h >@@ -64,7 +64,7 @@ public: > > DECLARE_INFO; > >- ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Module, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, derivedContextType(), ClassFieldsInitializer::NotNeeded, isArrowFunctionContext(), false, EvalContextType::None); } >+ ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, PrivateBrandRequirement::None, false, ConstructorKind::None, JSParserScriptMode::Module, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, derivedContextType(), ClassFieldsInitializer::NotNeeded, isArrowFunctionContext(), false, EvalContextType::None); } > > UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); } > >diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h >index 4d3e925455b..f3bfa043d0c 100644 >--- a/Source/JavaScriptCore/runtime/Options.h >+++ b/Source/JavaScriptCore/runtime/Options.h >@@ -522,6 +522,7 @@ constexpr bool enableWebAssemblyStreamingApi = false; > v(double, dumpJITMemoryFlushInterval, 10, Restricted, "Maximum time in between flushes of the JIT memory dump in seconds.") \ > v(bool, useUnlinkedCodeBlockJettisoning, false, Normal, "If true, UnlinkedCodeBlock can be jettisoned.") \ > v(bool, useClassFields, true, Normal, "If true, the parser will understand data fields inside classes.") \ >+ v(bool, usePrivateMethods, true, Normal, "If true, the parser will understand private methods and accessors. This requires useClassFeilds to be true.") \ > > enum OptionEquivalence { > SameOption, >diff --git a/Source/JavaScriptCore/runtime/ProgramExecutable.h b/Source/JavaScriptCore/runtime/ProgramExecutable.h >index 23639570d76..68eec6ff6a8 100644 >--- a/Source/JavaScriptCore/runtime/ProgramExecutable.h >+++ b/Source/JavaScriptCore/runtime/ProgramExecutable.h >@@ -71,7 +71,7 @@ public: > > DECLARE_INFO; > >- ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), ClassFieldsInitializer::NotNeeded, isArrowFunctionContext(), false, EvalContextType::None); } >+ ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, PrivateBrandRequirement::None, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), ClassFieldsInitializer::NotNeeded, isArrowFunctionContext(), false, EvalContextType::None); } > > TemplateObjectMap& ensureTemplateObjectMap(VM&); > >diff --git a/Source/JavaScriptCore/runtime/Symbol.cpp b/Source/JavaScriptCore/runtime/Symbol.cpp >index c8be03af825..838ba9f5a22 100644 >--- a/Source/JavaScriptCore/runtime/Symbol.cpp >+++ b/Source/JavaScriptCore/runtime/Symbol.cpp >@@ -133,4 +133,11 @@ Symbol* Symbol::create(VM& vm, SymbolImpl& uid) > return symbol; > } > >+Symbol* Symbol::createPrivate(VM& vm, PrivateSymbolImpl& uid) >+{ >+ Symbol* symbol = new (NotNull, allocateCell<Symbol>(vm.heap)) Symbol(vm, uid); >+ symbol->finishCreation(vm); >+ return symbol; >+} >+ > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/Symbol.h b/Source/JavaScriptCore/runtime/Symbol.h >index ca9942e55ae..41d71e372d9 100644 >--- a/Source/JavaScriptCore/runtime/Symbol.h >+++ b/Source/JavaScriptCore/runtime/Symbol.h >@@ -48,6 +48,7 @@ public: > static Symbol* create(VM&); > static Symbol* createWithDescription(VM&, const String&); > JS_EXPORT_PRIVATE static Symbol* create(VM&, SymbolImpl& uid); >+ static Symbol* createPrivate(VM&, PrivateSymbolImpl& uid); > > PrivateName privateName() const { return m_privateName; } > String descriptiveString() const; >diff --git a/Source/JavaScriptCore/runtime/SymbolTable.cpp b/Source/JavaScriptCore/runtime/SymbolTable.cpp >index de0719c8546..68968e9b4ae 100644 >--- a/Source/JavaScriptCore/runtime/SymbolTable.cpp >+++ b/Source/JavaScriptCore/runtime/SymbolTable.cpp >@@ -185,7 +185,7 @@ SymbolTable* SymbolTable::cloneScopePart(VM& vm) > auto iter = m_rareData->m_privateNames.begin(); > auto end = m_rareData->m_privateNames.end(); > for (; iter != end; ++iter) >- result->m_rareData->m_privateNames.add(*iter); >+ result->m_rareData->m_privateNames.add(iter->key, iter->value); > } > } > >diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h >index 90bad373e5e..e3bf1a2d759 100644 >--- a/Source/JavaScriptCore/runtime/SymbolTable.h >+++ b/Source/JavaScriptCore/runtime/SymbolTable.h >@@ -35,6 +35,7 @@ > #include "ScopedArgumentsTable.h" > #include "TypeLocation.h" > #include "VarOffset.h" >+#include "VariableEnvironment.h" > #include "Watchpoint.h" > #include <memory> > #include <wtf/HashTraits.h> >@@ -448,8 +449,7 @@ public: > typedef HashMap<RefPtr<UniquedStringImpl>, RefPtr<TypeSet>, IdentifierRepHash> UniqueTypeSetMap; > typedef HashMap<VarOffset, RefPtr<UniquedStringImpl>> OffsetToVariableMap; > typedef Vector<SymbolTableEntry*> LocalToEntryVec; >- typedef HashSet<RefPtr<UniquedStringImpl>, StringRepHash> PrivateNameSet; >- typedef WTF::IteratorRange<typename PrivateNameSet::iterator> PrivateNameIteratorRange; >+ typedef WTF::IteratorRange<typename VariableEnvironment::PrivateNames::iterator> PrivateNameIteratorRange; > > template<typename CellType, SubspaceAccess> > static IsoSubspace* subspaceFor(VM& vm) >@@ -598,7 +598,7 @@ public: > bool hasPrivateNames() const { return m_rareData && m_rareData->m_privateNames.size(); } > ALWAYS_INLINE PrivateNameIteratorRange privateNames() > { >- PrivateNameSet::iterator begin, end; >+ VariableEnvironment::PrivateNames::iterator begin, end; > if (m_rareData) { > begin = m_rareData->m_privateNames.begin(); > end = m_rareData->m_privateNames.end(); >@@ -606,14 +606,14 @@ public: > return PrivateNameIteratorRange(begin, end); > } > >- void addPrivateName(UniquedStringImpl* key) >+ void addPrivateName(const RefPtr<UniquedStringImpl>& key, PrivateNameEntry value) > { > ASSERT(key && !key->isSymbol()); > if (!m_rareData) > m_rareData = std::make_unique<SymbolTableRareData>(); > >- ASSERT(!m_rareData->m_privateNames.contains(key)); >- m_rareData->m_privateNames.add(key); >+ ASSERT(m_rareData->m_privateNames.find(key) == m_rareData->m_privateNames.end()); >+ m_rareData->m_privateNames.add(key, value); > } > > template<typename Entry> >@@ -744,7 +744,7 @@ public: > OffsetToVariableMap m_offsetToVariableMap; > UniqueTypeSetMap m_uniqueTypeSetMap; > WriteBarrier<CodeBlock> m_codeBlock; >- PrivateNameSet m_privateNames; >+ VariableEnvironment::PrivateNames m_privateNames; > }; > > private:
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 194434
:
370694
|
373050
|
380859
|
390683
|
393477
|
408191
|
411896
|
411978
|
412125
|
413292
|
413857
|
415781
|
417378
|
417999
|
418748
|
418881
|
418888
|
418929
|
419624
|
419630
|
419714