Ignore:
Timestamp:
Feb 22, 2017, 1:23:08 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

JSModuleNamespace object should have IC
https://bugs.webkit.org/show_bug.cgi?id=160590

Reviewed by Saam Barati.

JSTests:

  • modules/module-assert-access-binding.js: Added.
  • modules/module-assert-access-namespace.js: Added.
  • modules/namespace-empty.js: Added.

(from.string_appeared_here.access):
(i.shouldThrow):

  • stress/module-namespace-access-change.js: Added.

(shouldBe):
(access):
(import.string_appeared_here.then):

  • stress/module-namespace-access-non-constant.js: Added.

(shouldBe):
(import.string_appeared_here.then):

  • stress/module-namespace-access-poly.js: Added.

(shouldBe):
(access):
(import.string_appeared_here.then):

  • stress/module-namespace-access-transitive-exports.js: Added.

(shouldBe):
(import.string_appeared_here.then):

  • stress/module-namespace-access.js: Added.

(shouldBe):
(import.string_appeared_here.then):

  • stress/resources/module-namespace-access-transitive-exports-2.js: Added.

(export.cocoa):
(export.change):

  • stress/resources/module-namespace-access-transitive-exports.js: Added.
  • stress/resources/module-namespace-access.js: Added.

(export.cocoa):
(export.change):

Source/JavaScriptCore:

This patch optimizes accesses to module namespace objects.

  1. Cache the resolutions for module namespace objects.

When constructing the module namespace object, we already resolves all the exports.
The module namespace object caches this result and leverage it in the later access in
getOwnPropertySlot. This avoids resolving bindings through resolveExport.

  1. Introduce ModuleNamespaceLoad IC.

This patch adds new IC for module namespace objects. The mechanism is simple, getOwnPropertySlot
tells us about module namespace object resolution. The IC first checks whether the given object
is an expected module namespace object. If this check succeeds, we load the value from the module
environment.

  1. Introduce DFG/FTL optimization.

After exploiting module namespace object accesses in (2), DFG can recognize this in ByteCodeParser.
DFG will convert it to CheckCell with the namespace object and GetClosureVar from the cached environment.
At that time, we have a chance to fold it to the constant.

This optimization improves the performance of accessing to module namespace objects.

Before

$ time ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m module-assert-access-namespace.js
../../WebKitBuild/module-ic-tot/Release/bin/jsc -m 0.43s user 0.03s system 101% cpu 0.451 total
$ time ../../WebKitBuild/module-ic-tot/Release/bin/jsc -m module-assert-access-binding.js
../../WebKitBuild/module-ic-tot/Release/bin/jsc -m 0.08s user 0.02s system 103% cpu 0.104 total

After

$ time ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-namespace.js
../../WebKitBuild/module-ic/Release/bin/jsc -m 0.11s user 0.01s system 106% cpu 0.109 total
$ time ../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-binding.js
../../WebKitBuild/module-ic/Release/bin/jsc -m module-assert-access-binding.j 0.08s user 0.02s system 102% cpu 0.105 total

  • CMakeLists.txt:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/AccessCase.cpp:

(JSC::AccessCase::create):
(JSC::AccessCase::guardedByStructureCheck):
(JSC::AccessCase::canReplace):
(JSC::AccessCase::visitWeak):
(JSC::AccessCase::generateWithGuard):
(JSC::AccessCase::generateImpl):

  • bytecode/AccessCase.h:
  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
(JSC::GetByIdStatus::makesCalls):
(JSC::GetByIdStatus::dump):

  • bytecode/GetByIdStatus.h:

(JSC::GetByIdStatus::isModuleNamespace):
(JSC::GetByIdStatus::takesSlowPath):
(JSC::GetByIdStatus::moduleNamespaceObject):
(JSC::GetByIdStatus::moduleEnvironment):
(JSC::GetByIdStatus::scopeOffset):

  • bytecode/ModuleNamespaceAccessCase.cpp: Added.

(JSC::ModuleNamespaceAccessCase::ModuleNamespaceAccessCase):
(JSC::ModuleNamespaceAccessCase::create):
(JSC::ModuleNamespaceAccessCase::~ModuleNamespaceAccessCase):
(JSC::ModuleNamespaceAccessCase::clone):
(JSC::ModuleNamespaceAccessCase::emit):

  • bytecode/ModuleNamespaceAccessCase.h: Added.

(JSC::ModuleNamespaceAccessCase::moduleNamespaceObject):
(JSC::ModuleNamespaceAccessCase::moduleEnvironment):
(JSC::ModuleNamespaceAccessCase::scopeOffset):

  • bytecode/PolymorphicAccess.cpp:

(WTF::printInternal):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleModuleNamespaceLoad):
(JSC::DFG::ByteCodeParser::handleGetById):

  • jit/AssemblyHelpers.h:

(JSC::AssemblyHelpers::loadValue):

  • jit/Repatch.cpp:

