Diff
Modified: trunk/JSTests/ChangeLog (249649 => 249650)
--- trunk/JSTests/ChangeLog 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/JSTests/ChangeLog 2019-09-09 17:52:07 UTC (rev 249650)
@@ -1,3 +1,13 @@
+2019-09-09 Yusuke Suzuki <ysuz...@apple.com>
+
+ [JSC] Promise resolve/reject functions should be created more efficiently
+ https://bugs.webkit.org/show_bug.cgi?id=201488
+
+ Reviewed by Mark Lam.
+
+ * microbenchmarks/promise-creation-many.js: Added.
+ (executor):
+
2019-09-09 Zan Dobersek <zdober...@igalia.com>
Unreviewed JSC test gardening.
Added: trunk/JSTests/microbenchmarks/promise-creation-many.js (0 => 249650)
--- trunk/JSTests/microbenchmarks/promise-creation-many.js (rev 0)
+++ trunk/JSTests/microbenchmarks/promise-creation-many.js 2019-09-09 17:52:07 UTC (rev 249650)
@@ -0,0 +1,6 @@
+function executor(resolve, reject) {
+}
+noInline(executor); // Ensure `resolve` and `reject`'s materialization.
+
+for (var i = 0; i < 1e6; ++i)
+ new Promise(executor);
Modified: trunk/Source/_javascript_Core/ChangeLog (249649 => 249650)
--- trunk/Source/_javascript_Core/ChangeLog 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-09-09 17:52:07 UTC (rev 249650)
@@ -1,3 +1,41 @@
+2019-09-09 Yusuke Suzuki <ysuz...@apple.com>
+
+ [JSC] Promise resolve/reject functions should be created more efficiently
+ https://bugs.webkit.org/show_bug.cgi?id=201488
+
+ Reviewed by Mark Lam.
+
+ 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):
+
2019-09-07 Mark Lam <mark....@apple.com>
performJITMemcpy() source buffer should not be in the Gigacage.
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (249649 => 249650)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2019-09-09 17:52:07 UTC (rev 249650)
@@ -7212,29 +7212,7 @@
m_jit.storePtr(scopeGPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfScopeChain()));
m_jit.storePtr(TrustedImmPtr::weakPointer(m_jit.graph(), executable), JITCompiler::Address(resultGPR, JSFunction::offsetOfExecutable()));
m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
-
- if (executable->isAnonymousBuiltinFunction()) {
- VM& vm = this->vm();
- m_jit.mutatorFence(vm);
- GPRTemporary allocator(this);
- Allocator allocatorValue = allocatorForNonVirtualConcurrently<FunctionRareData>(vm, sizeof(FunctionRareData), AllocatorForMode::AllocatorIfExists);
- emitAllocateJSCell(scratch1GPR, JITAllocator::constant(allocatorValue), allocator.gpr(), TrustedImmPtr(m_jit.graph().registerStructure(vm.functionRareDataStructure.get())), scratch2GPR, slowPath);
-
- ptrdiff_t objectAllocationProfileOffset = FunctionRareData::offsetOfObjectAllocationProfile();
- m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfAllocator()));
- m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfStructure()));
- m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, objectAllocationProfileOffset + ObjectAllocationProfileWithPrototype::offsetOfPrototype()));
- m_jit.storePtr(TrustedImmPtr(0x1), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfAllocationProfileWatchpointSet()));
- m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfInternalFunctionAllocationProfile() + InternalFunctionAllocationProfile::offsetOfStructure()));
- m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfBoundFunctionStructure()));
- m_jit.storePtr(TrustedImmPtr(nullptr), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfAllocationProfileClearingWatchpoint()));
- m_jit.store8(TrustedImm32(0), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfHasReifiedLength()));
- m_jit.store8(TrustedImm32(1), JITCompiler::Address(scratch1GPR, FunctionRareData::offsetOfHasReifiedName()));
- m_jit.mutatorFence(vm);
- m_jit.storePtr(scratch1GPR, JITCompiler::Address(resultGPR, JSFunction::offsetOfRareData()));
- } else
- m_jit.mutatorFence(vm());
-
+ m_jit.mutatorFence(vm());
}
void SpeculativeJIT::compileNewFunction(Node* node)
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (249649 => 249650)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2019-09-09 17:52:07 UTC (rev 249650)
@@ -5575,25 +5575,7 @@
m_out.storePtr(scope, fastObject, m_heaps.JSFunction_scope);
m_out.storePtr(weakPointer(executable), fastObject, m_heaps.JSFunction_executable);
m_out.storePtr(m_out.intPtrZero, fastObject, m_heaps.JSFunction_rareData);
-
- VM& vm = this->vm();
- if (executable->isAnonymousBuiltinFunction()) {
- mutatorFence();
- Allocator allocator = allocatorForNonVirtualConcurrently<FunctionRareData>(vm, sizeof(FunctionRareData), AllocatorForMode::AllocatorIfExists);
- LValue rareData = allocateCell(m_out.constIntPtr(allocator.localAllocator()), vm.functionRareDataStructure.get(), slowPath);
- m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_allocator);
- m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_structure);
- m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_prototype);
- m_out.storePtr(m_out.intPtrOne, rareData, m_heaps.FunctionRareData_allocationProfileWatchpointSet);
- m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_internalFunctionAllocationProfile_structure);
- m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_boundFunctionStructure);
- m_out.storePtr(m_out.intPtrZero, rareData, m_heaps.FunctionRareData_allocationProfileClearingWatchpoint);
- m_out.store32As8(m_out.int32One, rareData, m_heaps.FunctionRareData_hasReifiedName);
- m_out.store32As8(m_out.int32Zero, rareData, m_heaps.FunctionRareData_hasReifiedLength);
- mutatorFence();
- m_out.storePtr(rareData, fastObject, m_heaps.JSFunction_rareData);
- } else
- mutatorFence();
+ mutatorFence();
ValueFromBlock fastResult = m_out.anchor(fastObject);
m_out.jump(continuation);
@@ -5602,6 +5584,7 @@
Vector<LValue> slowPathArguments;
slowPathArguments.append(scope);
+ VM& vm = this->vm();
LValue callResult = lazySlowPath(
[=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> {
auto* operation = operationNewFunctionWithInvalidatedReallocationWatchpoint;
Modified: trunk/Source/_javascript_Core/runtime/FunctionRareData.cpp (249649 => 249650)
--- trunk/Source/_javascript_Core/runtime/FunctionRareData.cpp 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/runtime/FunctionRareData.cpp 2019-09-09 17:52:07 UTC (rev 249650)
@@ -33,9 +33,9 @@
const ClassInfo FunctionRareData::s_info = { "FunctionRareData", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(FunctionRareData) };
-FunctionRareData* FunctionRareData::create(VM& vm)
+FunctionRareData* FunctionRareData::create(VM& vm, JSFunction* function)
{
- FunctionRareData* rareData = new (NotNull, allocateCell<FunctionRareData>(vm.heap)) FunctionRareData(vm);
+ FunctionRareData* rareData = new (NotNull, allocateCell<FunctionRareData>(vm.heap)) FunctionRareData(vm, function);
rareData->finishCreation(vm);
return rareData;
}
@@ -62,7 +62,7 @@
visitor.append(rareData->m_boundFunctionStructure);
}
-FunctionRareData::FunctionRareData(VM& vm)
+FunctionRareData::FunctionRareData(VM& vm, JSFunction* function)
: Base(vm, vm.functionRareDataStructure.get())
, m_objectAllocationProfile()
// We initialize blind so that changes to the prototype after function creation but before
@@ -69,6 +69,7 @@
// the first allocation don't disable optimizations. This isn't super important, since the
// function is unlikely to allocate a rare data until the first allocation anyway.
, m_allocationProfileWatchpointSet(ClearWatchpoint)
+ , m_hasReifiedName(function->isAnonymousBuiltinFunction())
{
}
Modified: trunk/Source/_javascript_Core/runtime/FunctionRareData.h (249649 => 249650)
--- trunk/Source/_javascript_Core/runtime/FunctionRareData.h 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/runtime/FunctionRareData.h 2019-09-09 17:52:07 UTC (rev 249650)
@@ -50,7 +50,7 @@
typedef JSCell Base;
static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal;
- static FunctionRareData* create(VM&);
+ static FunctionRareData* create(VM&, JSFunction*);
static const bool needsDestruction = true;
static void destroy(JSCell*);
@@ -119,7 +119,7 @@
class AllocationProfileClearingWatchpoint;
protected:
- FunctionRareData(VM&);
+ FunctionRareData(VM&, JSFunction*);
~FunctionRareData();
private:
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (249649 => 249650)
--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp 2019-09-09 17:52:07 UTC (rev 249650)
@@ -125,10 +125,6 @@
Base::finishCreation(vm);
ASSERT(jsDynamicCast<JSFunction*>(vm, this));
ASSERT(type() == JSFunctionType);
- if (isAnonymousBuiltinFunction()) {
- // This is anonymous builtin function.
- rareData(vm)->setHasReifiedName();
- }
}
void JSFunction::finishCreation(VM& vm, NativeExecutable* executable, int length, const String& name)
@@ -146,7 +142,7 @@
FunctionRareData* JSFunction::allocateRareData(VM& vm)
{
ASSERT(!m_rareData);
- FunctionRareData* rareData = FunctionRareData::create(vm);
+ FunctionRareData* rareData = FunctionRareData::create(vm, this);
// A DFG compilation thread may be trying to read the rare data
// We want to ensure that it sees it properly allocated
@@ -186,7 +182,7 @@
ASSERT(canUseAllocationProfile());
VM& vm = exec->vm();
JSObject* prototype = prototypeForConstruction(vm, exec);
- FunctionRareData* rareData = FunctionRareData::create(vm);
+ FunctionRareData* rareData = FunctionRareData::create(vm, this);
rareData->initializeObjectAllocationProfile(vm, globalObject(vm), prototype, inlineCapacity, this);
// A DFG compilation thread may be trying to read the rare data
Modified: trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h (249649 => 249650)
--- trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2019-09-09 17:44:33 UTC (rev 249649)
+++ trunk/Source/_javascript_Core/runtime/JSFunctionInlines.h 2019-09-09 17:52:07 UTC (rev 249650)
@@ -110,7 +110,11 @@
inline bool JSFunction::hasReifiedName() const
{
- return m_rareData ? m_rareData->hasReifiedName() : false;
+ if (m_rareData)
+ return m_rareData->hasReifiedName();
+ if (isAnonymousBuiltinFunction())
+ return true;
+ return false;
}
inline bool JSFunction::canUseAllocationProfile()