Skip to content

Commit

Permalink
Merge r242015 - [JSC] Lazily create sentinel Map and Set buckets
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=194975

Reviewed by Saam Barati.

If VM::canUseJIT() returns false, we can lazily initialize sentinel Map and Set buckets.
This patch adds getters to VM which lazily allocate these buckets. We eagerly initialize
them if VM::canUseJIT() returns true since they can be touched from DFG and FTL.

* bytecode/BytecodeIntrinsicRegistry.cpp:
(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
(JSC::BytecodeIntrinsicRegistry::sentinelMapBucketValue):
(JSC::BytecodeIntrinsicRegistry::sentinelSetBucketValue):
* bytecode/BytecodeIntrinsicRegistry.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGOperations.cpp:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetMapBucketNext):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucketNext):
* runtime/MapConstructor.cpp:
(JSC::mapPrivateFuncMapBucketNext):
* runtime/SetConstructor.cpp:
(JSC::setPrivateFuncSetBucketNext):
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::sentinelSetBucketSlow):
(JSC::VM::sentinelMapBucketSlow):
* runtime/VM.h:
(JSC::VM::sentinelSetBucket):
(JSC::VM::sentinelMapBucket):
  • Loading branch information
Constellation authored and carlosgcampos committed Mar 5, 2019
1 parent ecbf9f8 commit 1c0cae5
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 26 deletions.
38 changes: 38 additions & 0 deletions Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,41 @@
2019-02-24 Yusuke Suzuki <ysuzuki@apple.com>

[JSC] Lazily create sentinel Map and Set buckets
https://bugs.webkit.org/show_bug.cgi?id=194975

Reviewed by Saam Barati.

If VM::canUseJIT() returns false, we can lazily initialize sentinel Map and Set buckets.
This patch adds getters to VM which lazily allocate these buckets. We eagerly initialize
them if VM::canUseJIT() returns true since they can be touched from DFG and FTL.

* bytecode/BytecodeIntrinsicRegistry.cpp:
(JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry):
(JSC::BytecodeIntrinsicRegistry::sentinelMapBucketValue):
(JSC::BytecodeIntrinsicRegistry::sentinelSetBucketValue):
* bytecode/BytecodeIntrinsicRegistry.h:
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
* dfg/DFGOperations.cpp:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileGetMapBucketNext):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucketNext):
* runtime/MapConstructor.cpp:
(JSC::mapPrivateFuncMapBucketNext):
* runtime/SetConstructor.cpp:
(JSC::setPrivateFuncSetBucketNext):
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::sentinelSetBucketSlow):
(JSC::VM::sentinelMapBucketSlow):
* runtime/VM.h:
(JSC::VM::sentinelSetBucket):
(JSC::VM::sentinelMapBucket):

2019-02-23 Mark Lam <mark.lam@apple.com>

Add an exception check and some assertions in StringPrototype.cpp.
Expand Down
14 changes: 11 additions & 3 deletions Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp
Expand Up @@ -69,8 +69,6 @@ BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry(VM& vm)
m_promiseStatePending.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Pending)));
m_promiseStateFulfilled.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Fulfilled)));
m_promiseStateRejected.set(m_vm, jsNumber(static_cast<unsigned>(JSPromise::Status::Rejected)));
m_sentinelMapBucket.set(m_vm, m_vm.sentinelMapBucket.get());
m_sentinelSetBucket.set(m_vm, m_vm.sentinelSetBucket.get());
m_GeneratorResumeModeNormal.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::NormalMode)));
m_GeneratorResumeModeThrow.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ThrowMode)));
m_GeneratorResumeModeReturn.set(m_vm, jsNumber(static_cast<int32_t>(JSGeneratorFunction::GeneratorResumeMode::ReturnMode)));
Expand Down Expand Up @@ -101,8 +99,18 @@ BytecodeIntrinsicNode::EmitterType BytecodeIntrinsicRegistry::lookup(const Ident
{ \
return m_##name.get(); \
}
JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS)
JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_SIMPLE_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS)
#undef JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS

JSValue BytecodeIntrinsicRegistry::sentinelMapBucketValue(BytecodeGenerator& generator)
{
return generator.vm()->sentinelMapBucket();
}

