haikuwebkit/Source/JavaScriptCore/runtime/DirectEvalExecutable.h

42 lines
2.1 KiB
C
Raw Permalink Normal View History

JSC should distinguish between local and global eval https://bugs.webkit.org/show_bug.cgi?id=164628 Reviewed by Saam Barati. Local use of the 'eval' keyword and invocation of the global window.eval function are distinct operations in JavaScript. This patch splits out LocalEvalExecutable vs GlobalEvalExecutable in order to help distinguish these operations in code. Our code used to do some silly things for lack of distinguishing these cases. For example, it would double cache local eval in CodeCache and EvalCodeCache. This made CodeCache seem more complicated than it really was. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: Added some files. * bytecode/CodeBlock.h: * bytecode/EvalCodeCache.h: (JSC::EvalCodeCache::tryGet): (JSC::EvalCodeCache::set): (JSC::EvalCodeCache::getSlow): Deleted. Moved code generation out of the cache to avoid tight coupling. Now the cache just caches. * bytecode/UnlinkedEvalCodeBlock.h: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::fromGlobalCode): * bytecode/UnlinkedModuleProgramCodeBlock.h: * bytecode/UnlinkedProgramCodeBlock.h: * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): Updated for interface changes. * interpreter/Interpreter.cpp: (JSC::eval): Moved code generation here so the cache didn't need to build it in. * llint/LLIntOffsetsExtractor.cpp: * runtime/CodeCache.cpp: (JSC::CodeCache::getUnlinkedGlobalCodeBlock): No need to check for TDZ variables any more. We only cache global programs, and global variable access always does TDZ checks. (JSC::CodeCache::getUnlinkedProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalEvalCodeBlock): (JSC::CodeCache::getUnlinkedModuleProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): (JSC::CodeCache::CodeCache): Deleted. (JSC::CodeCache::~CodeCache): Deleted. (JSC::CodeCache::getGlobalCodeBlock): Deleted. (JSC::CodeCache::getProgramCodeBlock): Deleted. (JSC::CodeCache::getEvalCodeBlock): Deleted. (JSC::CodeCache::getModuleProgramCodeBlock): Deleted. (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Deleted. * runtime/CodeCache.h: (JSC::CodeCache::clear): (JSC::generateUnlinkedCodeBlock): Moved unlinked code block creation out of the CodeCache class and into a stand-alone function because we need it for local eval, which does not live in CodeCache. * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::create): Deleted. * runtime/EvalExecutable.h: (): Deleted. * runtime/GlobalEvalExecutable.cpp: Added. (JSC::GlobalEvalExecutable::create): (JSC::GlobalEvalExecutable::GlobalEvalExecutable): * runtime/GlobalEvalExecutable.h: Added. * runtime/LocalEvalExecutable.cpp: Added. (JSC::LocalEvalExecutable::create): (JSC::LocalEvalExecutable::LocalEvalExecutable): * runtime/LocalEvalExecutable.h: Added. Split out Local vs Global EvalExecutable classes to distinguish these operations in code. The key difference is that LocalEvalExecutable does not live in the CodeCache and only lives in the EvalCodeCache. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::createProgramCodeBlock): (JSC::JSGlobalObject::createLocalEvalCodeBlock): (JSC::JSGlobalObject::createGlobalEvalCodeBlock): (JSC::JSGlobalObject::createModuleProgramCodeBlock): (JSC::JSGlobalObject::createEvalCodeBlock): Deleted. * runtime/JSGlobalObject.h: * runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): (JSC::JSScope::collectVariablesUnderTDZ): Deleted. We don't include global lexical variables in our concept of TDZ scopes anymore. Global variable access always does TDZ checks unconditionally. So, only closure scope accesses give specific consideration to TDZ checks. * runtime/JSScope.h: Canonical link: https://commits.webkit.org/182430@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208712 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-14 22:57:12 +00:00
/*
Use IsoCellSets to track Executables with clearable code. https://bugs.webkit.org/show_bug.cgi?id=186877 Reviewed by Filip Pizlo. Here’s an example of the results that this fix may yield: 1. The workload: load cnn.com, wait for it to fully load, scroll down and up. 2. Statistics on memory touched and memory freed by VM::deleteAllCode(): Visiting Executables: Old New Number of objects visited: 70897 14264 Number of objects with deletable code: 14264 (20.1%) 14264 (100%) Number of memory pages visited: 3224 1602 Number of memory pages with deletable code: 1602 (49.7%) 1602 (100%) Visitng UnlinkedFunctionExecutables: Old New Number of objects visited: 105454 17231 Number of objects with deletable code: 42319 (20.1%) 17231 (100%) ** Number of memory pages visited: 4796 1349 Number of memory pages with deletable code: 4013 (83.7%) 1349 (100%) ** The number of objects differ because the old code only visit unlinked executables indirectly via linked executables, whereas the new behavior visit all unlinked executables with deletable code directly. This means: a. we used to not visit unlinked executables that have not been linked yet i.e. deleteAllCode() may not delete all code (especially code that is not used). b. we had to visit all linked executables to check if they of type FunctionExecutable, before going on to visit their unlinked executable, and this includes the ones that do not have deletable code. This means that we would touch more memory in the process. Both of these these issues are now fixed with the new code. This code was tested with manually inserted instrumentation to track the above statistics. It is not feasible to write an automated test for this without leaving a lot of invasive instrumentation in the code. * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor): * bytecode/UnlinkedFunctionExecutable.h: * heap/CodeBlockSetInlines.h: (JSC::CodeBlockSet::iterateViaSubspaces): * heap/Heap.cpp: (JSC::Heap::deleteAllCodeBlocks): (JSC::Heap::deleteAllUnlinkedCodeBlocks): (JSC::Heap::deleteUnmarkedCompiledCode): (JSC::Heap::clearUnmarkedExecutables): Deleted. (JSC::Heap::addExecutable): Deleted. * heap/Heap.h: * runtime/DirectEvalExecutable.h: * runtime/ExecutableBase.cpp: (JSC::ExecutableBase::hasClearableCode const): - this is written based on the implementation of ExecutableBase::clearCode(). * runtime/ExecutableBase.h: * runtime/FunctionExecutable.h: * runtime/IndirectEvalExecutable.h: * runtime/ModuleProgramExecutable.h: * runtime/ProgramExecutable.h: * runtime/ScriptExecutable.cpp: (JSC::ScriptExecutable::clearCode): (JSC::ScriptExecutable::installCode): * runtime/ScriptExecutable.h: (JSC::ScriptExecutable::finishCreation): * runtime/VM.cpp: (JSC::VM::VM): * runtime/VM.h: (JSC::VM::ScriptExecutableSpaceAndSet::ScriptExecutableSpaceAndSet): (JSC::VM::ScriptExecutableSpaceAndSet::clearableCodeSetFor): (JSC::VM::forEachScriptExecutableSpace): (JSC::VM::UnlinkedFunctionExecutableSpaceAndSet::UnlinkedFunctionExecutableSpaceAndSet): (JSC::VM::UnlinkedFunctionExecutableSpaceAndSet::clearableCodeSetFor): Canonical link: https://commits.webkit.org/202139@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233039 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2018-06-21 15:09:40 +00:00
* Copyright (C) 2016-2018 Apple Inc. All rights reserved.
JSC should distinguish between local and global eval https://bugs.webkit.org/show_bug.cgi?id=164628 Reviewed by Saam Barati. Local use of the 'eval' keyword and invocation of the global window.eval function are distinct operations in JavaScript. This patch splits out LocalEvalExecutable vs GlobalEvalExecutable in order to help distinguish these operations in code. Our code used to do some silly things for lack of distinguishing these cases. For example, it would double cache local eval in CodeCache and EvalCodeCache. This made CodeCache seem more complicated than it really was. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: Added some files. * bytecode/CodeBlock.h: * bytecode/EvalCodeCache.h: (JSC::EvalCodeCache::tryGet): (JSC::EvalCodeCache::set): (JSC::EvalCodeCache::getSlow): Deleted. Moved code generation out of the cache to avoid tight coupling. Now the cache just caches. * bytecode/UnlinkedEvalCodeBlock.h: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::fromGlobalCode): * bytecode/UnlinkedModuleProgramCodeBlock.h: * bytecode/UnlinkedProgramCodeBlock.h: * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): Updated for interface changes. * interpreter/Interpreter.cpp: (JSC::eval): Moved code generation here so the cache didn't need to build it in. * llint/LLIntOffsetsExtractor.cpp: * runtime/CodeCache.cpp: (JSC::CodeCache::getUnlinkedGlobalCodeBlock): No need to check for TDZ variables any more. We only cache global programs, and global variable access always does TDZ checks. (JSC::CodeCache::getUnlinkedProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalEvalCodeBlock): (JSC::CodeCache::getUnlinkedModuleProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): (JSC::CodeCache::CodeCache): Deleted. (JSC::CodeCache::~CodeCache): Deleted. (JSC::CodeCache::getGlobalCodeBlock): Deleted. (JSC::CodeCache::getProgramCodeBlock): Deleted. (JSC::CodeCache::getEvalCodeBlock): Deleted. (JSC::CodeCache::getModuleProgramCodeBlock): Deleted. (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Deleted. * runtime/CodeCache.h: (JSC::CodeCache::clear): (JSC::generateUnlinkedCodeBlock): Moved unlinked code block creation out of the CodeCache class and into a stand-alone function because we need it for local eval, which does not live in CodeCache. * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::create): Deleted. * runtime/EvalExecutable.h: (): Deleted. * runtime/GlobalEvalExecutable.cpp: Added. (JSC::GlobalEvalExecutable::create): (JSC::GlobalEvalExecutable::GlobalEvalExecutable): * runtime/GlobalEvalExecutable.h: Added. * runtime/LocalEvalExecutable.cpp: Added. (JSC::LocalEvalExecutable::create): (JSC::LocalEvalExecutable::LocalEvalExecutable): * runtime/LocalEvalExecutable.h: Added. Split out Local vs Global EvalExecutable classes to distinguish these operations in code. The key difference is that LocalEvalExecutable does not live in the CodeCache and only lives in the EvalCodeCache. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::createProgramCodeBlock): (JSC::JSGlobalObject::createLocalEvalCodeBlock): (JSC::JSGlobalObject::createGlobalEvalCodeBlock): (JSC::JSGlobalObject::createModuleProgramCodeBlock): (JSC::JSGlobalObject::createEvalCodeBlock): Deleted. * runtime/JSGlobalObject.h: * runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): (JSC::JSScope::collectVariablesUnderTDZ): Deleted. We don't include global lexical variables in our concept of TDZ scopes anymore. Global variable access always does TDZ checks unconditionally. So, only closure scope accesses give specific consideration to TDZ checks. * runtime/JSScope.h: Canonical link: https://commits.webkit.org/182430@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208712 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-14 22:57:12 +00:00
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "EvalExecutable.h"
namespace JSC {
class DirectEvalExecutable final : public EvalExecutable {
public:
[ESNext] Implement private methods https://bugs.webkit.org/show_bug.cgi?id=194434 Reviewed by Filip Pizlo. JSTests: * stress/private-brand-installed-after-super-call-from-arrow-function.js: Added. * stress/private-brand-installed-after-super-call-from-eval.js: Added. * stress/private-method-brand-check.js: Added. * stress/private-method-change-attribute-from-branded-structure.js: Added. * stress/private-method-change-prototype-from-branded-structure.js: Added. * stress/private-method-check-private-brand-ic.js: Added. * stress/private-method-check-structure-miss.js: Added. * stress/private-method-comparison.js: Added. * stress/private-method-delete-property-from-branded-structure.js: Added. * stress/private-method-extends-brand-check.js: Added. * stress/private-method-get-and-call.js: Added. * stress/private-method-invalid-multiple-brand-installation.js: Added. * stress/private-method-invalidate-compiled-with-constant-symbol.js: Added. * stress/private-method-nested-class.js: Added. * stress/private-method-on-sealed-objects.js: Added. * stress/private-method-on-uncacheable-dictionary.js: Added. * stress/private-method-polymorphic-with-constant-symbol.js: Added. * stress/private-method-set-brand-should-have-write-barrier.js: Added. * stress/private-method-untyped-use.js: Added. * stress/private-method-with-uncacheable-dictionary-transition.js: Added. * stress/private-methods-inline-cache.js: Added. * stress/private-methods-megamorphic-ic.js: Added. * stress/private-methods-on-proxy.js: Added. * stress/private-methods-poly-ic-multiple-classes.js: Added. * stress/private-methods-poly-ic-single-class.js: Added. * stress/private-names-available-on-direct-eval.js: Added. * test262/config.yaml: Source/JavaScriptCore: 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: ``` { // class lexical scope const @privateBrand = @createPrivateSymbol(); const #m = function () { return 3; } C.prototype.method = function() { @check_private_brand(this, @privateBrand); return #m.call(this); } C = function() { @set_private_brand(this, @privateBrand); } } let c = new C(); console.log(c.method()); // prints 3 ``` # Resolving correct brand to 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 o.#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: ``` mov loc9, arg1 resolve_scope loc10, "#m" get_from_scope loc11, loc10, "@privateBrand" check_private_brand loc9, loc11 get_from_scope loc11, loc10, "#m" // setup call frame call loc11, ... // ... ``` # Brand check mechanism We are introducing in this patch 2 new bytecodes to allow brand check of objects: `op_set_brand` and `op_check_brand`. `op_set_brand` sets a new brand in an object, so we can perform the brand check later when accessing private methods. This operations throws when trying to add the same brand twice in an Object. `op_check_brand` checks if the given object contains the brand we are looking for. It traverses the brand chain to verify if the brand is present, and throws `TypeError` otherwise. We are also introducing a subclass for Structure called BrandedStructure. It is used to store brands and to allow brand check mechanism. BrandedStructure stores a brand and a parent pointer to another BrandedStructure that allow us traverse the brand chain. With `BrandedStructure`, we can then infer that a given object has the brand we are looking for just checking its structureId. This is a very good optimization, since we can reduce most of brand checks to structure checks. We created a new kind of transition called `SetBrand` that happens when `op_set_brand` is executed. This allow us to cache such kind of trasitions on trasition table using the key `<brand->uid, 0, TransitionKind::SetBrand>`. During this transition, we take previous structure and apply one of the following rules: 1. If it's a BrandedStructure, we then set it to `m_parentBrand`, to allow proper brand chain check. 2. If it's not a BrandedStructure, we set `m_parentBrand` to `nullptr`, meaning that this is the first brand being added to the object with this structure. For now, we are using the flag `isBrandedStructure` to identify that a given Structure is a BrandedStructure. This is done to avoid changes on places where we are checking for `vm.structureStructure()`. However, if we ever need space on Structure, this flag is a good candidate to be deleted and we can move to a solution that uses `vm.brandedStructureStructure()`; # JIT Support This patch also includes initial JIT support for `set_private_brand` and `check_private_brand`. On Baseline JIT, we are using `JITPravateBrandAccessGenerator` to support IC for both operands. On `DFGByteCodeParser` we are trying to inline brand access whenever possible, and fallbacking to `SetPrivateBrand` and `CheckPrivateBrand` otherwise. Those nodes are not being optimized at their full potential, but the code generated by them is also relying on `JITPrivateBrandAccessGenerator` to have IC support for both DFG and FTL. During DFG parsing, we try to reduce those access to `CheckIsConstant` and `CheckStructure` (with `PutStructure` for `set_private_brand` cases) based on available profiled data. This is meant to make brand checks almost free on DFG/FTL tiers when we have a single evaluation of a class, since the `CheckIsConstant` can be eliminated by the constant-folded scope load, and the `CheckStructure` is very likely to be redundant to any other `CheckStructure` that can be performed on receiver when we have a finite structure set. For instance, when we have a brand check on a path-of-no-return to a `GetByOffset` sequence on the same receiver, the `CheckStructure` for the brand check will enable CSE of the `CheckStructure` that would happen for that `GetByOffset`. Such design is possible because brand checks supports polymorphic access very similr to what we have for `GetByOffset` sequences. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * 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 `@privateBrand` that we use to store private brand on class's scope. * bytecode/AccessCase.cpp: (JSC::AccessCase::createCheckPrivateBrand): (JSC::AccessCase::createSetPrivateBrand): (JSC::AccessCase::requiresIdentifierNameMatch const): (JSC::AccessCase::requiresInt32PropertyCheck const): (JSC::AccessCase::needsScratchFPR const): (JSC::AccessCase::forEachDependentCell const): (JSC::AccessCase::doesCalls const): (JSC::AccessCase::canReplace const): (JSC::AccessCase::dump const): (JSC::AccessCase::generateWithGuard): (JSC::AccessCase::generateImpl): * bytecode/AccessCase.h: (JSC::AccessCase::structure const): (JSC::AccessCase::newStructure const): * bytecode/BytecodeList.rb: * bytecode/BytecodeUseDef.cpp: (JSC::computeUsesForBytecodeIndexImpl): (JSC::computeDefsForBytecodeIndexImpl): * bytecode/CheckPrivateBrandStatus.cpp: Added. (JSC::CheckPrivateBrandStatus::appendVariant): (JSC::CheckPrivateBrandStatus::computeForBaseline): (JSC::CheckPrivateBrandStatus::CheckPrivateBrandStatus): (JSC::CheckPrivateBrandStatus::computeForStubInfoWithoutExitSiteFeedback): (JSC::CheckPrivateBrandStatus::computeFor): (JSC::CheckPrivateBrandStatus::slowVersion const): (JSC::CheckPrivateBrandStatus::merge): (JSC::CheckPrivateBrandStatus::filter): (JSC::CheckPrivateBrandStatus::singleIdentifier const): (JSC::CheckPrivateBrandStatus::visitAggregate): (JSC::CheckPrivateBrandStatus::markIfCheap): (JSC::CheckPrivateBrandStatus::finalize): (JSC::CheckPrivateBrandStatus::dump const): * bytecode/CheckPrivateBrandStatus.h: Added. * bytecode/CheckPrivateBrandVariant.cpp: Added. (JSC::CheckPrivateBrandVariant::CheckPrivateBrandVariant): (JSC::CheckPrivateBrandVariant::~CheckPrivateBrandVariant): (JSC::CheckPrivateBrandVariant::attemptToMerge): (JSC::CheckPrivateBrandVariant::markIfCheap): (JSC::CheckPrivateBrandVariant::finalize): (JSC::CheckPrivateBrandVariant::visitAggregate): (JSC::CheckPrivateBrandVariant::dump const): (JSC::CheckPrivateBrandVariant::dumpInContext const): * bytecode/CheckPrivateBrandVariant.h: Added. (JSC::CheckPrivateBrandVariant::structureSet const): (JSC::CheckPrivateBrandVariant::structureSet): (JSC::CheckPrivateBrandVariant::identifier const): (JSC::CheckPrivateBrandVariant::overlaps): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::finishCreation): (JSC::CodeBlock::finalizeLLIntInlineCaches): * bytecode/ExecutableInfo.h: (JSC::ExecutableInfo::ExecutableInfo): (JSC::ExecutableInfo::privateBrandRequirement const): * bytecode/PolymorphicAccess.cpp: (JSC::PolymorphicAccess::regenerate): (WTF::printInternal): * bytecode/RecordedStatuses.cpp: (JSC::RecordedStatuses::operator=): (JSC::RecordedStatuses::addCheckPrivateBrandStatus): (JSC::RecordedStatuses::addSetPrivateBrandStatus): (JSC::RecordedStatuses::visitAggregate): (JSC::RecordedStatuses::markIfCheap): * bytecode/RecordedStatuses.h: (JSC::RecordedStatuses::forEachVector): * bytecode/SetPrivateBrandStatus.cpp: Added. (JSC::SetPrivateBrandStatus::appendVariant): (JSC::SetPrivateBrandStatus::computeForBaseline): (JSC::SetPrivateBrandStatus::SetPrivateBrandStatus): (JSC::SetPrivateBrandStatus::computeForStubInfoWithoutExitSiteFeedback): (JSC::SetPrivateBrandStatus::computeFor): (JSC::SetPrivateBrandStatus::slowVersion const): (JSC::SetPrivateBrandStatus::merge): (JSC::SetPrivateBrandStatus::filter): (JSC::SetPrivateBrandStatus::singleIdentifier const): (JSC::SetPrivateBrandStatus::visitAggregate): (JSC::SetPrivateBrandStatus::markIfCheap): (JSC::SetPrivateBrandStatus::finalize): (JSC::SetPrivateBrandStatus::dump const): * bytecode/SetPrivateBrandStatus.h: Added. * bytecode/SetPrivateBrandVariant.cpp: Added. (JSC::SetPrivateBrandVariant::SetPrivateBrandVariant): (JSC::SetPrivateBrandVariant::~SetPrivateBrandVariant): (JSC::SetPrivateBrandVariant::attemptToMerge): (JSC::SetPrivateBrandVariant::markIfCheap): (JSC::SetPrivateBrandVariant::finalize): (JSC::SetPrivateBrandVariant::visitAggregate): (JSC::SetPrivateBrandVariant::dump const): (JSC::SetPrivateBrandVariant::dumpInContext const): * bytecode/SetPrivateBrandVariant.h: Added. (JSC::SetPrivateBrandVariant::oldStructure const): (JSC::SetPrivateBrandVariant::newStructure const): (JSC::SetPrivateBrandVariant::identifier const): (JSC::SetPrivateBrandVariant::overlaps): * bytecode/StructureStubInfo.cpp: (JSC::StructureStubInfo::reset): * bytecode/StructureStubInfo.h: * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::privateBrandRequirement const): * bytecode/UnlinkedCodeBlockGenerator.h: (JSC::UnlinkedCodeBlockGenerator::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 PrivateNameEnvironment. These environments stores private name entries that are visible into the scope of the function/eval. 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. (JSC::BytecodeGenerator::instantiateLexicalVariables): (JSC::BytecodeGenerator::emitGetPrivateName): (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): We added `m_privateNamesStack` to BytecodeGenerator to represent the scope chain of available private names while generating bytecode. (JSC::BytecodeGenerator::emitCheckPrivateBrand): (JSC::BytecodeGenerator::isPrivateMethod): (JSC::BytecodeGenerator::pushPrivateAccessNames): (JSC::BytecodeGenerator::popPrivateAccessNames): (JSC::BytecodeGenerator::getAvailablePrivateAccessNames): (JSC::BytecodeGenerator::emitNewDefaultConstructor): (JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction): (JSC::BytecodeGenerator::emitDirectGetByVal): Deleted. * bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::privateBrandRequirement const): (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::makeFunction): This change is required to properly propagate PrivateBrandRequirement to arrow functions that can potentially call `super()`. * bytecompiler/NodesCodegen.cpp: (JSC::PropertyListNode::emitDeclarePrivateFieldNames): (JSC::PropertyListNode::emitBytecode): (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. (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::PostfixNode::emitDot): (JSC::PrefixNode::emitDot): (JSC::ClassExprNode::emitBytecode): * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterICStatus): * dfg/DFGArgumentsEliminationPhase.cpp: * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGCapabilities.cpp: (JSC::DFG::capabilityLevel): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGClobbersExitState.cpp: (JSC::DFG::clobbersExitState): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.h: * dfg/DFGJITCompiler.cpp: (JSC::DFG::JITCompiler::link): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addPrivateBrandAccess): * dfg/DFGMayExit.cpp: * dfg/DFGNode.h: (JSC::DFG::Node::hasCheckPrivateBrandStatus): (JSC::DFG::Node::checkPrivateBrandStatus): (JSC::DFG::Node::hasSetPrivateBrandStatus): (JSC::DFG::Node::setPrivateBrandStatus): * dfg/DFGNodeType.h: * dfg/DFGObjectAllocationSinkingPhase.cpp: * dfg/DFGPredictionPropagationPhase.cpp: * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileCheckPrivateBrand): (JSC::DFG::SpeculativeJIT::compileSetPrivateBrand): * dfg/DFGSpeculativeJIT.h: * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGStoreBarrierInsertionPhase.cpp: * dfg/DFGVarargsForwardingPhase.cpp: * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compilePrivateBrandAccess): (JSC::FTL::DFG::LowerDFGToB3::compileCheckPrivateBrand): (JSC::FTL::DFG::LowerDFGToB3::compileSetPrivateBrand): * interpreter/Interpreter.cpp: (JSC::eval): * jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases): (JSC::JIT::link): * jit/JIT.h: * jit/JITInlineCacheGenerator.cpp: (JSC::JITPrivateBrandAccessGenerator::JITPrivateBrandAccessGenerator): (JSC::JITPrivateBrandAccessGenerator::generateFastPath): (JSC::JITPrivateBrandAccessGenerator::finalize): * jit/JITInlineCacheGenerator.h: (JSC::JITPrivateBrandAccessGenerator::JITPrivateBrandAccessGenerator): (JSC::JITPrivateBrandAccessGenerator::slowPathJump const): * jit/JITOperations.cpp: (JSC::JSC_DEFINE_JIT_OPERATION): (JSC::getPrivateName): * jit/JITOperations.h: * jit/JITPropertyAccess.cpp: (JSC::JIT::emit_op_set_private_brand): (JSC::JIT::emitSlow_op_set_private_brand): (JSC::JIT::emit_op_check_private_brand): (JSC::JIT::emitSlow_op_check_private_brand): * jit/JITPropertyAccess32_64.cpp: (JSC::JIT::emit_op_set_private_brand): (JSC::JIT::emitSlow_op_set_private_brand): (JSC::JIT::emit_op_check_private_brand): (JSC::JIT::emitSlow_op_check_private_brand): * jit/Repatch.cpp: (JSC::tryCacheCheckPrivateBrand): (JSC::repatchCheckPrivateBrand): (JSC::tryCacheSetPrivateBrand): (JSC::repatchSetPrivateBrand): (JSC::resetCheckPrivateBrand): (JSC::resetSetPrivateBrand): * jit/Repatch.h: * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LLIntSlowPaths.h: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * parser/Nodes.cpp: (JSC::FunctionMetadataNode::FunctionMetadataNode): * parser/Nodes.h: (JSC::BaseDotNode::isPrivateMember const): (JSC::BaseDotNode::isPrivateField const): Deleted. * parser/Parser.cpp: (JSC::Parser<LexerType>::parseClass): (JSC::Parser<LexerType>::parseMemberExpression): * parser/Parser.h: (JSC::Scope::declarePrivateMethod): (JSC::Scope::declarePrivateField): (JSC::Parser<LexerType>::parse): (JSC::parse): (JSC::Scope::declarePrivateName): Deleted. * parser/ParserModes.h: * parser/SyntaxChecker.h: (JSC::SyntaxChecker::createDotAccess): * parser/VariableEnvironment.cpp: (JSC::VariableEnvironment::declarePrivateMethod): * parser/VariableEnvironment.h: (JSC::VariableEnvironmentEntry::isPrivateField const): (JSC::VariableEnvironmentEntry::isPrivateMethod const): (JSC::VariableEnvironmentEntry::setIsPrivateField): (JSC::VariableEnvironmentEntry::setIsPrivateMethod): (JSC::PrivateNameEntry::isMethod const): (JSC::PrivateNameEntry::isPrivateMethodOrAcessor const): (JSC::VariableEnvironment::addPrivateName): (JSC::VariableEnvironment::declarePrivateField): (JSC::VariableEnvironment::declarePrivateMethod): (JSC::VariableEnvironment::privateNameEnvironment const): (JSC::VariableEnvironment::hasPrivateMethodOrAccessor const): (JSC::VariableEnvironment::addPrivateNamesFrom): (JSC::VariableEnvironmentEntry::isPrivateName const): Deleted. (JSC::VariableEnvironmentEntry::setIsPrivateName): Deleted. (JSC::VariableEnvironment::declarePrivateName): Deleted. * runtime/CachedTypes.cpp: (JSC::CachedCodeBlockRareData::encode): (JSC::CachedCodeBlockRareData::decode const): (JSC::CachedFunctionExecutableRareData::encode): (JSC::CachedFunctionExecutableRareData::decode const): (JSC::CachedFunctionExecutable::privateBrandRequirement const): (JSC::CachedCodeBlock::derivedContextType const): (JSC::CachedFunctionExecutable::encode): (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): (JSC::CachedCodeBlock::needsClassFieldInitializer const): Deleted. * runtime/CodeCache.cpp: (JSC::generateUnlinkedCodeBlockImpl): (JSC::generateUnlinkedCodeBlock): (JSC::generateUnlinkedCodeBlockForDirectEval): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): * runtime/CodeCache.h: * runtime/DirectEvalExecutable.cpp: (JSC::DirectEvalExecutable::create): (JSC::DirectEvalExecutable::DirectEvalExecutable): * runtime/DirectEvalExecutable.h: * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::EvalExecutable): * runtime/EvalExecutable.h: (JSC::EvalExecutable::executableInfo const): (JSC::EvalExecutable::privateBrandRequirement const): * runtime/ExceptionHelpers.cpp: (JSC::createInvalidPrivateNameError): * runtime/IndirectEvalExecutable.cpp: (JSC::IndirectEvalExecutable::IndirectEvalExecutable): * runtime/JSObject.h: * runtime/JSObjectInlines.h: (JSC::JSObject::checkPrivateBrand): (JSC::JSObject::setPrivateBrand): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): * runtime/JSScope.h: * runtime/ModuleProgramExecutable.h: * runtime/Options.cpp: (JSC::Options::recomputeDependentOptions): * runtime/OptionsList.h: * runtime/ProgramExecutable.h: * runtime/Structure.cpp: (JSC::Structure::materializePropertyTable): (JSC::BrandedStructure::BrandedStructure): (JSC::BrandedStructure::create): (JSC::BrandedStructure::checkBrand): (JSC::Structure::setBrandTransitionFromExistingStructureImpl): (JSC::Structure::setBrandTransitionFromExistingStructureConcurrently): (JSC::Structure::setBrandTransition): * runtime/Structure.h: (JSC::Structure::finishCreation): * runtime/StructureInlines.h: (JSC::Structure::create): (JSC::Structure::forEachPropertyConcurrently): * runtime/StructureTransitionTable.h: * runtime/SymbolTable.cpp: (JSC::SymbolTable::cloneScopePart): * runtime/SymbolTable.h: * runtime/VM.cpp: (JSC::VM::VM): * runtime/VM.h: Canonical link: https://commits.webkit.org/233852@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@272580 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-02-09 16:30:24 +00:00
static DirectEvalExecutable* create(JSGlobalObject*, const SourceCode&, DerivedContextType, NeedsClassFieldInitializer, PrivateBrandRequirement, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType, const TDZEnvironment* parentScopeTDZVariables, const PrivateNameEnvironment*, ECMAMode);
JSC should distinguish between local and global eval https://bugs.webkit.org/show_bug.cgi?id=164628 Reviewed by Saam Barati. Local use of the 'eval' keyword and invocation of the global window.eval function are distinct operations in JavaScript. This patch splits out LocalEvalExecutable vs GlobalEvalExecutable in order to help distinguish these operations in code. Our code used to do some silly things for lack of distinguishing these cases. For example, it would double cache local eval in CodeCache and EvalCodeCache. This made CodeCache seem more complicated than it really was. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: Added some files. * bytecode/CodeBlock.h: * bytecode/EvalCodeCache.h: (JSC::EvalCodeCache::tryGet): (JSC::EvalCodeCache::set): (JSC::EvalCodeCache::getSlow): Deleted. Moved code generation out of the cache to avoid tight coupling. Now the cache just caches. * bytecode/UnlinkedEvalCodeBlock.h: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::fromGlobalCode): * bytecode/UnlinkedModuleProgramCodeBlock.h: * bytecode/UnlinkedProgramCodeBlock.h: * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): Updated for interface changes. * interpreter/Interpreter.cpp: (JSC::eval): Moved code generation here so the cache didn't need to build it in. * llint/LLIntOffsetsExtractor.cpp: * runtime/CodeCache.cpp: (JSC::CodeCache::getUnlinkedGlobalCodeBlock): No need to check for TDZ variables any more. We only cache global programs, and global variable access always does TDZ checks. (JSC::CodeCache::getUnlinkedProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalEvalCodeBlock): (JSC::CodeCache::getUnlinkedModuleProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): (JSC::CodeCache::CodeCache): Deleted. (JSC::CodeCache::~CodeCache): Deleted. (JSC::CodeCache::getGlobalCodeBlock): Deleted. (JSC::CodeCache::getProgramCodeBlock): Deleted. (JSC::CodeCache::getEvalCodeBlock): Deleted. (JSC::CodeCache::getModuleProgramCodeBlock): Deleted. (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Deleted. * runtime/CodeCache.h: (JSC::CodeCache::clear): (JSC::generateUnlinkedCodeBlock): Moved unlinked code block creation out of the CodeCache class and into a stand-alone function because we need it for local eval, which does not live in CodeCache. * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::create): Deleted. * runtime/EvalExecutable.h: (): Deleted. * runtime/GlobalEvalExecutable.cpp: Added. (JSC::GlobalEvalExecutable::create): (JSC::GlobalEvalExecutable::GlobalEvalExecutable): * runtime/GlobalEvalExecutable.h: Added. * runtime/LocalEvalExecutable.cpp: Added. (JSC::LocalEvalExecutable::create): (JSC::LocalEvalExecutable::LocalEvalExecutable): * runtime/LocalEvalExecutable.h: Added. Split out Local vs Global EvalExecutable classes to distinguish these operations in code. The key difference is that LocalEvalExecutable does not live in the CodeCache and only lives in the EvalCodeCache. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::createProgramCodeBlock): (JSC::JSGlobalObject::createLocalEvalCodeBlock): (JSC::JSGlobalObject::createGlobalEvalCodeBlock): (JSC::JSGlobalObject::createModuleProgramCodeBlock): (JSC::JSGlobalObject::createEvalCodeBlock): Deleted. * runtime/JSGlobalObject.h: * runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): (JSC::JSScope::collectVariablesUnderTDZ): Deleted. We don't include global lexical variables in our concept of TDZ scopes anymore. Global variable access always does TDZ checks unconditionally. So, only closure scope accesses give specific consideration to TDZ checks. * runtime/JSScope.h: Canonical link: https://commits.webkit.org/182430@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208712 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-14 22:57:12 +00:00
private:
[ESNext] Implement private methods https://bugs.webkit.org/show_bug.cgi?id=194434 Reviewed by Filip Pizlo. JSTests: * stress/private-brand-installed-after-super-call-from-arrow-function.js: Added. * stress/private-brand-installed-after-super-call-from-eval.js: Added. * stress/private-method-brand-check.js: Added. * stress/private-method-change-attribute-from-branded-structure.js: Added. * stress/private-method-change-prototype-from-branded-structure.js: Added. * stress/private-method-check-private-brand-ic.js: Added. * stress/private-method-check-structure-miss.js: Added. * stress/private-method-comparison.js: Added. * stress/private-method-delete-property-from-branded-structure.js: Added. * stress/private-method-extends-brand-check.js: Added. * stress/private-method-get-and-call.js: Added. * stress/private-method-invalid-multiple-brand-installation.js: Added. * stress/private-method-invalidate-compiled-with-constant-symbol.js: Added. * stress/private-method-nested-class.js: Added. * stress/private-method-on-sealed-objects.js: Added. * stress/private-method-on-uncacheable-dictionary.js: Added. * stress/private-method-polymorphic-with-constant-symbol.js: Added. * stress/private-method-set-brand-should-have-write-barrier.js: Added. * stress/private-method-untyped-use.js: Added. * stress/private-method-with-uncacheable-dictionary-transition.js: Added. * stress/private-methods-inline-cache.js: Added. * stress/private-methods-megamorphic-ic.js: Added. * stress/private-methods-on-proxy.js: Added. * stress/private-methods-poly-ic-multiple-classes.js: Added. * stress/private-methods-poly-ic-single-class.js: Added. * stress/private-names-available-on-direct-eval.js: Added. * test262/config.yaml: Source/JavaScriptCore: 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: ``` { // class lexical scope const @privateBrand = @createPrivateSymbol(); const #m = function () { return 3; } C.prototype.method = function() { @check_private_brand(this, @privateBrand); return #m.call(this); } C = function() { @set_private_brand(this, @privateBrand); } } let c = new C(); console.log(c.method()); // prints 3 ``` # Resolving correct brand to 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 o.#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: ``` mov loc9, arg1 resolve_scope loc10, "#m" get_from_scope loc11, loc10, "@privateBrand" check_private_brand loc9, loc11 get_from_scope loc11, loc10, "#m" // setup call frame call loc11, ... // ... ``` # Brand check mechanism We are introducing in this patch 2 new bytecodes to allow brand check of objects: `op_set_brand` and `op_check_brand`. `op_set_brand` sets a new brand in an object, so we can perform the brand check later when accessing private methods. This operations throws when trying to add the same brand twice in an Object. `op_check_brand` checks if the given object contains the brand we are looking for. It traverses the brand chain to verify if the brand is present, and throws `TypeError` otherwise. We are also introducing a subclass for Structure called BrandedStructure. It is used to store brands and to allow brand check mechanism. BrandedStructure stores a brand and a parent pointer to another BrandedStructure that allow us traverse the brand chain. With `BrandedStructure`, we can then infer that a given object has the brand we are looking for just checking its structureId. This is a very good optimization, since we can reduce most of brand checks to structure checks. We created a new kind of transition called `SetBrand` that happens when `op_set_brand` is executed. This allow us to cache such kind of trasitions on trasition table using the key `<brand->uid, 0, TransitionKind::SetBrand>`. During this transition, we take previous structure and apply one of the following rules: 1. If it's a BrandedStructure, we then set it to `m_parentBrand`, to allow proper brand chain check. 2. If it's not a BrandedStructure, we set `m_parentBrand` to `nullptr`, meaning that this is the first brand being added to the object with this structure. For now, we are using the flag `isBrandedStructure` to identify that a given Structure is a BrandedStructure. This is done to avoid changes on places where we are checking for `vm.structureStructure()`. However, if we ever need space on Structure, this flag is a good candidate to be deleted and we can move to a solution that uses `vm.brandedStructureStructure()`; # JIT Support This patch also includes initial JIT support for `set_private_brand` and `check_private_brand`. On Baseline JIT, we are using `JITPravateBrandAccessGenerator` to support IC for both operands. On `DFGByteCodeParser` we are trying to inline brand access whenever possible, and fallbacking to `SetPrivateBrand` and `CheckPrivateBrand` otherwise. Those nodes are not being optimized at their full potential, but the code generated by them is also relying on `JITPrivateBrandAccessGenerator` to have IC support for both DFG and FTL. During DFG parsing, we try to reduce those access to `CheckIsConstant` and `CheckStructure` (with `PutStructure` for `set_private_brand` cases) based on available profiled data. This is meant to make brand checks almost free on DFG/FTL tiers when we have a single evaluation of a class, since the `CheckIsConstant` can be eliminated by the constant-folded scope load, and the `CheckStructure` is very likely to be redundant to any other `CheckStructure` that can be performed on receiver when we have a finite structure set. For instance, when we have a brand check on a path-of-no-return to a `GetByOffset` sequence on the same receiver, the `CheckStructure` for the brand check will enable CSE of the `CheckStructure` that would happen for that `GetByOffset`. Such design is possible because brand checks supports polymorphic access very similr to what we have for `GetByOffset` sequences. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: * Sources.txt: * 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 `@privateBrand` that we use to store private brand on class's scope. * bytecode/AccessCase.cpp: (JSC::AccessCase::createCheckPrivateBrand): (JSC::AccessCase::createSetPrivateBrand): (JSC::AccessCase::requiresIdentifierNameMatch const): (JSC::AccessCase::requiresInt32PropertyCheck const): (JSC::AccessCase::needsScratchFPR const): (JSC::AccessCase::forEachDependentCell const): (JSC::AccessCase::doesCalls const): (JSC::AccessCase::canReplace const): (JSC::AccessCase::dump const): (JSC::AccessCase::generateWithGuard): (JSC::AccessCase::generateImpl): * bytecode/AccessCase.h: (JSC::AccessCase::structure const): (JSC::AccessCase::newStructure const): * bytecode/BytecodeList.rb: * bytecode/BytecodeUseDef.cpp: (JSC::computeUsesForBytecodeIndexImpl): (JSC::computeDefsForBytecodeIndexImpl): * bytecode/CheckPrivateBrandStatus.cpp: Added. (JSC::CheckPrivateBrandStatus::appendVariant): (JSC::CheckPrivateBrandStatus::computeForBaseline): (JSC::CheckPrivateBrandStatus::CheckPrivateBrandStatus): (JSC::CheckPrivateBrandStatus::computeForStubInfoWithoutExitSiteFeedback): (JSC::CheckPrivateBrandStatus::computeFor): (JSC::CheckPrivateBrandStatus::slowVersion const): (JSC::CheckPrivateBrandStatus::merge): (JSC::CheckPrivateBrandStatus::filter): (JSC::CheckPrivateBrandStatus::singleIdentifier const): (JSC::CheckPrivateBrandStatus::visitAggregate): (JSC::CheckPrivateBrandStatus::markIfCheap): (JSC::CheckPrivateBrandStatus::finalize): (JSC::CheckPrivateBrandStatus::dump const): * bytecode/CheckPrivateBrandStatus.h: Added. * bytecode/CheckPrivateBrandVariant.cpp: Added. (JSC::CheckPrivateBrandVariant::CheckPrivateBrandVariant): (JSC::CheckPrivateBrandVariant::~CheckPrivateBrandVariant): (JSC::CheckPrivateBrandVariant::attemptToMerge): (JSC::CheckPrivateBrandVariant::markIfCheap): (JSC::CheckPrivateBrandVariant::finalize): (JSC::CheckPrivateBrandVariant::visitAggregate): (JSC::CheckPrivateBrandVariant::dump const): (JSC::CheckPrivateBrandVariant::dumpInContext const): * bytecode/CheckPrivateBrandVariant.h: Added. (JSC::CheckPrivateBrandVariant::structureSet const): (JSC::CheckPrivateBrandVariant::structureSet): (JSC::CheckPrivateBrandVariant::identifier const): (JSC::CheckPrivateBrandVariant::overlaps): * bytecode/CodeBlock.cpp: (JSC::CodeBlock::finishCreation): (JSC::CodeBlock::finalizeLLIntInlineCaches): * bytecode/ExecutableInfo.h: (JSC::ExecutableInfo::ExecutableInfo): (JSC::ExecutableInfo::privateBrandRequirement const): * bytecode/PolymorphicAccess.cpp: (JSC::PolymorphicAccess::regenerate): (WTF::printInternal): * bytecode/RecordedStatuses.cpp: (JSC::RecordedStatuses::operator=): (JSC::RecordedStatuses::addCheckPrivateBrandStatus): (JSC::RecordedStatuses::addSetPrivateBrandStatus): (JSC::RecordedStatuses::visitAggregate): (JSC::RecordedStatuses::markIfCheap): * bytecode/RecordedStatuses.h: (JSC::RecordedStatuses::forEachVector): * bytecode/SetPrivateBrandStatus.cpp: Added. (JSC::SetPrivateBrandStatus::appendVariant): (JSC::SetPrivateBrandStatus::computeForBaseline): (JSC::SetPrivateBrandStatus::SetPrivateBrandStatus): (JSC::SetPrivateBrandStatus::computeForStubInfoWithoutExitSiteFeedback): (JSC::SetPrivateBrandStatus::computeFor): (JSC::SetPrivateBrandStatus::slowVersion const): (JSC::SetPrivateBrandStatus::merge): (JSC::SetPrivateBrandStatus::filter): (JSC::SetPrivateBrandStatus::singleIdentifier const): (JSC::SetPrivateBrandStatus::visitAggregate): (JSC::SetPrivateBrandStatus::markIfCheap): (JSC::SetPrivateBrandStatus::finalize): (JSC::SetPrivateBrandStatus::dump const): * bytecode/SetPrivateBrandStatus.h: Added. * bytecode/SetPrivateBrandVariant.cpp: Added. (JSC::SetPrivateBrandVariant::SetPrivateBrandVariant): (JSC::SetPrivateBrandVariant::~SetPrivateBrandVariant): (JSC::SetPrivateBrandVariant::attemptToMerge): (JSC::SetPrivateBrandVariant::markIfCheap): (JSC::SetPrivateBrandVariant::finalize): (JSC::SetPrivateBrandVariant::visitAggregate): (JSC::SetPrivateBrandVariant::dump const): (JSC::SetPrivateBrandVariant::dumpInContext const): * bytecode/SetPrivateBrandVariant.h: Added. (JSC::SetPrivateBrandVariant::oldStructure const): (JSC::SetPrivateBrandVariant::newStructure const): (JSC::SetPrivateBrandVariant::identifier const): (JSC::SetPrivateBrandVariant::overlaps): * bytecode/StructureStubInfo.cpp: (JSC::StructureStubInfo::reset): * bytecode/StructureStubInfo.h: * bytecode/UnlinkedCodeBlock.cpp: (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock): * bytecode/UnlinkedCodeBlock.h: (JSC::UnlinkedCodeBlock::privateBrandRequirement const): * bytecode/UnlinkedCodeBlockGenerator.h: (JSC::UnlinkedCodeBlockGenerator::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 PrivateNameEnvironment. These environments stores private name entries that are visible into the scope of the function/eval. 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. (JSC::BytecodeGenerator::instantiateLexicalVariables): (JSC::BytecodeGenerator::emitGetPrivateName): (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): We added `m_privateNamesStack` to BytecodeGenerator to represent the scope chain of available private names while generating bytecode. (JSC::BytecodeGenerator::emitCheckPrivateBrand): (JSC::BytecodeGenerator::isPrivateMethod): (JSC::BytecodeGenerator::pushPrivateAccessNames): (JSC::BytecodeGenerator::popPrivateAccessNames): (JSC::BytecodeGenerator::getAvailablePrivateAccessNames): (JSC::BytecodeGenerator::emitNewDefaultConstructor): (JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction): (JSC::BytecodeGenerator::emitDirectGetByVal): Deleted. * bytecompiler/BytecodeGenerator.h: (JSC::BytecodeGenerator::privateBrandRequirement const): (JSC::BytecodeGenerator::generate): (JSC::BytecodeGenerator::makeFunction): This change is required to properly propagate PrivateBrandRequirement to arrow functions that can potentially call `super()`. * bytecompiler/NodesCodegen.cpp: (JSC::PropertyListNode::emitDeclarePrivateFieldNames): (JSC::PropertyListNode::emitBytecode): (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. (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::PostfixNode::emitDot): (JSC::PrefixNode::emitDot): (JSC::ClassExprNode::emitBytecode): * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): * dfg/DFGAbstractInterpreterInlines.h: (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterICStatus): * dfg/DFGArgumentsEliminationPhase.cpp: * dfg/DFGByteCodeParser.cpp: (JSC::DFG::ByteCodeParser::parseBlock): * dfg/DFGCapabilities.cpp: (JSC::DFG::capabilityLevel): * dfg/DFGClobberize.h: (JSC::DFG::clobberize): * dfg/DFGClobbersExitState.cpp: (JSC::DFG::clobbersExitState): * dfg/DFGDoesGC.cpp: (JSC::DFG::doesGC): * dfg/DFGFixupPhase.cpp: (JSC::DFG::FixupPhase::fixupNode): * dfg/DFGGraph.h: * dfg/DFGJITCompiler.cpp: (JSC::DFG::JITCompiler::link): * dfg/DFGJITCompiler.h: (JSC::DFG::JITCompiler::addPrivateBrandAccess): * dfg/DFGMayExit.cpp: * dfg/DFGNode.h: (JSC::DFG::Node::hasCheckPrivateBrandStatus): (JSC::DFG::Node::checkPrivateBrandStatus): (JSC::DFG::Node::hasSetPrivateBrandStatus): (JSC::DFG::Node::setPrivateBrandStatus): * dfg/DFGNodeType.h: * dfg/DFGObjectAllocationSinkingPhase.cpp: * dfg/DFGPredictionPropagationPhase.cpp: * dfg/DFGSafeToExecute.h: (JSC::DFG::safeToExecute): * dfg/DFGSpeculativeJIT.cpp: (JSC::DFG::SpeculativeJIT::compileCheckPrivateBrand): (JSC::DFG::SpeculativeJIT::compileSetPrivateBrand): * dfg/DFGSpeculativeJIT.h: * dfg/DFGSpeculativeJIT32_64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGSpeculativeJIT64.cpp: (JSC::DFG::SpeculativeJIT::compile): * dfg/DFGStoreBarrierInsertionPhase.cpp: * dfg/DFGVarargsForwardingPhase.cpp: * ftl/FTLCapabilities.cpp: (JSC::FTL::canCompile): * ftl/FTLLowerDFGToB3.cpp: (JSC::FTL::DFG::LowerDFGToB3::compileNode): (JSC::FTL::DFG::LowerDFGToB3::compilePrivateBrandAccess): (JSC::FTL::DFG::LowerDFGToB3::compileCheckPrivateBrand): (JSC::FTL::DFG::LowerDFGToB3::compileSetPrivateBrand): * interpreter/Interpreter.cpp: (JSC::eval): * jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompileSlowCases): (JSC::JIT::link): * jit/JIT.h: * jit/JITInlineCacheGenerator.cpp: (JSC::JITPrivateBrandAccessGenerator::JITPrivateBrandAccessGenerator): (JSC::JITPrivateBrandAccessGenerator::generateFastPath): (JSC::JITPrivateBrandAccessGenerator::finalize): * jit/JITInlineCacheGenerator.h: (JSC::JITPrivateBrandAccessGenerator::JITPrivateBrandAccessGenerator): (JSC::JITPrivateBrandAccessGenerator::slowPathJump const): * jit/JITOperations.cpp: (JSC::JSC_DEFINE_JIT_OPERATION): (JSC::getPrivateName): * jit/JITOperations.h: * jit/JITPropertyAccess.cpp: (JSC::JIT::emit_op_set_private_brand): (JSC::JIT::emitSlow_op_set_private_brand): (JSC::JIT::emit_op_check_private_brand): (JSC::JIT::emitSlow_op_check_private_brand): * jit/JITPropertyAccess32_64.cpp: (JSC::JIT::emit_op_set_private_brand): (JSC::JIT::emitSlow_op_set_private_brand): (JSC::JIT::emit_op_check_private_brand): (JSC::JIT::emitSlow_op_check_private_brand): * jit/Repatch.cpp: (JSC::tryCacheCheckPrivateBrand): (JSC::repatchCheckPrivateBrand): (JSC::tryCacheSetPrivateBrand): (JSC::repatchSetPrivateBrand): (JSC::resetCheckPrivateBrand): (JSC::resetSetPrivateBrand): * jit/Repatch.h: * llint/LLIntSlowPaths.cpp: (JSC::LLInt::LLINT_SLOW_PATH_DECL): * llint/LLIntSlowPaths.h: * llint/LowLevelInterpreter32_64.asm: * llint/LowLevelInterpreter64.asm: * parser/Nodes.cpp: (JSC::FunctionMetadataNode::FunctionMetadataNode): * parser/Nodes.h: (JSC::BaseDotNode::isPrivateMember const): (JSC::BaseDotNode::isPrivateField const): Deleted. * parser/Parser.cpp: (JSC::Parser<LexerType>::parseClass): (JSC::Parser<LexerType>::parseMemberExpression): * parser/Parser.h: (JSC::Scope::declarePrivateMethod): (JSC::Scope::declarePrivateField): (JSC::Parser<LexerType>::parse): (JSC::parse): (JSC::Scope::declarePrivateName): Deleted. * parser/ParserModes.h: * parser/SyntaxChecker.h: (JSC::SyntaxChecker::createDotAccess): * parser/VariableEnvironment.cpp: (JSC::VariableEnvironment::declarePrivateMethod): * parser/VariableEnvironment.h: (JSC::VariableEnvironmentEntry::isPrivateField const): (JSC::VariableEnvironmentEntry::isPrivateMethod const): (JSC::VariableEnvironmentEntry::setIsPrivateField): (JSC::VariableEnvironmentEntry::setIsPrivateMethod): (JSC::PrivateNameEntry::isMethod const): (JSC::PrivateNameEntry::isPrivateMethodOrAcessor const): (JSC::VariableEnvironment::addPrivateName): (JSC::VariableEnvironment::declarePrivateField): (JSC::VariableEnvironment::declarePrivateMethod): (JSC::VariableEnvironment::privateNameEnvironment const): (JSC::VariableEnvironment::hasPrivateMethodOrAccessor const): (JSC::VariableEnvironment::addPrivateNamesFrom): (JSC::VariableEnvironmentEntry::isPrivateName const): Deleted. (JSC::VariableEnvironmentEntry::setIsPrivateName): Deleted. (JSC::VariableEnvironment::declarePrivateName): Deleted. * runtime/CachedTypes.cpp: (JSC::CachedCodeBlockRareData::encode): (JSC::CachedCodeBlockRareData::decode const): (JSC::CachedFunctionExecutableRareData::encode): (JSC::CachedFunctionExecutableRareData::decode const): (JSC::CachedFunctionExecutable::privateBrandRequirement const): (JSC::CachedCodeBlock::derivedContextType const): (JSC::CachedFunctionExecutable::encode): (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): (JSC::CachedCodeBlock::needsClassFieldInitializer const): Deleted. * runtime/CodeCache.cpp: (JSC::generateUnlinkedCodeBlockImpl): (JSC::generateUnlinkedCodeBlock): (JSC::generateUnlinkedCodeBlockForDirectEval): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): * runtime/CodeCache.h: * runtime/DirectEvalExecutable.cpp: (JSC::DirectEvalExecutable::create): (JSC::DirectEvalExecutable::DirectEvalExecutable): * runtime/DirectEvalExecutable.h: * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::EvalExecutable): * runtime/EvalExecutable.h: (JSC::EvalExecutable::executableInfo const): (JSC::EvalExecutable::privateBrandRequirement const): * runtime/ExceptionHelpers.cpp: (JSC::createInvalidPrivateNameError): * runtime/IndirectEvalExecutable.cpp: (JSC::IndirectEvalExecutable::IndirectEvalExecutable): * runtime/JSObject.h: * runtime/JSObjectInlines.h: (JSC::JSObject::checkPrivateBrand): (JSC::JSObject::setPrivateBrand): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): * runtime/JSScope.h: * runtime/ModuleProgramExecutable.h: * runtime/Options.cpp: (JSC::Options::recomputeDependentOptions): * runtime/OptionsList.h: * runtime/ProgramExecutable.h: * runtime/Structure.cpp: (JSC::Structure::materializePropertyTable): (JSC::BrandedStructure::BrandedStructure): (JSC::BrandedStructure::create): (JSC::BrandedStructure::checkBrand): (JSC::Structure::setBrandTransitionFromExistingStructureImpl): (JSC::Structure::setBrandTransitionFromExistingStructureConcurrently): (JSC::Structure::setBrandTransition): * runtime/Structure.h: (JSC::Structure::finishCreation): * runtime/StructureInlines.h: (JSC::Structure::create): (JSC::Structure::forEachPropertyConcurrently): * runtime/StructureTransitionTable.h: * runtime/SymbolTable.cpp: (JSC::SymbolTable::cloneScopePart): * runtime/SymbolTable.h: * runtime/VM.cpp: (JSC::VM::VM): * runtime/VM.h: Canonical link: https://commits.webkit.org/233852@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@272580 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2021-02-09 16:30:24 +00:00
DirectEvalExecutable(JSGlobalObject*, const SourceCode&, bool inStrictContext, DerivedContextType, NeedsClassFieldInitializer, PrivateBrandRequirement, bool isArrowFunctionContext, bool isInsideOrdinaryFunction, EvalContextType);
JSC should distinguish between local and global eval https://bugs.webkit.org/show_bug.cgi?id=164628 Reviewed by Saam Barati. Local use of the 'eval' keyword and invocation of the global window.eval function are distinct operations in JavaScript. This patch splits out LocalEvalExecutable vs GlobalEvalExecutable in order to help distinguish these operations in code. Our code used to do some silly things for lack of distinguishing these cases. For example, it would double cache local eval in CodeCache and EvalCodeCache. This made CodeCache seem more complicated than it really was. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: Added some files. * bytecode/CodeBlock.h: * bytecode/EvalCodeCache.h: (JSC::EvalCodeCache::tryGet): (JSC::EvalCodeCache::set): (JSC::EvalCodeCache::getSlow): Deleted. Moved code generation out of the cache to avoid tight coupling. Now the cache just caches. * bytecode/UnlinkedEvalCodeBlock.h: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::fromGlobalCode): * bytecode/UnlinkedModuleProgramCodeBlock.h: * bytecode/UnlinkedProgramCodeBlock.h: * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): Updated for interface changes. * interpreter/Interpreter.cpp: (JSC::eval): Moved code generation here so the cache didn't need to build it in. * llint/LLIntOffsetsExtractor.cpp: * runtime/CodeCache.cpp: (JSC::CodeCache::getUnlinkedGlobalCodeBlock): No need to check for TDZ variables any more. We only cache global programs, and global variable access always does TDZ checks. (JSC::CodeCache::getUnlinkedProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalEvalCodeBlock): (JSC::CodeCache::getUnlinkedModuleProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): (JSC::CodeCache::CodeCache): Deleted. (JSC::CodeCache::~CodeCache): Deleted. (JSC::CodeCache::getGlobalCodeBlock): Deleted. (JSC::CodeCache::getProgramCodeBlock): Deleted. (JSC::CodeCache::getEvalCodeBlock): Deleted. (JSC::CodeCache::getModuleProgramCodeBlock): Deleted. (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Deleted. * runtime/CodeCache.h: (JSC::CodeCache::clear): (JSC::generateUnlinkedCodeBlock): Moved unlinked code block creation out of the CodeCache class and into a stand-alone function because we need it for local eval, which does not live in CodeCache. * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::create): Deleted. * runtime/EvalExecutable.h: (): Deleted. * runtime/GlobalEvalExecutable.cpp: Added. (JSC::GlobalEvalExecutable::create): (JSC::GlobalEvalExecutable::GlobalEvalExecutable): * runtime/GlobalEvalExecutable.h: Added. * runtime/LocalEvalExecutable.cpp: Added. (JSC::LocalEvalExecutable::create): (JSC::LocalEvalExecutable::LocalEvalExecutable): * runtime/LocalEvalExecutable.h: Added. Split out Local vs Global EvalExecutable classes to distinguish these operations in code. The key difference is that LocalEvalExecutable does not live in the CodeCache and only lives in the EvalCodeCache. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::createProgramCodeBlock): (JSC::JSGlobalObject::createLocalEvalCodeBlock): (JSC::JSGlobalObject::createGlobalEvalCodeBlock): (JSC::JSGlobalObject::createModuleProgramCodeBlock): (JSC::JSGlobalObject::createEvalCodeBlock): Deleted. * runtime/JSGlobalObject.h: * runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): (JSC::JSScope::collectVariablesUnderTDZ): Deleted. We don't include global lexical variables in our concept of TDZ scopes anymore. Global variable access always does TDZ checks unconditionally. So, only closure scope accesses give specific consideration to TDZ checks. * runtime/JSScope.h: Canonical link: https://commits.webkit.org/182430@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208712 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-14 22:57:12 +00:00
};
static_assert(sizeof(DirectEvalExecutable) == sizeof(EvalExecutable), "");
JSC should distinguish between local and global eval https://bugs.webkit.org/show_bug.cgi?id=164628 Reviewed by Saam Barati. Local use of the 'eval' keyword and invocation of the global window.eval function are distinct operations in JavaScript. This patch splits out LocalEvalExecutable vs GlobalEvalExecutable in order to help distinguish these operations in code. Our code used to do some silly things for lack of distinguishing these cases. For example, it would double cache local eval in CodeCache and EvalCodeCache. This made CodeCache seem more complicated than it really was. * CMakeLists.txt: * JavaScriptCore.xcodeproj/project.pbxproj: Added some files. * bytecode/CodeBlock.h: * bytecode/EvalCodeCache.h: (JSC::EvalCodeCache::tryGet): (JSC::EvalCodeCache::set): (JSC::EvalCodeCache::getSlow): Deleted. Moved code generation out of the cache to avoid tight coupling. Now the cache just caches. * bytecode/UnlinkedEvalCodeBlock.h: * bytecode/UnlinkedFunctionExecutable.cpp: (JSC::UnlinkedFunctionExecutable::fromGlobalCode): * bytecode/UnlinkedModuleProgramCodeBlock.h: * bytecode/UnlinkedProgramCodeBlock.h: * debugger/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::evaluateWithScopeExtension): Updated for interface changes. * interpreter/Interpreter.cpp: (JSC::eval): Moved code generation here so the cache didn't need to build it in. * llint/LLIntOffsetsExtractor.cpp: * runtime/CodeCache.cpp: (JSC::CodeCache::getUnlinkedGlobalCodeBlock): No need to check for TDZ variables any more. We only cache global programs, and global variable access always does TDZ checks. (JSC::CodeCache::getUnlinkedProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalEvalCodeBlock): (JSC::CodeCache::getUnlinkedModuleProgramCodeBlock): (JSC::CodeCache::getUnlinkedGlobalFunctionExecutable): (JSC::CodeCache::CodeCache): Deleted. (JSC::CodeCache::~CodeCache): Deleted. (JSC::CodeCache::getGlobalCodeBlock): Deleted. (JSC::CodeCache::getProgramCodeBlock): Deleted. (JSC::CodeCache::getEvalCodeBlock): Deleted. (JSC::CodeCache::getModuleProgramCodeBlock): Deleted. (JSC::CodeCache::getFunctionExecutableFromGlobalCode): Deleted. * runtime/CodeCache.h: (JSC::CodeCache::clear): (JSC::generateUnlinkedCodeBlock): Moved unlinked code block creation out of the CodeCache class and into a stand-alone function because we need it for local eval, which does not live in CodeCache. * runtime/EvalExecutable.cpp: (JSC::EvalExecutable::create): Deleted. * runtime/EvalExecutable.h: (): Deleted. * runtime/GlobalEvalExecutable.cpp: Added. (JSC::GlobalEvalExecutable::create): (JSC::GlobalEvalExecutable::GlobalEvalExecutable): * runtime/GlobalEvalExecutable.h: Added. * runtime/LocalEvalExecutable.cpp: Added. (JSC::LocalEvalExecutable::create): (JSC::LocalEvalExecutable::LocalEvalExecutable): * runtime/LocalEvalExecutable.h: Added. Split out Local vs Global EvalExecutable classes to distinguish these operations in code. The key difference is that LocalEvalExecutable does not live in the CodeCache and only lives in the EvalCodeCache. * runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::createProgramCodeBlock): (JSC::JSGlobalObject::createLocalEvalCodeBlock): (JSC::JSGlobalObject::createGlobalEvalCodeBlock): (JSC::JSGlobalObject::createModuleProgramCodeBlock): (JSC::JSGlobalObject::createEvalCodeBlock): Deleted. * runtime/JSGlobalObject.h: * runtime/JSGlobalObjectFunctions.cpp: (JSC::globalFuncEval): * runtime/JSScope.cpp: (JSC::JSScope::collectClosureVariablesUnderTDZ): (JSC::JSScope::collectVariablesUnderTDZ): Deleted. We don't include global lexical variables in our concept of TDZ scopes anymore. Global variable access always does TDZ checks unconditionally. So, only closure scope accesses give specific consideration to TDZ checks. * runtime/JSScope.h: Canonical link: https://commits.webkit.org/182430@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208712 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2016-11-14 22:57:12 +00:00
} // namespace JSC