Diff
Modified: trunk/JSTests/ChangeLog (265271 => 265272)
--- trunk/JSTests/ChangeLog 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/JSTests/ChangeLog 2020-08-05 01:32:52 UTC (rev 265272)
@@ -1,3 +1,15 @@
+2020-08-04 Keith Miller <keith_mil...@apple.com>
+
+ CheckpointSideState shoud play nicely with StackOverflowException unwinding.
+ https://bugs.webkit.org/show_bug.cgi?id=215114
+
+ Reviewed by Saam Barati.
+
+ * stress/stack-overflow-into-frame-with-pending-checkpoint.js: Added.
+ (foo.catch.async bar):
+ (foo.catch):
+ (foo):
+
2020-08-03 Caio Lima <ticaiol...@gmail.com>
[JSC][MIPS] Test gardening July 31st edition
Added: trunk/JSTests/stress/stack-overflow-into-frame-with-pending-checkpoint.js (0 => 265272)
--- trunk/JSTests/stress/stack-overflow-into-frame-with-pending-checkpoint.js (rev 0)
+++ trunk/JSTests/stress/stack-overflow-into-frame-with-pending-checkpoint.js 2020-08-05 01:32:52 UTC (rev 265272)
@@ -0,0 +1,19 @@
+//@ requireOptions("--jitPolicyScale=0")
+
+function foo() {
+ 'use strict'
+ try {
+ foo();
+ } catch(e) {
+ ({__proto__:0});
+ async function bar(a0) {
+ bar(a0, ...[0]);
+ }
+ for (let i=0; i<1000; i++) {
+ bar();
+ }
+ bar(0, 0);
+ }
+}
+
+foo();
Modified: trunk/Source/_javascript_Core/ChangeLog (265271 => 265272)
--- trunk/Source/_javascript_Core/ChangeLog 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/ChangeLog 2020-08-05 01:32:52 UTC (rev 265272)
@@ -1,3 +1,67 @@
+2020-08-04 Keith Miller <keith_mil...@apple.com>
+
+ CheckpointSideState shoud play nicely with StackOverflowException unwinding.
+ https://bugs.webkit.org/show_bug.cgi?id=215114
+
+ Reviewed by Saam Barati.
+
+ This patch fixes an issue where we the StackVisitor would
+ automatically unwind into the first frame before calling into the
+ provided functor. As a note, we do this because the first frame is
+ not fully initialized at the time we check for stack
+ overflow. When this happened we would fail to clear the side state
+ causing a memory leak. To fix this the unwind function now clears
+ every checkpoint up to and including the call frame containing our
+ handler. Some care needs to be taken that we don't clear
+ checkpoint side state for other threads, which could happen if
+ there are no checkpoints on the current thread and an API
+ miggrated us from another thread below the current thread.
+
+ This patch also makes two refacorings. The first is to make the
+ checkpoint side state into a stack, which is how we used it
+ anyway. The second is that CallFrame::dump and everything associated
+ with it is now marked const so we can PointerDump a CallFrame*.
+
+ * dfg/DFGOSRExit.cpp:
+ (JSC::DFG::OSRExit::compileExit):
+ * ftl/FTLOSRExitCompiler.cpp:
+ (JSC::FTL::compileStub):
+ * interpreter/CallFrame.cpp:
+ (JSC::CallFrame::bytecodeIndex const):
+ (JSC::CallFrame::codeOrigin const):
+ (JSC::CallFrame::dump const):
+ (JSC::CallFrame::bytecodeIndex): Deleted.
+ (JSC::CallFrame::codeOrigin): Deleted.
+ (JSC::CallFrame::dump): Deleted.
+ * interpreter/CallFrame.h:
+ (JSC::CallFrame::argument const):
+ (JSC::CallFrame::uncheckedArgument const):
+ (JSC::CallFrame::getArgumentUnsafe const):
+ (JSC::CallFrame::thisValue const):
+ (JSC::CallFrame::newTarget const):
+ (JSC::CallFrame::argument): Deleted.
+ (JSC::CallFrame::uncheckedArgument): Deleted.
+ (JSC::CallFrame::getArgumentUnsafe): Deleted.
+ (JSC::CallFrame::thisValue): Deleted.
+ (JSC::CallFrame::newTarget): Deleted.
+ * interpreter/CheckpointOSRExitSideState.h:
+ (JSC::CheckpointOSRExitSideState::CheckpointOSRExitSideState):
+ * interpreter/Interpreter.cpp:
+ (JSC::UnwindFunctor::operator() const):
+ (JSC::Interpreter::unwind):
+ (): Deleted.
+ * llint/LLIntSlowPaths.cpp:
+ (JSC::LLInt::slow_path_checkpoint_osr_exit_from_inlined_call):
+ (JSC::LLInt::slow_path_checkpoint_osr_exit):
+ * runtime/VM.cpp:
+ (JSC::VM::scanSideState const):
+ (JSC::VM::pushCheckpointOSRSideState):
+ (JSC::VM::popCheckpointOSRSideState):
+ (JSC::VM::popAllCheckpointOSRSideStateUntil):
+ (JSC::VM::addCheckpointOSRSideState): Deleted.
+ (JSC::VM::findCheckpointOSRSideState): Deleted.
+ * runtime/VM.h:
+
2020-08-03 Alberto Garcia <be...@igalia.com>
[GTK] 2.29.4 fails to build in armhf
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp (265271 => 265272)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp 2020-08-05 01:32:52 UTC (rev 265272)
@@ -42,6 +42,8 @@
#include "OperandsInlines.h"
#include "ProbeContext.h"
+#include <wtf/Scope.h>
+
namespace JSC { namespace DFG {
OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAValueProfile valueProfile, SpeculativeJIT* jit, unsigned streamIndex, unsigned recoveryIndex)
@@ -591,8 +593,16 @@
VM* vmPtr = &vm;
auto* tmpScratch = scratch + operands.tmpIndex(0);
jit.probe([=, values = WTFMove(values)] (Probe::Context& context) {
+ Vector<std::unique_ptr<CheckpointOSRExitSideState>> sideStates;
+ sideStates.reserveInitialCapacity(exit.m_codeOrigin.inlineDepth());
+ auto sideStateCommitter = makeScopeExit([&] {
+ for (size_t i = sideStates.size(); i--;)
+ vmPtr->pushCheckpointOSRSideState(WTFMove(sideStates[i]));
+ });
+
+
auto addSideState = [&] (CallFrame* frame, BytecodeIndex index, size_t tmpOffset) {
- std::unique_ptr<CheckpointOSRExitSideState> sideState = WTF::makeUnique<CheckpointOSRExitSideState>();
+ std::unique_ptr<CheckpointOSRExitSideState> sideState = WTF::makeUnique<CheckpointOSRExitSideState>(frame);
sideState->bytecodeIndex = index;
for (size_t i = 0; i < maxNumCheckpointTmps; ++i) {
@@ -650,7 +660,7 @@
}
}
- vmPtr->addCheckpointOSRSideState(frame, WTFMove(sideState));
+ sideStates.append(WTFMove(sideState));
};
const CodeOrigin* codeOrigin;
Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp (265271 => 265272)
--- trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExitCompiler.cpp 2020-08-05 01:32:52 UTC (rev 265272)
@@ -43,6 +43,8 @@
#include "OperandsInlines.h"
#include "ProbeContext.h"
+#include <wtf/Scope.h>
+
namespace JSC { namespace FTL {
using namespace DFG;
@@ -481,14 +483,21 @@
JSValue* tmpScratch = reinterpret_cast<JSValue*>(scratch + exit.m_descriptor->m_values.tmpIndex(0));
VM* vmPtr = &vm;
jit.probe([=] (Probe::Context& context) {
+ Vector<std::unique_ptr<CheckpointOSRExitSideState>> sideStates;
+ sideStates.reserveInitialCapacity(exit.m_codeOrigin.inlineDepth());
+ auto sideStateCommitter = makeScopeExit([&] {
+ for (size_t i = sideStates.size(); i--;)
+ vmPtr->pushCheckpointOSRSideState(WTFMove(sideStates[i]));
+ });
+
auto addSideState = [&] (CallFrame* frame, BytecodeIndex index, size_t tmpOffset) {
- std::unique_ptr<CheckpointOSRExitSideState> sideState = WTF::makeUnique<CheckpointOSRExitSideState>();
+ std::unique_ptr<CheckpointOSRExitSideState> sideState = WTF::makeUnique<CheckpointOSRExitSideState>(frame);
sideState->bytecodeIndex = index;
for (size_t i = 0; i < maxNumCheckpointTmps; ++i)
sideState->tmps[i] = tmpScratch[i + tmpOffset];
- vmPtr->addCheckpointOSRSideState(frame, WTFMove(sideState));
+ sideStates.append(WTFMove(sideState));
};
const CodeOrigin* codeOrigin;
Modified: trunk/Source/_javascript_Core/interpreter/CallFrame.cpp (265271 => 265272)
--- trunk/Source/_javascript_Core/interpreter/CallFrame.cpp 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/interpreter/CallFrame.cpp 2020-08-05 01:32:52 UTC (rev 265272)
@@ -127,7 +127,7 @@
return callSiteIndex().bits();
}
-BytecodeIndex CallFrame::bytecodeIndex()
+BytecodeIndex CallFrame::bytecodeIndex() const
{
ASSERT(!callee().isWasm());
if (!codeBlock())
@@ -147,7 +147,7 @@
return callSiteIndex().bytecodeIndex();
}
-CodeOrigin CallFrame::codeOrigin()
+CodeOrigin CallFrame::codeOrigin() const
{
if (!codeBlock())
return CodeOrigin(BytecodeIndex(0));
@@ -267,7 +267,7 @@
return emptyString();
}
-void CallFrame::dump(PrintStream& out)
+void CallFrame::dump(PrintStream& out) const
{
if (CodeBlock* codeBlock = this->codeBlock()) {
out.print(codeBlock->inferredName(), "#", codeBlock->hashAsStringIfPossible(), " [", codeBlock->jitType(), " ", bytecodeIndex(), "]");
Modified: trunk/Source/_javascript_Core/interpreter/CallFrame.h (265271 => 265272)
--- trunk/Source/_javascript_Core/interpreter/CallFrame.h 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/interpreter/CallFrame.h 2020-08-05 01:32:52 UTC (rev 265272)
@@ -174,11 +174,11 @@
// also return 0 if the call frame has no notion of bytecode offsets (for
// example if it's native code).
// https://bugs.webkit.org/show_bug.cgi?id=121754
- BytecodeIndex bytecodeIndex();
+ BytecodeIndex bytecodeIndex() const;
// This will get you a CodeOrigin. It will always succeed. May return
// CodeOrigin(BytecodeIndex(0)) if we're in native code.
- JS_EXPORT_PRIVATE CodeOrigin codeOrigin();
+ JS_EXPORT_PRIVATE CodeOrigin codeOrigin() const;
inline Register* topOfFrame();
@@ -211,13 +211,13 @@
// use thisValue() and setThisValue() below.
JSValue* addressOfArgumentsStart() const { return bitwise_cast<JSValue*>(this + argumentOffset(0)); }
- JSValue argument(size_t argument)
+ JSValue argument(size_t argument) const
{
if (argument >= argumentCount())
return jsUndefined();
return getArgumentUnsafe(argument);
}
- JSValue uncheckedArgument(size_t argument)
+ JSValue uncheckedArgument(size_t argument) const
{
ASSERT(argument < argumentCount());
return getArgumentUnsafe(argument);
@@ -227,7 +227,7 @@
this[argumentOffset(argument)] = value;
}
- JSValue getArgumentUnsafe(size_t argIndex)
+ JSValue getArgumentUnsafe(size_t argIndex) const
{
// User beware! This method does not verify that there is a valid
// argument at the specified argIndex. This is used for debugging
@@ -237,12 +237,12 @@
}
static int thisArgumentOffset() { return argumentOffsetIncludingThis(0); }
- JSValue thisValue() { return this[thisArgumentOffset()].jsValue(); }
+ JSValue thisValue() const { return this[thisArgumentOffset()].jsValue(); }
void setThisValue(JSValue value) { this[thisArgumentOffset()] = value; }
// Under the constructor implemented in C++, thisValue holds the newTarget instead of the automatically constructed value.
// The result of this function is only effective under the "construct" context.
- JSValue newTarget() { return thisValue(); }
+ JSValue newTarget() const { return thisValue(); }
JSValue argumentAfterCapture(size_t argument);
@@ -278,7 +278,7 @@
StackVisitor::visit<action, Functor>(this, vm, functor);
}
- void dump(PrintStream&);
+ void dump(PrintStream&) const;
// This function is used in LLDB btjs.
JS_EXPORT_PRIVATE const char* describeFrame();
Modified: trunk/Source/_javascript_Core/interpreter/CheckpointOSRExitSideState.h (265271 => 265272)
--- trunk/Source/_javascript_Core/interpreter/CheckpointOSRExitSideState.h 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/interpreter/CheckpointOSRExitSideState.h 2020-08-05 01:32:52 UTC (rev 265272)
@@ -33,7 +33,11 @@
struct CheckpointOSRExitSideState {
WTF_MAKE_FAST_ALLOCATED;
public:
+ CheckpointOSRExitSideState(CallFrame* frame)
+ : associatedCallFrame(frame)
+ { }
+ CallFrame* associatedCallFrame;
BytecodeIndex bytecodeIndex;
JSValue tmps[maxNumCheckpointTmps] { };
};
Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (265271 => 265272)
--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp 2020-08-05 01:32:52 UTC (rev 265272)
@@ -524,11 +524,6 @@
m_handler = nullptr;
if (m_codeBlock) {
- // FIXME: We should support exception handling in checkpoints.
-#if ENABLE(DFG_JIT)
- if (removeCodePtrTag(m_returnPC) == LLInt::getCodePtr<NoPtrTag>(checkpoint_osr_exit_from_inlined_call_trampoline).executableAddress())
- m_codeBlock->vm().findCheckpointOSRSideState(m_callFrame);
-#endif
if (!m_isTermination) {
m_handler = findExceptionHandler(visitor, m_codeBlock, RequiredHandler::AnyHandler);
if (m_handler)
@@ -551,7 +546,6 @@
if (shouldStopUnwinding)
return StackVisitor::Done;
- m_returnPC = m_callFrame->returnPC().value();
return StackVisitor::Continue;
}
@@ -588,7 +582,6 @@
bool m_isTermination;
CodeBlock*& m_codeBlock;
HandlerInfo*& m_handler;
- mutable const void* m_returnPC { nullptr };
};
NEVER_INLINE HandlerInfo* Interpreter::unwind(VM& vm, CallFrame*& callFrame, Exception* exception)
@@ -612,6 +605,9 @@
HandlerInfo* handler = nullptr;
UnwindFunctor functor(vm, callFrame, isTerminatedExecutionException(vm, exception), codeBlock, handler);
StackVisitor::visit<StackVisitor::TerminateIfTopEntryFrameIsEmpty>(callFrame, vm, functor);
+ if (vm.hasCheckpointOSRSideState())
+ vm.popAllCheckpointOSRSideStateUntil(callFrame);
+
if (!handler)
return nullptr;
Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (265271 => 265272)
--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp 2020-08-05 01:32:52 UTC (rev 265272)
@@ -2202,7 +2202,7 @@
SlowPathFrameTracer tracer(vm, callFrame);
auto scope = DECLARE_THROW_SCOPE(vm);
- std::unique_ptr<CheckpointOSRExitSideState> sideState = vm.findCheckpointOSRSideState(callFrame);
+ std::unique_ptr<CheckpointOSRExitSideState> sideState = vm.popCheckpointOSRSideState(callFrame);
BytecodeIndex bytecodeIndex = sideState->bytecodeIndex;
ASSERT(bytecodeIndex.checkpoint());
@@ -2253,7 +2253,7 @@
JSGlobalObject* globalObject = codeBlock->globalObject();
- std::unique_ptr<CheckpointOSRExitSideState> sideState = vm.findCheckpointOSRSideState(callFrame);
+ std::unique_ptr<CheckpointOSRExitSideState> sideState = vm.popCheckpointOSRSideState(callFrame);
BytecodeIndex bytecodeIndex = sideState->bytecodeIndex;
ASSERT(bytecodeIndex.checkpoint());
Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (265271 => 265272)
--- trunk/Source/_javascript_Core/runtime/VM.cpp 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp 2020-08-05 01:32:52 UTC (rev 265272)
@@ -1078,27 +1078,43 @@
void VM::scanSideState(ConservativeRoots& roots) const
{
ASSERT(heap.worldIsStopped());
- for (const auto& iter : m_checkpointSideState) {
- static_assert(sizeof(iter.value->tmps) / sizeof(JSValue) == maxNumCheckpointTmps);
- roots.add(iter.value->tmps, iter.value->tmps + maxNumCheckpointTmps);
+ for (const auto& sideState : m_checkpointSideState) {
+ static_assert(sizeof(sideState->tmps) / sizeof(JSValue) == maxNumCheckpointTmps);
+ roots.add(sideState->tmps, sideState->tmps + maxNumCheckpointTmps);
}
}
#endif
-void VM::addCheckpointOSRSideState(CallFrame* callFrame, std::unique_ptr<CheckpointOSRExitSideState>&& payload)
+void VM::pushCheckpointOSRSideState(std::unique_ptr<CheckpointOSRExitSideState>&& payload)
{
ASSERT(currentThreadIsHoldingAPILock());
- auto addResult = m_checkpointSideState.add(callFrame, WTFMove(payload));
- ASSERT_UNUSED(addResult, addResult.isNewEntry);
+ ASSERT(payload->associatedCallFrame);
+#if ASSERT_ENABLED
+ for (const auto& sideState : m_checkpointSideState)
+ ASSERT(sideState->associatedCallFrame != payload->associatedCallFrame);
+#endif
+ m_checkpointSideState.append(WTFMove(payload));
}
-std::unique_ptr<CheckpointOSRExitSideState> VM::findCheckpointOSRSideState(CallFrame* callFrame)
+std::unique_ptr<CheckpointOSRExitSideState> VM::popCheckpointOSRSideState(CallFrame* expectedCallFrame)
{
ASSERT(currentThreadIsHoldingAPILock());
- auto sideState = m_checkpointSideState.take(callFrame);
+ auto sideState = m_checkpointSideState.takeLast();
+ RELEASE_ASSERT(sideState->associatedCallFrame == expectedCallFrame);
return sideState;
}
+void VM::popAllCheckpointOSRSideStateUntil(CallFrame* target)
+{
+ ASSERT(currentThreadIsHoldingAPILock());
+ auto bounds = StackBounds::currentThreadStackBounds().withSoftOrigin(target);
+ ASSERT(bounds.contains(target));
+
+ // We have to worry about migrating from another thread since there may be no checkpoints in our thread but one in the other threads.
+ while (m_checkpointSideState.size() && bounds.contains(m_checkpointSideState.last()->associatedCallFrame))
+ m_checkpointSideState.takeLast();
+}
+
void logSanitizeStack(VM& vm)
{
if (Options::verboseSanitizeStack() && vm.topCallFrame) {
Modified: trunk/Source/_javascript_Core/runtime/VM.h (265271 => 265272)
--- trunk/Source/_javascript_Core/runtime/VM.h 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/_javascript_Core/runtime/VM.h 2020-08-05 01:32:52 UTC (rev 265272)
@@ -944,8 +944,9 @@
void gatherScratchBufferRoots(ConservativeRoots&);
- void addCheckpointOSRSideState(CallFrame*, std::unique_ptr<CheckpointOSRExitSideState>&&);
- std::unique_ptr<CheckpointOSRExitSideState> findCheckpointOSRSideState(CallFrame*);
+ void pushCheckpointOSRSideState(std::unique_ptr<CheckpointOSRExitSideState>&&);
+ std::unique_ptr<CheckpointOSRExitSideState> popCheckpointOSRSideState(CallFrame* expectedFrame);
+ void popAllCheckpointOSRSideStateUntil(CallFrame* targetFrame);
bool hasCheckpointOSRSideState() const { return m_checkpointSideState.size(); }
void scanSideState(ConservativeRoots&) const;
@@ -1206,7 +1207,7 @@
Lock m_scratchBufferLock;
Vector<ScratchBuffer*> m_scratchBuffers;
size_t m_sizeOfLastScratchBuffer { 0 };
- HashMap<CallFrame*, std::unique_ptr<CheckpointOSRExitSideState>> m_checkpointSideState;
+ Vector<std::unique_ptr<CheckpointOSRExitSideState>, 4> m_checkpointSideState;
InlineWatchpointSet m_primitiveGigacageEnabled;
FunctionHasExecutedCache m_functionHasExecutedCache;
std::unique_ptr<ControlFlowProfiler> m_controlFlowProfiler;
Modified: trunk/Source/WTF/ChangeLog (265271 => 265272)
--- trunk/Source/WTF/ChangeLog 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/WTF/ChangeLog 2020-08-05 01:32:52 UTC (rev 265272)
@@ -1,3 +1,15 @@
+2020-08-04 Keith Miller <keith_mil...@apple.com>
+
+ CheckpointSideState shoud play nicely with StackOverflowException unwinding.
+ https://bugs.webkit.org/show_bug.cgi?id=215114
+
+ Reviewed by Saam Barati.
+
+ Add a helper so we can have soft stack bounds.
+
+ * wtf/StackBounds.h:
+ (WTF::StackBounds::withSoftOrigin const):
+
2020-08-04 Fujii Hironori <hironori.fu...@sony.com>
[MSVC] wtf/Optional.h: error C2280: 'WTF::constexpr_storage_t<T> &WTF::constexpr_storage_t<T>::operator =(const WTF::constexpr_storage_t<T> &)': attempting to reference a deleted function
Modified: trunk/Source/WTF/wtf/StackBounds.h (265271 => 265272)
--- trunk/Source/WTF/wtf/StackBounds.h 2020-08-05 01:27:12 UTC (rev 265271)
+++ trunk/Source/WTF/wtf/StackBounds.h 2020-08-05 01:32:52 UTC (rev 265272)
@@ -104,6 +104,12 @@
return startOfUserStack - maxUserStackWithReservedZone;
}
+ StackBounds withSoftOrigin(void* origin) const
+ {
+ ASSERT(contains(origin));
+ return StackBounds(origin, m_bound);
+ }
+
private:
StackBounds(void* origin, void* end)
: m_origin(origin)