JSValue BytecodeIntrinsicRegistry::sentinelSetBucketValue(BytecodeGenerator& generator)
{
return generator.vm()->sentinelSetBucket();
}

} // namespace JSC

12 changes: 9 additions & 3 deletions Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h
Expand Up @@ -66,6 +66,10 @@ class Identifier;
macro(defineEnumerableWritableConfigurableDataProperty) \

#define JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(macro) \
JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_SIMPLE_EACH_NAME(macro) \
JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_CUSTOM_EACH_NAME(macro) \

#define JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_SIMPLE_EACH_NAME(macro) \
macro(undefined) \
macro(Infinity) \
macro(iterationKindKey) \
Expand All @@ -85,8 +89,6 @@ class Identifier;
macro(promiseStatePending) \
macro(promiseStateFulfilled) \
macro(promiseStateRejected) \
macro(sentinelMapBucket) \
macro(sentinelSetBucket) \
macro(GeneratorResumeModeNormal) \
macro(GeneratorResumeModeThrow) \
macro(GeneratorResumeModeReturn) \
Expand All @@ -101,6 +103,10 @@ class Identifier;
macro(AsyncGeneratorSuspendReasonAwait) \
macro(AsyncGeneratorSuspendReasonNone) \

#define JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_CUSTOM_EACH_NAME(macro) \
macro(sentinelMapBucket) \
macro(sentinelSetBucket) \

class BytecodeIntrinsicRegistry {
WTF_MAKE_FAST_ALLOCATED;
WTF_MAKE_NONCOPYABLE(BytecodeIntrinsicRegistry);
Expand All @@ -120,7 +126,7 @@ class BytecodeIntrinsicRegistry {
HashMap<RefPtr<UniquedStringImpl>, EmitterType, IdentifierRepHash> m_bytecodeIntrinsicMap;

#define JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS(name) Strong<Unknown> m_##name;
JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS)
JSC_COMMON_BYTECODE_INTRINSIC_CONSTANTS_SIMPLE_EACH_NAME(JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS)
#undef JSC_DECLARE_BYTECODE_INTRINSIC_CONSTANT_GENERATORS
};

Expand Down
4 changes: 2 additions & 2 deletions Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Expand Up @@ -2929,9 +2929,9 @@ bool ByteCodeParser::handleIntrinsicCall(Node* callee, VirtualRegister result, I
Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(normalizedKey), Edge(hash));
JSCell* sentinel = nullptr;
if (intrinsic == JSMapHasIntrinsic)
sentinel = m_vm->sentinelMapBucket.get();
sentinel = m_vm->sentinelMapBucket();
else
sentinel = m_vm->sentinelSetBucket.get();
sentinel = m_vm->sentinelSetBucket();

FrozenValue* frozenPointer = m_graph.freeze(sentinel);
Node* invertedResult = addToGraph(CompareEqPtr, OpInfo(frozenPointer), bucket);
Expand Down
8 changes: 4 additions & 4 deletions Source/JavaScriptCore/dfg/DFGOperations.cpp
Expand Up @@ -2892,7 +2892,7 @@ JSCell* JIT_OPERATION operationJSMapFindBucket(ExecState* exec, JSCell* map, Enc
NativeCallFrameTracer tracer(&vm, exec);
JSMap::BucketType** bucket = jsCast<JSMap*>(map)->findBucket(exec, JSValue::decode(key), hash);
if (!bucket)
return vm.sentinelMapBucket.get();
return vm.sentinelMapBucket();
return *bucket;
}

Expand All @@ -2902,7 +2902,7 @@ JSCell* JIT_OPERATION operationJSSetFindBucket(ExecState* exec, JSCell* map, Enc
NativeCallFrameTracer tracer(&vm, exec);
JSSet::BucketType** bucket = jsCast<JSSet*>(map)->findBucket(exec, JSValue::decode(key), hash);
if (!bucket)
return vm.sentinelSetBucket.get();
return vm.sentinelSetBucket();
return *bucket;
}

