Changeset 249650 in webkit


Ignore:
Timestamp:
Sep 9, 2019 10:52:07 AM (5 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Promise resolve/reject functions should be created more efficiently
https://bugs.webkit.org/show_bug.cgi?id=201488

Reviewed by Mark Lam.

JSTests:

  • microbenchmarks/promise-creation-many.js: Added.

(executor):

Source/JavaScriptCore:

While r246553 fixed an important issue, it makes anonymous-builtin-function creation costly since it enforces FunctionRareData allocations.
Unfortunately, anonymous-builtin-function function can be created frequently since this type of function is used
for resolve and reject arguments of Promise's executor (e.g. new Promise((resolve, reject) => ...)'s resolve and reject).
Since we are now always creating FunctionRareData for these functions, this additional allocation makes promise creation slower.

In this patch, we use isAnonymousBuiltinFunction information for hasReifiedName correctly. And we propagate isAnonymousBuiltinFunction information
to FunctionRareData to initialize m_hasReifiedName correctly. Then we can avoid unnecessary FunctionRareData allocation, which makes
anonymous-builtin-function creation faster.

We can ensure that this patch does not revert r246553's fix by running JSTests/stress/builtin-private-function-name.js test.
The simple microbenchmark shows 1.7x improvement.

ToT Patched

promise-creation-many 45.6701+-0.1488 26.8663+-1.8336 definitely 1.6999x faster

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileNewFunctionCommon):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):

  • runtime/FunctionRareData.cpp:

(JSC::FunctionRareData::create):
(JSC::FunctionRareData::FunctionRareData):

  • runtime/FunctionRareData.h:
  • runtime/JSFunction.cpp:

(JSC::JSFunction::finishCreation):
(JSC::JSFunction::allocateRareData):
(JSC::JSFunction::allocateAndInitializeRareData):

  • runtime/JSFunctionInlines.h:

(JSC::JSFunction::hasReifiedName const):