(JSC::tryCacheGetByID):

  • runtime/AbstractModuleRecord.cpp:

(JSC::AbstractModuleRecord::getModuleNamespace):

  • runtime/JSModuleNamespaceObject.cpp:

(JSC::JSModuleNamespaceObject::finishCreation):
(JSC::JSModuleNamespaceObject::visitChildren):
(JSC::getValue):
(JSC::JSModuleNamespaceObject::getOwnPropertySlot):
(JSC::JSModuleNamespaceObject::getOwnPropertyNames):

  • runtime/JSModuleNamespaceObject.h:

(JSC::isJSModuleNamespaceObject):
(JSC::JSModuleNamespaceObject::create): Deleted.
(JSC::JSModuleNamespaceObject::createStructure): Deleted.
(JSC::JSModuleNamespaceObject::moduleRecord): Deleted.

  • runtime/JSModuleRecord.h:

(JSC::JSModuleRecord::moduleEnvironment): Deleted.

  • runtime/PropertySlot.h:

(JSC::PropertySlot::PropertySlot):
(JSC::PropertySlot::domJIT):
(JSC::PropertySlot::moduleNamespaceSlot):
(JSC::PropertySlot::setValueModuleNamespace):
(JSC::PropertySlot::setCacheableCustom):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/PropertySlot.h

    r212717 r212818  
    2424#include "PropertyName.h"
    2525#include "PropertyOffset.h"
     26#include "ScopeOffset.h"
    2627#include <wtf/Assertions.h>
    2728
     
    3334class GetterSetter;
    3435class JSObject;
     36class JSModuleEnvironment;
    3537
    3638// ECMA 262-3 8.6.1
     
    8789    };
    8890
     91    enum class AdditionalDataType : uint8_t {
     92        None,
     93        DOMJIT, // Annotated with DOMJIT information.
     94        ModuleNamespace, // ModuleNamespaceObject's environment access.
     95    };
     96
    8997    explicit PropertySlot(const JSValue thisValue, InternalMethodType internalMethodType)
    9098        : m_offset(invalidOffset)
     
    95103        , m_propertyType(TypeUnset)
    96104        , m_internalMethodType(internalMethodType)
     105        , m_additionalDataType(AdditionalDataType::None)
    97106        , m_isTaintedByOpaqueObject(false)
    98107    {
     
    164173    DOMJIT::GetterSetter* domJIT() const
    165174    {
    166         return m_domJIT;
     175        if (m_additionalDataType == AdditionalDataType::DOMJIT)
     176            return m_additionalData.domJIT;
     177        return nullptr;
     178    }
     179
     180    struct ModuleNamespaceSlot {
     181        JSModuleEnvironment* environment;
     182        unsigned scopeOffset;
     183    };
     184
     185    std::optional<ModuleNamespaceSlot> moduleNamespaceSlot() const
     186    {
     187        if (m_additionalDataType == AdditionalDataType::ModuleNamespace)
     188            return m_additionalData.moduleNamespaceSlot;
     189        return std::nullopt;
    167190    }
    168191
     
    207230    }
    208231
     232    void setValueModuleNamespace(JSObject* slotBase, unsigned attributes, JSValue value, JSModuleEnvironment* environment, ScopeOffset scopeOffset)
     233    {
     234        setValue(slotBase, attributes, value);
     235        m_additionalDataType = AdditionalDataType::ModuleNamespace;
     236        m_additionalData.moduleNamespaceSlot.environment = environment;
     237        m_additionalData.moduleNamespaceSlot.scopeOffset = scopeOffset.offset();
     238    }
     239
    209240    void setCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
    210241    {
     
    221252    }
    222253   
    223     void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue, DOMJIT::GetterSetter* domJIT = nullptr)
     254    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue)
    224255    {
    225256        ASSERT(attributes == attributesForStructure(attributes));
     
    233264        m_propertyType = TypeCustom;
    234265        m_offset = !invalidOffset;
    235         m_domJIT = domJIT;
     266    }
     267
     268    void setCacheableCustom(JSObject* slotBase, unsigned attributes, GetValueFunc getValue, DOMJIT::GetterSetter* domJIT)
     269    {
     270        setCacheableCustom(slotBase, attributes, getValue);
     271        if (domJIT) {
     272            m_additionalDataType = AdditionalDataType::DOMJIT;
     273            m_additionalData.domJIT = domJIT;
     274        }
    236275    }
    237276
     
    329368    PropertyType m_propertyType;
    330369    InternalMethodType m_internalMethodType;
    331     DOMJIT::GetterSetter* m_domJIT { nullptr };
     370    AdditionalDataType m_additionalDataType;
     371    union {
     372        DOMJIT::GetterSetter* domJIT;
     373        ModuleNamespaceSlot moduleNamespaceSlot;
     374    } m_additionalData;
    332375    bool m_isTaintedByOpaqueObject;
    333376};
Note: See TracChangeset for help on using the changeset viewer.