Expand All @@ -2912,7 +2912,7 @@ JSCell* JIT_OPERATION operationSetAdd(ExecState* exec, JSCell* set, EncodedJSVal
NativeCallFrameTracer tracer(&vm, exec);
auto* bucket = jsCast<JSSet*>(set)->addNormalized(exec, JSValue::decode(key), JSValue(), hash);
if (!bucket)
return vm.sentinelSetBucket.get();
return vm.sentinelSetBucket();
return bucket;
}

Expand All @@ -2922,7 +2922,7 @@ JSCell* JIT_OPERATION operationMapSet(ExecState* exec, JSCell* map, EncodedJSVal
NativeCallFrameTracer tracer(&vm, exec);
auto* bucket = jsCast<JSMap*>(map)->addNormalized(exec, JSValue::decode(key), JSValue::decode(value), hash);
if (!bucket)
return vm.sentinelMapBucket.get();
return vm.sentinelMapBucket();
return bucket;
}

Expand Down
4 changes: 2 additions & 2 deletions Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Expand Up @@ -11792,10 +11792,10 @@ void SpeculativeJIT::compileGetMapBucketNext(Node* node)
notBucket.link(&m_jit);
JSCell* sentinel = nullptr;
if (node->bucketOwnerType() == BucketOwnerType::Map)
sentinel = m_jit.vm()->sentinelMapBucket.get();
sentinel = m_jit.vm()->sentinelMapBucket();
else {
ASSERT(node->bucketOwnerType() == BucketOwnerType::Set);
sentinel = m_jit.vm()->sentinelSetBucket.get();
sentinel = m_jit.vm()->sentinelSetBucket();
}
m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), sentinel), resultGPR);
done.link(&m_jit);
Expand Down
4 changes: 2 additions & 2 deletions Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Expand Up @@ -4217,9 +4217,9 @@ void SpeculativeJIT::compile(Node* node)

notPresentInTable.link(&m_jit);
if (node->child1().useKind() == MapObjectUse)
m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelMapBucket.get()), resultGPR);
m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelMapBucket()), resultGPR);
else
m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelSetBucket.get()), resultGPR);
m_jit.move(TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelSetBucket()), resultGPR);
done.link(&m_jit);
cellResult(resultGPR, node);
break;
Expand Down
8 changes: 4 additions & 4 deletions Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Expand Up @@ -9744,9 +9744,9 @@ class LowerDFGToB3 {
m_out.appendTo(notPresentInTable, continuation);
ValueFromBlock notPresentResult;
if (m_node->child1().useKind() == MapObjectUse)
notPresentResult = m_out.anchor(weakPointer(vm().sentinelMapBucket.get()));
notPresentResult = m_out.anchor(weakPointer(vm().sentinelMapBucket()));
else if (m_node->child1().useKind() == SetObjectUse)
notPresentResult = m_out.anchor(weakPointer(vm().sentinelSetBucket.get()));
notPresentResult = m_out.anchor(weakPointer(vm().sentinelSetBucket()));
else
RELEASE_ASSERT_NOT_REACHED();
m_out.jump(continuation);
Expand Down Expand Up @@ -9792,10 +9792,10 @@ class LowerDFGToB3 {
m_out.appendTo(noBucket, hasBucket);
ValueFromBlock noBucketResult;
if (m_node->bucketOwnerType() == BucketOwnerType::Map)
noBucketResult = m_out.anchor(weakPointer(vm().sentinelMapBucket.get()));
noBucketResult = m_out.anchor(weakPointer(vm().sentinelMapBucket()));
else {
ASSERT(m_node->bucketOwnerType() == BucketOwnerType::Set);
noBucketResult = m_out.anchor(weakPointer(vm().sentinelSetBucket.get()));
noBucketResult = m_out.anchor(weakPointer(vm().sentinelSetBucket()));
}
m_out.jump(continuation);

Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/MapConstructor.cpp
Expand Up @@ -136,7 +136,7 @@ EncodedJSValue JSC_HOST_CALL mapPrivateFuncMapBucketNext(ExecState* exec)
return JSValue::encode(bucket);
bucket = bucket->next();
}
return JSValue::encode(exec->vm().sentinelMapBucket.get());
return JSValue::encode(exec->vm().sentinelMapBucket());
}