Location:
trunk
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r249644 r249650  
     12019-09-09  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Promise resolve/reject functions should be created more efficiently
     4        https://bugs.webkit.org/show_bug.cgi?id=201488
     5
     6        Reviewed by Mark Lam.
     7
     8        * microbenchmarks/promise-creation-many.js: Added.
     9        (executor):
     10
    1112019-09-09  Zan Dobersek  <zdobersek@igalia.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r249613 r249650  
     12019-09-09  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Promise resolve/reject functions should be created more efficiently
     4        https://bugs.webkit.org/show_bug.cgi?id=201488
     5
     6        Reviewed by Mark Lam.
     7
     8        While r246553 fixed an important issue, it makes anonymous-builtin-function creation costly since it enforces FunctionRareData allocations.
     9        Unfortunately, anonymous-builtin-function function can be created frequently since this type of function is used
     10        for `resolve` and `reject` arguments of Promise's executor (e.g. `new Promise((resolve, reject) => ...)`'s resolve and reject).
     11        Since we are now always creating FunctionRareData for these functions, this additional allocation makes promise creation slower.
     12
     13        In this patch, we use `isAnonymousBuiltinFunction` information for `hasReifiedName` correctly. And we propagate `isAnonymousBuiltinFunction` information
     14        to FunctionRareData to initialize `m_hasReifiedName` correctly. Then we can avoid unnecessary FunctionRareData allocation, which makes
     15        anonymous-builtin-function creation faster.
     16
     17        We can ensure that this patch does not revert r246553's fix by running JSTests/stress/builtin-private-function-name.js test.
     18        The simple microbenchmark shows 1.7x improvement.
     19
     20                                              ToT                     Patched
     21
     22            promise-creation-many       45.6701+-0.1488     ^     26.8663+-1.8336        ^ definitely 1.6999x faster
     23
     24        * dfg/DFGSpeculativeJIT.cpp:
     25        (JSC::DFG::SpeculativeJIT::compileNewFunctionCommon):
     26        * ftl/FTLLowerDFGToB3.cpp:
     27        (JSC::FTL::DFG::LowerDFGToB3::compileNewFunction):
     28        * runtime/FunctionRareData.cpp:
     29        (JSC::FunctionRareData::create):
     30        (JSC::FunctionRareData::FunctionRareData):
     31        * runtime/FunctionRareData.h:
     32        * runtime/JSFunction.cpp:
     33        (JSC::JSFunction::finishCreation):
     34        (JSC::JSFunction::allocateRareData):
     35        (JSC::JSFunction::allocateAndInitializeRareData):
     36        * runtime/JSFunctionInlines.h:
     37        (JSC::JSFunction::hasReifiedName const):
     38
    1392019-09-07  Mark Lam  <mark.lam@apple.com>
    240
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r249597 r249650  
    72137213    m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), executable), JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable()));
    72147214    m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
    7215    
    7216     if (executable->isAnonymousBuiltinFunction()) {
    7217         VM& vm = this->vm();
    7218         m_jit.mutatorFence(vm);
    7219         GPRTemporary allocator(this);
    7220         Allocator allocatorValue = allocatorForNonVirtualConcurrently<FunctionRareData>(vm, sizeof(FunctionRareData), AllocatorForMode::AllocatorIfExists);
    7221         emitAllocateJSCell(scratch1GPR, JITAllocator::constant(allocatorValue), allocator.gpr(), TrustedImmPtr(m_jit.graph().registerStructure(vm.functionRareDataStructure.get())), scratch2GPR, slowPath);
    7222 
    7223         ptrdiff_t objectAllocationProfileOffset = FunctionRareData::offsetOfObjectAllocationProfile();
    7224         m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfAllocator()));
    7225         m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfStructure()));
    7226         m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfPrototype()));
    7227         m_jit.storePtr(TrustedImmPtr(0x1), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfAllocationProfileWatchpointSet()));
    7228         m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()));
    7229         m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfBoundFunctionStructure()));
    7230         m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfAllocationProfileClearingWatchpoint()));
    7231         m_jit.store8(TrustedImm32(0), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfHasReifiedLength()));
    7232         m_jit.store8(TrustedImm32(1), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfHasReifiedName()));
    7233         m_jit.mutatorFence(vm);
    7234         m_jit.storePtr(scratch1GPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
    7235     } else
    7236         m_jit.mutatorFence(vm());
    7237 
     7215    m_jit.mutatorFence(vm());
    72387216}
    72397217
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r249597 r249650  
    55765576        m_out.storePtr(weakPointer(executable), fastObject, m_heaps.JSFunction_executable);
    55775577        m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.JSFunction_rareData);
    5578        
    5579         VM& vm = this->vm();
    5580         if (executable->isAnonymousBuiltinFunction()) {
    5581             mutatorFence();
    5582             Allocator allocator = allocatorForNonVirtualConcurrently<FunctionRareData>(vm, sizeof(FunctionRareData), AllocatorForMode::AllocatorIfExists);
    5583             LValue rareData = allocateCell(m_out.constIntPtr(allocator.localAllocator()), vm.functionRareDataStructure.get(), slowPath);
    5584             m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_allocator);
    5585             m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_structure);
    5586             m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_prototype);
    5587             m_out.storePtr(m_out.intPtrOne, rareData, m_heaps.FunctionRareData_allocationProfileWatchpointSet);
    5588             m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_internalFunctionAllocationProfile_structure);
    5589             m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_boundFunctionStructure);
    5590             m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_allocationProfileClearingWatchpoint);
    5591             m_out.store32As8(m_out.int32One, rareData, m_heaps.FunctionRareData_hasReifiedName);
    5592             m_out.store32As8(m_out.int32Zero, rareData, m_heaps.FunctionRareData_hasReifiedLength);
    5593             mutatorFence();
    5594             m_out.storePtr(rareData, fastObject, m_heaps.JSFunction_rareData);
    5595         } else
    5596             mutatorFence();
     5578        mutatorFence();
    55975579
    55985580        ValueFromBlock fastResult = m_out.anchor(fastObject);
     
    56035585        Vector<LValue> slowPathArguments;
    56045586        slowPathArguments.append(scope);
     5587        VM& vm = this->vm();
    56055588        LValue callResult = lazySlowPath(
    56065589            [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
  • trunk/Source/JavaScriptCore/runtime/FunctionRareData.cpp

    r249509 r249650  
    3434const ClassInfo FunctionRareData::s_info = { "FunctionRareData", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(FunctionRareData) };
    3535
    36 FunctionRareData* FunctionRareData::create(VM& vm)
     36FunctionRareData* FunctionRareData::create(VM& vm, JSFunction* function)
    3737{
    38     FunctionRareData* rareData = new (NotNull, allocateCell<FunctionRareData>(vm.heap)) FunctionRareData(vm);
     38    FunctionRareData* rareData = new (NotNull, allocateCell<FunctionRareData>(vm.heap)) FunctionRareData(vm, function);
    3939    rareData->finishCreation(vm);
    4040    return rareData;
     
    6363}
    6464
    65 FunctionRareData::FunctionRareData(VM& vm)
     65FunctionRareData::FunctionRareData(VM& vm, JSFunction* function)
    6666    : Base(vm, vm.functionRareDataStructure.get())
    6767    , m_objectAllocationProfile()
     
    7070    // function is unlikely to allocate a rare data until the first allocation anyway.
    7171    , m_allocationProfileWatchpointSet(ClearWatchpoint)
     72    , m_hasReifiedName(function->isAnonymousBuiltinFunction())
    7273{
    7374}
  • trunk/Source/JavaScriptCore/runtime/FunctionRareData.h

    r249509 r249650  
    5151    static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
    5252
    53     static FunctionRareData* create(VM&);
     53    static FunctionRareData* create(VM&, JSFunction*);
    5454
    5555    static const bool needsDestruction = true;
     
    120120
    121121protected:
    122     FunctionRareData(VM&);
     122    FunctionRareData(VM&, JSFunction*);
    123123    ~FunctionRareData();
    124124
  • trunk/Source/JavaScriptCore/runtime/JSFunction.cpp

    r249175 r249650  
    126126    ASSERT(jsDynamicCast<JSFunction*>(vm, this));
    127127    ASSERT(type() == JSFunctionType);
    128     if (isAnonymousBuiltinFunction()) {
    129         // This is anonymous builtin function.
    130         rareData(vm)->setHasReifiedName();
    131     }
    132128}
    133129
     
    147143{
    148144    ASSERT(!m_rareData);
    149     FunctionRareData* rareData = FunctionRareData::create(vm);
     145    FunctionRareData* rareData = FunctionRareData::create(vm, this);
    150146
    151147    // A DFG compilation thread may be trying to read the rare data
     
    187183    VM& vm = exec->vm();
    188184    JSObject* prototype = prototypeForConstruction(vm, exec);
    189     FunctionRareData* rareData = FunctionRareData::create(vm);
     185    FunctionRareData* rareData = FunctionRareData::create(vm, this);
    190186    rareData->initializeObjectAllocationProfile(vm, globalObject(vm), prototype, inlineCapacity, this);
    191187
  • trunk/Source/JavaScriptCore/runtime/JSFunctionInlines.h

    r246553 r249650  
    111111inline bool JSFunction::hasReifiedName() const
    112112{
    113     return m_rareData ? m_rareData->hasReifiedName() : false;
     113    if (m_rareData)
     114        return m_rareData->hasReifiedName();
     115    if (isAnonymousBuiltinFunction())
     116        return true;
     117    return false;
    114118}
    115119
Note: See TracChangeset for help on using the changeset viewer.