Diff
Modified: branches/safari-608-branch/Source/_javascript_Core/ChangeLog (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/ChangeLog 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/ChangeLog 2019-08-12 23:41:37 UTC (rev 248556)
@@ -1,3 +1,131 @@
+2019-08-12 Alan Coon <[email protected]>
+
+ Cherry-pick r248027. rdar://problem/53836556
+
+ [JSC] Emit write barrier after storing instead of before storing
+ https://bugs.webkit.org/show_bug.cgi?id=200193
+
+ Reviewed by Saam Barati.
+
+ I reviewed tricky GC-related code including visitChildren and manual writeBarrier, and I found that we have several problems with write-barriers.
+
+ 1. Some write-barriers are emitted before stores happen
+
+ Some code like LazyProperty emits write-barrier before we store the value. This is wrong since JSC has concurrent collector. Let's consider the situation like this.
+
+ 1. Cell "A" is not marked yet
+ 2. Write-barrier is emitted onto "A"
+ 3. Concurrent collector scans "A"
+ 4. Store to "A"'s field happens
+ 5. (4)'s field is not rescaned
+
+ We should emit write-barrier after stores. This patch places write-barriers after stores happen.
+
+ 2. Should emit write-barrier after the stored fields are reachable from the owner.
+
+ We have code that is logically the same to the following.
+
+ ```
+ auto data = ""
+ data->m_field.set(vm, owner, value);
+
+ storeStoreBarrier();
+ owner->m_data = WTFMove(data);
+ ```
+
+ This is not correct. When write-barrier is emitted, the owner cannot reach to the field that is stored.
+ The actual example is AccessCase. We are emitting write-barriers with owner when creating AccessCase, but this is not
+ effective until this AccessCase is chained to StructureStubInfo, which is reachable from CodeBlock.
+
+ I don't think this is actually an issue because currently AccessCase generation is guarded by CodeBlock->m_lock. And CodeBlock::visitChildren takes this lock.
+ But emitting a write-barrier at the right place is still better. This patch places write-barriers when StructureStubInfo::addAccessCase is called.
+
+ Speculative GC fix, it was hard to reproduce the crash since we need to control concurrent collector and main thread's scheduling in an instruction-level.
+
+ * bytecode/BytecodeList.rb:
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::finishCreation):
+ * bytecode/StructureStubInfo.cpp:
+ (JSC::StructureStubInfo::addAccessCase):
+ * bytecode/StructureStubInfo.h:
+ (JSC::StructureStubInfo::considerCaching):
+ * dfg/DFGPlan.cpp:
+ (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
+ * jit/JITOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ (JSC::LLInt::setupGetByIdPrototypeCache):
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/LazyPropertyInlines.h:
+ (JSC::ElementType>::setMayBeNull):
+ * runtime/RegExpCachedResult.h:
+ (JSC::RegExpCachedResult::record):
+
+ git-svn-id: https://svn.webkit.org/repository/webkit/trunk@248027 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+ 2019-07-30 Yusuke Suzuki <[email protected]>
+
+ [JSC] Emit write barrier after storing instead of before storing
+ https://bugs.webkit.org/show_bug.cgi?id=200193
+
+ Reviewed by Saam Barati.
+
+ I reviewed tricky GC-related code including visitChildren and manual writeBarrier, and I found that we have several problems with write-barriers.
+
+ 1. Some write-barriers are emitted before stores happen
+
+ Some code like LazyProperty emits write-barrier before we store the value. This is wrong since JSC has concurrent collector. Let's consider the situation like this.
+
+ 1. Cell "A" is not marked yet
+ 2. Write-barrier is emitted onto "A"
+ 3. Concurrent collector scans "A"
+ 4. Store to "A"'s field happens
+ 5. (4)'s field is not rescaned
+
+ We should emit write-barrier after stores. This patch places write-barriers after stores happen.
+
+ 2. Should emit write-barrier after the stored fields are reachable from the owner.
+
+ We have code that is logically the same to the following.
+
+ ```
+ auto data = ""
+ data->m_field.set(vm, owner, value);
+
+ storeStoreBarrier();
+ owner->m_data = WTFMove(data);
+ ```
+
+ This is not correct. When write-barrier is emitted, the owner cannot reach to the field that is stored.
+ The actual example is AccessCase. We are emitting write-barriers with owner when creating AccessCase, but this is not
+ effective until this AccessCase is chained to StructureStubInfo, which is reachable from CodeBlock.
+
+ I don't think this is actually an issue because currently AccessCase generation is guarded by CodeBlock->m_lock. And CodeBlock::visitChildren takes this lock.
+ But emitting a write-barrier at the right place is still better. This patch places write-barriers when StructureStubInfo::addAccessCase is called.
+
+ Speculative GC fix, it was hard to reproduce the crash since we need to control concurrent collector and main thread's scheduling in an instruction-level.
+
+ * bytecode/BytecodeList.rb:
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::finishCreation):
+ * bytecode/StructureStubInfo.cpp:
+ (JSC::StructureStubInfo::addAccessCase):
+ * bytecode/StructureStubInfo.h:
+ (JSC::StructureStubInfo::considerCaching):
+ * dfg/DFGPlan.cpp:
+ (JSC::DFG::Plan::finalizeWithoutNotifyingCallback):
+ * jit/JITOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+ (JSC::LLInt::setupGetByIdPrototypeCache):
+ * runtime/CommonSlowPaths.cpp:
+ (JSC::SLOW_PATH_DECL):
+ * runtime/LazyPropertyInlines.h:
+ (JSC::ElementType>::setMayBeNull):
+ * runtime/RegExpCachedResult.h:
+ (JSC::RegExpCachedResult::record):
+
2019-08-09 Alan Coon <[email protected]>
Cherry-pick r248462. rdar://problem/54144119
Modified: branches/safari-608-branch/Source/_javascript_Core/bytecode/BytecodeList.rb (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/bytecode/BytecodeList.rb 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/bytecode/BytecodeList.rb 2019-08-12 23:41:37 UTC (rev 248556)
@@ -841,8 +841,8 @@
constantScope: WriteBarrierBase[JSScope],
# written from the slow path
- globalLexicalEnvironment: JSGlobalLexicalEnvironment.*,
- globalObject: JSGlobalObject.*,
+ globalLexicalEnvironment: WriteBarrierBase[JSGlobalLexicalEnvironment],
+ globalObject: WriteBarrierBase[JSGlobalObject],
},
}
Modified: branches/safari-608-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/bytecode/CodeBlock.cpp 2019-08-12 23:41:37 UTC (rev 248556)
@@ -603,7 +603,7 @@
if (op.type == GlobalProperty || op.type == GlobalPropertyWithVarInjectionChecks)
metadata.m_globalLexicalBindingEpoch = m_globalObject->globalLexicalBindingEpoch();
} else
- metadata.m_globalObject = nullptr;
+ metadata.m_globalObject.clear();
break;
}
Modified: branches/safari-608-branch/Source/_javascript_Core/bytecode/StructureStubInfo.cpp (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/bytecode/StructureStubInfo.cpp 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/bytecode/StructureStubInfo.cpp 2019-08-12 23:41:37 UTC (rev 248556)
@@ -136,92 +136,96 @@
const GCSafeConcurrentJSLocker& locker, CodeBlock* codeBlock, const Identifier& ident, std::unique_ptr<AccessCase> accessCase)
{
VM& vm = *codeBlock->vm();
-
- if (StructureStubInfoInternal::verbose)
- dataLog("Adding access case: ", accessCase, "\n");
-
- if (!accessCase)
- return AccessGenerationResult::GaveUp;
-
- AccessGenerationResult result;
-
- if (cacheType == CacheType::Stub) {
- result = u.stub->addCase(locker, vm, codeBlock, *this, ident, WTFMove(accessCase));
+ ASSERT(vm.heap.isDeferred());
+ AccessGenerationResult result = ([&] () -> AccessGenerationResult {
+ if (StructureStubInfoInternal::verbose)
+ dataLog("Adding access case: ", accessCase, "\n");
- if (StructureStubInfoInternal::verbose)
- dataLog("Had stub, result: ", result, "\n");
+ if (!accessCase)
+ return AccessGenerationResult::GaveUp;
+
+ AccessGenerationResult result;
+
+ if (cacheType == CacheType::Stub) {
+ result = u.stub->addCase(locker, vm, codeBlock, *this, ident, WTFMove(accessCase));
+
+ if (StructureStubInfoInternal::verbose)
+ dataLog("Had stub, result: ", result, "\n");
- if (result.shouldResetStubAndFireWatchpoints())
- return result;
+ if (result.shouldResetStubAndFireWatchpoints())
+ return result;
+ if (!result.buffered()) {
+ bufferedStructures.clear();
+ return result;
+ }
+ } else {
+ std::unique_ptr<PolymorphicAccess> access = std::make_unique<PolymorphicAccess>();
+
+ Vector<std::unique_ptr<AccessCase>, 2> accessCases;
+
+ std::unique_ptr<AccessCase> previousCase =
+ AccessCase::fromStructureStubInfo(vm, codeBlock, *this);
+ if (previousCase)
+ accessCases.append(WTFMove(previousCase));
+
+ accessCases.append(WTFMove(accessCase));
+
+ result = access->addCases(locker, vm, codeBlock, *this, ident, WTFMove(accessCases));
+
+ if (StructureStubInfoInternal::verbose)
+ dataLog("Created stub, result: ", result, "\n");
+
+ if (result.shouldResetStubAndFireWatchpoints())
+ return result;
+
+ if (!result.buffered()) {
+ bufferedStructures.clear();
+ return result;
+ }
+
+ cacheType = CacheType::Stub;
+ u.stub = access.release();
+ }
+
+ RELEASE_ASSERT(!result.generatedSomeCode());
+
+ // If we didn't buffer any cases then bail. If this made no changes then we'll just try again
+ // subject to cool-down.
if (!result.buffered()) {
+ if (StructureStubInfoInternal::verbose)
+ dataLog("Didn't buffer anything, bailing.\n");
bufferedStructures.clear();
return result;
}
- } else {
- std::unique_ptr<PolymorphicAccess> access = std::make_unique<PolymorphicAccess>();
- Vector<std::unique_ptr<AccessCase>, 2> accessCases;
+ // The buffering countdown tells us if we should be repatching now.
+ if (bufferingCountdown) {
+ if (StructureStubInfoInternal::verbose)
+ dataLog("Countdown is too high: ", bufferingCountdown, ".\n");
+ return result;
+ }
- std::unique_ptr<AccessCase> previousCase =
- AccessCase::fromStructureStubInfo(vm, codeBlock, *this);
- if (previousCase)
- accessCases.append(WTFMove(previousCase));
+ // Forget the buffered structures so that all future attempts to cache get fully handled by the
+ // PolymorphicAccess.
+ bufferedStructures.clear();
- accessCases.append(WTFMove(accessCase));
+ result = u.stub->regenerate(locker, vm, codeBlock, *this, ident);
- result = access->addCases(locker, vm, codeBlock, *this, ident, WTFMove(accessCases));
+ if (StructureStubInfoInternal::verbose)
+ dataLog("Regeneration result: ", result, "\n");
- if (StructureStubInfoInternal::verbose)
- dataLog("Created stub, result: ", result, "\n");
-
- if (result.shouldResetStubAndFireWatchpoints())
+ RELEASE_ASSERT(!result.buffered());
+
+ if (!result.generatedSomeCode())
return result;
-
- if (!result.buffered()) {
- bufferedStructures.clear();
- return result;
- }
- cacheType = CacheType::Stub;
- u.stub = access.release();
- }
-
- RELEASE_ASSERT(!result.generatedSomeCode());
-
- // If we didn't buffer any cases then bail. If this made no changes then we'll just try again
- // subject to cool-down.
- if (!result.buffered()) {
- if (StructureStubInfoInternal::verbose)
- dataLog("Didn't buffer anything, bailing.\n");
- bufferedStructures.clear();
+ // If we generated some code then we don't want to attempt to repatch in the future until we
+ // gather enough cases.
+ bufferingCountdown = Options::repatchBufferingCountdown();
return result;
- }
-
- // The buffering countdown tells us if we should be repatching now.
- if (bufferingCountdown) {
- if (StructureStubInfoInternal::verbose)
- dataLog("Countdown is too high: ", bufferingCountdown, ".\n");
- return result;
- }
-
- // Forget the buffered structures so that all future attempts to cache get fully handled by the
- // PolymorphicAccess.
- bufferedStructures.clear();
-
- result = u.stub->regenerate(locker, vm, codeBlock, *this, ident);
-
- if (StructureStubInfoInternal::verbose)
- dataLog("Regeneration result: ", result, "\n");
-
- RELEASE_ASSERT(!result.buffered());
-
- if (!result.generatedSomeCode())
- return result;
-
- // If we generated some code then we don't want to attempt to repatch in the future until we
- // gather enough cases.
- bufferingCountdown = Options::repatchBufferingCountdown();
+ })();
+ vm.heap.writeBarrier(codeBlock);
return result;
}
Modified: branches/safari-608-branch/Source/_javascript_Core/bytecode/StructureStubInfo.h (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/bytecode/StructureStubInfo.h 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/bytecode/StructureStubInfo.h 2019-08-12 23:41:37 UTC (rev 248556)
@@ -92,8 +92,10 @@
// This returns true if it has marked everything that it will ever mark.
bool propagateTransitions(SlotVisitor&);
- ALWAYS_INLINE bool considerCaching(CodeBlock* codeBlock, Structure* structure)
+ ALWAYS_INLINE bool considerCaching(VM& vm, CodeBlock* codeBlock, Structure* structure)
{
+ DisallowGC disallowGC;
+
// We never cache non-cells.
if (!structure) {
sawNonCell = true;
@@ -151,10 +153,8 @@
// the base's structure. That seems unlikely for the canonical use of instanceof, where
// the prototype is fixed.
bool isNewlyAdded = bufferedStructures.add(structure);
- if (isNewlyAdded) {
- VM& vm = *codeBlock->vm();
+ if (isNewlyAdded)
vm.heap.writeBarrier(codeBlock);
- }
return isNewlyAdded;
}
countdown--;
Modified: branches/safari-608-branch/Source/_javascript_Core/dfg/DFGPlan.cpp (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/dfg/DFGPlan.cpp 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/dfg/DFGPlan.cpp 2019-08-12 23:41:37 UTC (rev 248556)
@@ -581,49 +581,56 @@
CompilationResult Plan::finalizeWithoutNotifyingCallback()
{
- // We will establish new references from the code block to things. So, we need a barrier.
- m_vm->heap.writeBarrier(m_codeBlock);
+ // We perform multiple stores before emitting a write-barrier. To ensure that no GC happens between store and write-barrier, we should ensure that
+ // GC is deferred when this function is called.
+ ASSERT(m_vm->heap.isDeferred());
- if (!isStillValidOnMainThread() || !isStillValid()) {
- CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("invalidated"));
- return CompilationInvalidated;
- }
+ CompilationResult result = [&] {
+ if (!isStillValidOnMainThread() || !isStillValid()) {
+ CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("invalidated"));
+ return CompilationInvalidated;
+ }
- bool result;
- if (m_codeBlock->codeType() == FunctionCode)
- result = m_finalizer->finalizeFunction();
- else
- result = m_finalizer->finalize();
+ bool result;
+ if (m_codeBlock->codeType() == FunctionCode)
+ result = m_finalizer->finalizeFunction();
+ else
+ result = m_finalizer->finalize();
- if (!result) {
- CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("failed"));
- return CompilationFailed;
- }
+ if (!result) {
+ CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("failed"));
+ return CompilationFailed;
+ }
- reallyAdd(m_codeBlock->jitCode()->dfgCommon());
+ reallyAdd(m_codeBlock->jitCode()->dfgCommon());
- if (validationEnabled()) {
- TrackedReferences trackedReferences;
+ if (validationEnabled()) {
+ TrackedReferences trackedReferences;
- for (WriteBarrier<JSCell>& reference : m_codeBlock->jitCode()->dfgCommon()->weakReferences)
- trackedReferences.add(reference.get());
- for (WriteBarrier<Structure>& reference : m_codeBlock->jitCode()->dfgCommon()->weakStructureReferences)
- trackedReferences.add(reference.get());
- for (WriteBarrier<Unknown>& constant : m_codeBlock->constants())
- trackedReferences.add(constant.get());
+ for (WriteBarrier<JSCell>& reference : m_codeBlock->jitCode()->dfgCommon()->weakReferences)
+ trackedReferences.add(reference.get());
+ for (WriteBarrier<Structure>& reference : m_codeBlock->jitCode()->dfgCommon()->weakStructureReferences)
+ trackedReferences.add(reference.get());
+ for (WriteBarrier<Unknown>& constant : m_codeBlock->constants())
+ trackedReferences.add(constant.get());
- for (auto* inlineCallFrame : *m_inlineCallFrames) {
- ASSERT(inlineCallFrame->baselineCodeBlock.get());
- trackedReferences.add(inlineCallFrame->baselineCodeBlock.get());
+ for (auto* inlineCallFrame : *m_inlineCallFrames) {
+ ASSERT(inlineCallFrame->baselineCodeBlock.get());
+ trackedReferences.add(inlineCallFrame->baselineCodeBlock.get());
+ }
+
+ // Check that any other references that we have anywhere in the JITCode are also
+ // tracked either strongly or weakly.
+ m_codeBlock->jitCode()->validateReferences(trackedReferences);
}
- // Check that any other references that we have anywhere in the JITCode are also
- // tracked either strongly or weakly.
- m_codeBlock->jitCode()->validateReferences(trackedReferences);
- }
+ CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("succeeded"));
+ return CompilationSuccessful;
+ }();
- CODEBLOCK_LOG_EVENT(m_codeBlock, "dfgFinalize", ("succeeded"));
- return CompilationSuccessful;
+ // We will establish new references from the code block to things. So, we need a barrier.
+ m_vm->heap.writeBarrier(m_codeBlock);
+ return result;
}
void Plan::finalizeAndNotifyCallback()
Modified: branches/safari-608-branch/Source/_javascript_Core/jit/JITOperations.cpp (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/jit/JITOperations.cpp 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/jit/JITOperations.cpp 2019-08-12 23:41:37 UTC (rev 248556)
@@ -182,7 +182,7 @@
baseValue.getPropertySlot(exec, ident, slot);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- if (stubInfo->considerCaching(exec->codeBlock(), baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset()))
+ if (stubInfo->considerCaching(*vm, exec->codeBlock(), baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset()))
repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Try);
return JSValue::encode(slot.getPureResult());
@@ -234,7 +234,7 @@
bool found = baseValue.getOwnPropertySlot(exec, ident, slot);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- if (stubInfo->considerCaching(exec->codeBlock(), baseValue.structureOrNull()))
+ if (stubInfo->considerCaching(vm, exec->codeBlock(), baseValue.structureOrNull()))
repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Direct);
RELEASE_AND_RETURN(scope, JSValue::encode(found ? slot.getValue(exec, ident) : jsUndefined()));
@@ -290,7 +290,7 @@
LOG_IC((ICEvent::OperationGetByIdOptimize, baseValue.classInfoOrNull(*vm), ident, baseValue == slot.slotBase()));
- if (stubInfo->considerCaching(exec->codeBlock(), baseValue.structureOrNull()))
+ if (stubInfo->considerCaching(*vm, exec->codeBlock(), baseValue.structureOrNull()))
repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Normal);
return found ? slot.getValue(exec, ident) : jsUndefined();
}));
@@ -343,7 +343,7 @@
return JSValue::encode(baseValue.getPropertySlot(exec, ident, slot, [&] (bool found, PropertySlot& slot) -> JSValue {
LOG_IC((ICEvent::OperationGetByIdWithThisOptimize, baseValue.classInfoOrNull(*vm), ident, baseValue == slot.slotBase()));
- if (stubInfo->considerCaching(exec->codeBlock(), baseValue.structureOrNull()))
+ if (stubInfo->considerCaching(*vm, exec->codeBlock(), baseValue.structureOrNull()))
repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::WithThis);
return found ? slot.getValue(exec, ident) : jsUndefined();
}));
@@ -421,7 +421,7 @@
scope.release();
PropertySlot slot(baseObject, PropertySlot::InternalMethodType::HasProperty);
bool found = baseObject->getPropertySlot(exec, ident, slot);
- if (stubInfo->considerCaching(exec->codeBlock(), baseObject->structure(vm)))
+ if (stubInfo->considerCaching(vm, exec->codeBlock(), baseObject->structure(vm)))
repatchInByID(exec, baseObject, ident, found, slot, *stubInfo);
return JSValue::encode(jsBoolean(found));
}
@@ -530,7 +530,7 @@
if (accessType != static_cast<AccessType>(stubInfo->accessType))
return;
- if (stubInfo->considerCaching(codeBlock, structure))
+ if (stubInfo->considerCaching(*vm, codeBlock, structure))
repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
}
@@ -560,7 +560,7 @@
if (accessType != static_cast<AccessType>(stubInfo->accessType))
return;
- if (stubInfo->considerCaching(codeBlock, structure))
+ if (stubInfo->considerCaching(*vm, codeBlock, structure))
repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
}
@@ -589,7 +589,7 @@
if (accessType != static_cast<AccessType>(stubInfo->accessType))
return;
- if (stubInfo->considerCaching(codeBlock, structure))
+ if (stubInfo->considerCaching(vm, codeBlock, structure))
repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
}
@@ -618,7 +618,7 @@
if (accessType != static_cast<AccessType>(stubInfo->accessType))
return;
- if (stubInfo->considerCaching(codeBlock, structure))
+ if (stubInfo->considerCaching(vm, codeBlock, structure))
repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
}
@@ -2229,7 +2229,7 @@
bool result = JSObject::defaultHasInstance(exec, value, proto);
RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
- if (stubInfo->considerCaching(exec->codeBlock(), value.structureOrNull()))
+ if (stubInfo->considerCaching(vm, exec->codeBlock(), value.structureOrNull()))
repatchInstanceOf(exec, value, proto, *stubInfo, result);
return JSValue::encode(jsBoolean(result));
Modified: branches/safari-608-branch/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2019-08-12 23:41:37 UTC (rev 248556)
@@ -677,14 +677,13 @@
metadata.m_structureID = 0;
metadata.m_offset = 0;
- if (structure->propertyAccessesAreCacheable()
- && !structure->needImpurePropertyWatchpoint()) {
+ if (structure->propertyAccessesAreCacheable() && !structure->needImpurePropertyWatchpoint()) {
+ {
+ ConcurrentJSLocker locker(codeBlock->m_lock);
+ metadata.m_structureID = structure->id();
+ metadata.m_offset = slot.cachedOffset();
+ }
vm.heap.writeBarrier(codeBlock);
-
- ConcurrentJSLocker locker(codeBlock->m_lock);
-
- metadata.m_structureID = structure->id();
- metadata.m_offset = slot.cachedOffset();
}
}
}
@@ -737,15 +736,16 @@
auto result = watchpointMap.add(std::make_tuple(structure->id(), bytecodeOffset), WTFMove(watchpoints));
ASSERT_UNUSED(result, result.isNewEntry);
- ConcurrentJSLocker locker(codeBlock->m_lock);
-
- if (slot.isUnset()) {
- metadata.m_modeMetadata.setUnsetMode(structure);
- return;
+ {
+ ConcurrentJSLocker locker(codeBlock->m_lock);
+ if (slot.isUnset())
+ metadata.m_modeMetadata.setUnsetMode(structure);
+ else {
+ ASSERT(slot.isValue());
+ metadata.m_modeMetadata.setProtoLoadMode(structure, offset, slot.slotBase());
+ }
}
- ASSERT(slot.isValue());
-
- metadata.m_modeMetadata.setProtoLoadMode(structure, offset, slot.slotBase());
+ vm.heap.writeBarrier(codeBlock);
}
@@ -796,7 +796,6 @@
Structure* structure = baseCell->structure(vm);
if (slot.isValue() && slot.slotBase() == baseValue) {
ConcurrentJSLocker locker(codeBlock->m_lock);
-
// Start out by clearing out the old cache.
metadata.m_modeMetadata.clearToDefaultModeWithoutCache();
@@ -803,12 +802,10 @@
// Prevent the prototype cache from ever happening.
metadata.m_modeMetadata.hitCountForLLIntCaching = 0;
- if (structure->propertyAccessesAreCacheable()
- && !structure->needImpurePropertyWatchpoint()) {
- vm.heap.writeBarrier(codeBlock);
-
+ if (structure->propertyAccessesAreCacheable() && !structure->needImpurePropertyWatchpoint()) {
metadata.m_modeMetadata.defaultMode.structureID = structure->id();
metadata.m_modeMetadata.defaultMode.cachedOffset = slot.cachedOffset();
+ vm.heap.writeBarrier(codeBlock);
}
} else if (UNLIKELY(metadata.m_modeMetadata.hitCountForLLIntCaching && (slot.isValue() || slot.isUnset()))) {
ASSERT(slot.slotBase() != baseValue);
@@ -816,12 +813,13 @@
if (!(--metadata.m_modeMetadata.hitCountForLLIntCaching))
setupGetByIdPrototypeCache(exec, vm, pc, metadata, baseCell, slot, ident);
}
- } else if (!LLINT_ALWAYS_ACCESS_SLOW
- && isJSArray(baseValue)
- && ident == vm.propertyNames->length) {
- ConcurrentJSLocker locker(codeBlock->m_lock);
- metadata.m_modeMetadata.setArrayLengthMode();
- metadata.m_modeMetadata.arrayLengthMode.arrayProfile.observeStructure(baseValue.asCell()->structure(vm));
+ } else if (!LLINT_ALWAYS_ACCESS_SLOW && isJSArray(baseValue) && ident == vm.propertyNames->length) {
+ {
+ ConcurrentJSLocker locker(codeBlock->m_lock);
+ metadata.m_modeMetadata.setArrayLengthMode();
+ metadata.m_modeMetadata.arrayLengthMode.arrayProfile.observeStructure(baseValue.asCell()->structure(vm));
+ }
+ vm.heap.writeBarrier(codeBlock);
}
LLINT_PROFILE_VALUE(result);
@@ -872,15 +870,9 @@
JSCell* baseCell = baseValue.asCell();
Structure* structure = baseCell->structure(vm);
- if (!structure->isUncacheableDictionary()
- && !structure->typeInfo().prohibitsPropertyCaching()
- && baseCell == slot.base()) {
-
- vm.heap.writeBarrier(codeBlock);
-
+ if (!structure->isUncacheableDictionary() && !structure->typeInfo().prohibitsPropertyCaching() && baseCell == slot.base()) {
if (slot.type() == PutPropertySlot::NewProperty) {
GCSafeConcurrentJSLocker locker(codeBlock->m_lock, vm.heap);
-
if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) {
ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated());
@@ -896,12 +888,17 @@
ASSERT(chain);
metadata.m_structureChain.set(vm, codeBlock, chain);
}
+ vm.heap.writeBarrier(codeBlock);
}
}
} else {
structure->didCachePropertyReplacement(vm, slot.cachedOffset());
- metadata.m_oldStructureID = structure->id();
- metadata.m_offset = slot.cachedOffset();
+ {
+ ConcurrentJSLocker locker(codeBlock->m_lock);
+ metadata.m_oldStructureID = structure->id();
+ metadata.m_offset = slot.cachedOffset();
+ }
+ vm.heap.writeBarrier(codeBlock);
}
}
}
Modified: branches/safari-608-branch/Source/_javascript_Core/runtime/CommonSlowPaths.cpp (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/runtime/CommonSlowPaths.cpp 2019-08-12 23:41:37 UTC (rev 248556)
@@ -1072,7 +1072,8 @@
BEGIN();
auto bytecode = pc->as<OpResolveScope>();
auto& metadata = bytecode.metadata(exec);
- const Identifier& ident = exec->codeBlock()->identifier(bytecode.m_var);
+ CodeBlock* codeBlock = exec->codeBlock();
+ const Identifier& ident = codeBlock->identifier(bytecode.m_var);
JSScope* scope = exec->uncheckedR(bytecode.m_scope.offset()).Register::scope();
JSObject* resolvedScope = JSScope::resolve(exec, scope, ident);
// Proxy can throw an error here, e.g. Proxy in with statement's @unscopables.
@@ -1093,16 +1094,16 @@
bool hasProperty = globalObject->hasProperty(exec, ident);
CHECK_EXCEPTION();
if (hasProperty) {
- ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
+ ConcurrentJSLocker locker(codeBlock->m_lock);
metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalPropertyWithVarInjectionChecks : GlobalProperty;
- metadata.m_globalObject = globalObject;
+ metadata.m_globalObject.set(vm, codeBlock, globalObject);
metadata.m_globalLexicalBindingEpoch = globalObject->globalLexicalBindingEpoch();
}
} else if (resolvedScope->isGlobalLexicalEnvironment()) {
JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(resolvedScope);
- ConcurrentJSLocker locker(exec->codeBlock()->m_lock);
+ ConcurrentJSLocker locker(codeBlock->m_lock);
metadata.m_resolveType = needsVarInjectionChecks(resolveType) ? GlobalLexicalVarWithVarInjectionChecks : GlobalLexicalVar;
- metadata.m_globalLexicalEnvironment = globalLexicalEnvironment;
+ metadata.m_globalLexicalEnvironment.set(vm, codeBlock, globalLexicalEnvironment);
}
break;
}
Modified: branches/safari-608-branch/Source/_javascript_Core/runtime/LazyPropertyInlines.h (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/runtime/LazyPropertyInlines.h 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/runtime/LazyPropertyInlines.h 2019-08-12 23:41:37 UTC (rev 248556)
@@ -53,9 +53,9 @@
template<typename OwnerType, typename ElementType>
void LazyProperty<OwnerType, ElementType>::setMayBeNull(VM& vm, const OwnerType* owner, ElementType* value)
{
- vm.heap.writeBarrier(owner, value);
m_pointer = bitwise_cast<uintptr_t>(value);
RELEASE_ASSERT(!(m_pointer & lazyTag));
+ vm.heap.writeBarrier(owner, value);
}
template<typename OwnerType, typename ElementType>
Modified: branches/safari-608-branch/Source/_javascript_Core/runtime/RegExpCachedResult.h (248555 => 248556)
--- branches/safari-608-branch/Source/_javascript_Core/runtime/RegExpCachedResult.h 2019-08-12 23:41:33 UTC (rev 248555)
+++ branches/safari-608-branch/Source/_javascript_Core/runtime/RegExpCachedResult.h 2019-08-12 23:41:37 UTC (rev 248556)
@@ -47,11 +47,11 @@
public:
ALWAYS_INLINE void record(VM& vm, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result)
{
- vm.heap.writeBarrier(owner);
m_lastRegExp.setWithoutWriteBarrier(regExp);
m_lastInput.setWithoutWriteBarrier(input);
m_result = result;
m_reified = false;
+ vm.heap.writeBarrier(owner);
}
JSArray* lastResult(ExecState*, JSObject* owner);