EncodedJSValue JSC_HOST_CALL mapPrivateFuncMapBucketKey(ExecState* exec)
Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/SetConstructor.cpp
Expand Up @@ -122,7 +122,7 @@ EncodedJSValue JSC_HOST_CALL setPrivateFuncSetBucketNext(ExecState* exec)
return JSValue::encode(bucket);
bucket = bucket->next();
}
return JSValue::encode(exec->vm().sentinelSetBucket.get());
return JSValue::encode(exec->vm().sentinelSetBucket());
}

EncodedJSValue JSC_HOST_CALL setPrivateFuncSetBucketKey(ExecState* exec)
Expand Down
24 changes: 22 additions & 2 deletions Source/JavaScriptCore/runtime/VM.cpp
Expand Up @@ -401,8 +401,11 @@ VM::VM(VMType vmType, HeapType heapType)
bigIntStructure.set(*this, JSBigInt::createStructure(*this, 0, jsNull()));
executableToCodeBlockEdgeStructure.set(*this, ExecutableToCodeBlockEdge::createStructure(*this, nullptr, jsNull()));

sentinelSetBucket.set(*this, JSSet::BucketType::createSentinel(*this));
sentinelMapBucket.set(*this, JSMap::BucketType::createSentinel(*this));
// Eagerly initialize constant cells since the concurrent compiler can access them.
if (canUseJIT()) {
sentinelMapBucket();
sentinelSetBucket();
}

Thread::current().setCurrentAtomicStringTable(existingEntryAtomicStringTable);

Expand Down Expand Up @@ -1284,6 +1287,23 @@ DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW(moduleProgramExecutableSpace, destructi

#undef DYNAMIC_SPACE_AND_SET_DEFINE_MEMBER_SLOW


JSCell* VM::sentinelSetBucketSlow()
{
ASSERT(!m_sentinelSetBucket);
auto* sentinel = JSSet::BucketType::createSentinel(*this);
m_sentinelSetBucket.set(*this, sentinel);
return sentinel;
}

JSCell* VM::sentinelMapBucketSlow()
{
ASSERT(!m_sentinelMapBucket);
auto* sentinel = JSMap::BucketType::createSentinel(*this);
m_sentinelMapBucket.set(*this, sentinel);
return sentinel;
}

JSGlobalObject* VM::vmEntryGlobalObject(const CallFrame* callFrame) const
{
if (callFrame && callFrame->isGlobalExec()) {
Expand Down
22 changes: 20 additions & 2 deletions Source/JavaScriptCore/runtime/VM.h
Expand Up @@ -539,8 +539,9 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
Strong<Structure> executableToCodeBlockEdgeStructure;

Strong<JSCell> emptyPropertyNameEnumerator;
Strong<JSCell> sentinelSetBucket;
Strong<JSCell> sentinelMapBucket;

Strong<JSCell> m_sentinelSetBucket;
Strong<JSCell> m_sentinelMapBucket;

std::unique_ptr<PromiseDeferredTimer> promiseDeferredTimer;

Expand All @@ -562,6 +563,20 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
AtomicStringTable* atomicStringTable() const { return m_atomicStringTable; }
WTF::SymbolRegistry& symbolRegistry() { return m_symbolRegistry; }

JSCell* sentinelSetBucket()
{
if (LIKELY(m_sentinelSetBucket))
return m_sentinelSetBucket.get();
return sentinelSetBucketSlow();
}

JSCell* sentinelMapBucket()
{
if (LIKELY(m_sentinelMapBucket))
return m_sentinelMapBucket.get();
return sentinelMapBucketSlow();
}

WeakGCMap<SymbolImpl*, Symbol, PtrHash<SymbolImpl*>> symbolImplToSymbolMap;

enum class DeletePropertyMode {
Expand Down Expand Up @@ -890,6 +905,9 @@ class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
static VM*& sharedInstanceInternal();
void createNativeThunk();

JSCell* sentinelSetBucketSlow();
JSCell* sentinelMapBucketSlow();

void updateStackLimits();

bool isSafeToRecurse(void* stackLimit) const
Expand Down

0 comments on commit 1c0cae5

Please sign in to comment.