summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter/JSStackInlines.h
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-08-25 19:20:41 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:30:55 +0000
commit6882a04fb36642862b11efe514251d32070c3d65 (patch)
treeb7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/interpreter/JSStackInlines.h
parentab6df191029eeeb0b0f16f127d553265659f739e (diff)
downloadqtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/JavaScriptCore/interpreter/JSStackInlines.h')
-rw-r--r--Source/JavaScriptCore/interpreter/JSStackInlines.h213
1 files changed, 38 insertions, 175 deletions
diff --git a/Source/JavaScriptCore/interpreter/JSStackInlines.h b/Source/JavaScriptCore/interpreter/JSStackInlines.h
index d316b5992..69508ab5d 100644
--- a/Source/JavaScriptCore/interpreter/JSStackInlines.h
+++ b/Source/JavaScriptCore/interpreter/JSStackInlines.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,202 +29,65 @@
#include "CallFrame.h"
#include "CodeBlock.h"
#include "JSStack.h"
+#include "VM.h"
namespace JSC {
-inline Register* JSStack::getTopOfFrame(CallFrame* frame)
+inline bool JSStack::ensureCapacityFor(Register* newTopOfStack)
{
- if (UNLIKELY(!frame))
- return begin();
- return frame->frameExtent();
-}
-
-inline Register* JSStack::getTopOfStack()
-{
- return getTopOfFrame(m_topCallFrame);
+#if !ENABLE(JIT)
+ return grow(newTopOfStack);
+#else
+ ASSERT(wtfThreadData().stack().isGrowingDownward());
+ return newTopOfStack >= m_vm.stackLimit();
+#endif
}
-inline Register* JSStack::getStartOfFrame(CallFrame* frame)
-{
- CallFrame* callerFrame = frame->callerFrameNoFlags();
- return getTopOfFrame(callerFrame);
-}
+#if !ENABLE(JIT)
-inline CallFrame* JSStack::pushFrame(CallFrame* callerFrame,
- class CodeBlock* codeBlock, JSScope* scope, int argsCount, JSObject* callee)
+inline Register* JSStack::topOfFrameFor(CallFrame* frame)
{
- ASSERT(!!scope);
- Register* oldEnd = getTopOfStack();
-
- // Ensure that we have enough space for the parameters:
- size_t paddedArgsCount = argsCount;
- if (codeBlock) {
- size_t numParameters = codeBlock->numParameters();
- if (paddedArgsCount < numParameters)
- paddedArgsCount = numParameters;
- }
-
- Register* newCallFrameSlot = oldEnd + paddedArgsCount + JSStack::CallFrameHeaderSize;
-#if ENABLE(DEBUG_JSSTACK)
- newCallFrameSlot += JSStack::FenceSize;
-#endif
- Register* newEnd = newCallFrameSlot;
- if (!!codeBlock)
- newEnd += codeBlock->m_numCalleeRegisters;
-
- // Ensure that we have the needed stack capacity to push the new frame:
- if (!grow(newEnd))
- return 0;
-
- // Compute the address of the new frame for this invocation:
- CallFrame* newCallFrame = CallFrame::create(newCallFrameSlot);
- ASSERT(!!newCallFrame);
-
- // The caller frame should always be the real previous frame on the stack,
- // and not a potential GlobalExec that was passed in. Point callerFrame to
- // the top frame on the stack.
- callerFrame = m_topCallFrame;
-
- // Initialize the frame header:
- newCallFrame->init(codeBlock, 0, scope,
- callerFrame->addHostCallFrameFlag(), argsCount, callee);
-
- ASSERT(!!newCallFrame->scope());
-
- // Pad additional args if needed:
- // Note: we need to subtract 1 from argsCount and paddedArgsCount to
- // exclude the this pointer.
- for (size_t i = argsCount-1; i < paddedArgsCount-1; ++i)
- newCallFrame->setArgument(i, jsUndefined());
-
- installFence(newCallFrame, __FUNCTION__, __LINE__);
- validateFence(newCallFrame, __FUNCTION__, __LINE__);
- installTrapsAfterFrame(newCallFrame);
-
- // Push the new frame:
- m_topCallFrame = newCallFrame;
-
- return newCallFrame;
+ if (UNLIKELY(!frame))
+ return baseOfStack();
+ return frame->topOfFrame() - 1;
}
-inline void JSStack::popFrame(CallFrame* frame)
+inline Register* JSStack::topOfStack()
{
- validateFence(frame, __FUNCTION__, __LINE__);
- CallFrame* callerFrame = frame->callerFrameNoFlags();
-
- // Pop to the caller:
- m_topCallFrame = callerFrame;
-
- // If we are popping the very first frame from the stack i.e. no more
- // frames before this, then we can now safely shrink the stack. In
- // this case, we're shrinking all the way to the beginning since there
- // are no more frames on the stack.
- if (!callerFrame)
- shrink(begin());
-
- installTrapsAfterFrame(callerFrame);
+ return topOfFrameFor(m_topCallFrame);
}
-
-#if ENABLE(DEBUG_JSSTACK)
-inline JSValue JSStack::generateFenceValue(size_t argIndex)
+inline void JSStack::shrink(Register* newTopOfStack)
{
- unsigned fenceBits = 0xfacebad0 | ((argIndex+1) & 0xf);
- JSValue fenceValue = JSValue(fenceBits);
- return fenceValue;
+ Register* newEnd = newTopOfStack - 1;
+ if (newEnd >= m_end)
+ return;
+ setStackLimit(newTopOfStack);
+ // Note: Clang complains of an unresolved linkage to maxExcessCapacity if
+ // invoke std::max() with it as an argument. To work around this, we first
+ // assign the constant to a local variable, and use the local instead.
+ ptrdiff_t maxExcessCapacity = JSStack::maxExcessCapacity;
+ ptrdiff_t maxExcessInRegisters = std::max(maxExcessCapacity, m_reservedZoneSizeInRegisters);
+ if (m_end == baseOfStack() && (highAddress() - m_commitTop) >= maxExcessInRegisters)
+ releaseExcessCapacity();
}
-// The JSStack fences mechanism works as follows:
-// 1. A fence is a number (JSStack::FenceSize) of JSValues that are initialized
-// with values generated by JSStack::generateFenceValue().
-// 2. When pushFrame() is called, the fence is installed after the max extent
-// of the previous topCallFrame and the last arg of the new frame:
-//
-// | ... |
-// |--------------------------------------|
-// | Frame Header of previous frame |
-// |--------------------------------------|
-// topCallFrame --> | |
-// | Locals of previous frame |
-// |--------------------------------------|
-// | *** the Fence *** |
-// |--------------------------------------|
-// | Args of new frame |
-// |--------------------------------------|
-// | Frame Header of new frame |
-// |--------------------------------------|
-// frame --> | Locals of new frame |
-// | |
-//
-// 3. In popFrame() and elsewhere, we can call JSStack::validateFence() to
-// assert that the fence contains the values we expect.
-
-inline void JSStack::installFence(CallFrame* frame, const char *function, int lineNo)
+inline bool JSStack::grow(Register* newTopOfStack)
{
- UNUSED_PARAM(function);
- UNUSED_PARAM(lineNo);
- Register* startOfFrame = getStartOfFrame(frame);
-
- // The last argIndex is at:
- size_t maxIndex = frame->argIndexForRegister(startOfFrame) + 1;
- size_t startIndex = maxIndex - FenceSize;
- for (size_t i = startIndex; i < maxIndex; ++i) {
- JSValue fenceValue = generateFenceValue(i);
- frame->setArgument(i, fenceValue);
- }
+ Register* newEnd = newTopOfStack - 1;
+ if (newEnd >= m_end)
+ return true;
+ return growSlowCase(newTopOfStack);
}
-inline void JSStack::validateFence(CallFrame* frame, const char *function, int lineNo)
+inline void JSStack::setStackLimit(Register* newTopOfStack)
{
- UNUSED_PARAM(function);
- UNUSED_PARAM(lineNo);
- ASSERT(!!frame->scope());
- Register* startOfFrame = getStartOfFrame(frame);
- size_t maxIndex = frame->argIndexForRegister(startOfFrame) + 1;
- size_t startIndex = maxIndex - FenceSize;
- for (size_t i = startIndex; i < maxIndex; ++i) {
- JSValue fenceValue = generateFenceValue(i);
- JSValue actualValue = frame->getArgumentUnsafe(i);
- ASSERT(fenceValue == actualValue);
- }
+ Register* newEnd = newTopOfStack - 1;
+ m_end = newEnd;
+ m_vm.setJSStackLimit(newTopOfStack);
}
-// When debugging the JSStack, we install bad values after the extent of the
-// topCallFrame at the end of pushFrame() and popFrame(). The intention is
-// to trigger crashes in the event that memory in this supposedly unused
-// region is read and consumed without proper initialization. After the trap
-// words are installed, the stack looks like this:
-//
-// | ... |
-// |-----------------------------|
-// | Frame Header of frame |
-// |-----------------------------|
-// topCallFrame --> | |
-// | Locals of frame |
-// |-----------------------------|
-// | *** Trap words *** |
-// |-----------------------------|
-// | Unused space ... |
-// | ... |
-
-inline void JSStack::installTrapsAfterFrame(CallFrame* frame)
-{
- Register* topOfFrame = getTopOfFrame(frame);
- const int sizeOfTrap = 64;
- int32_t* startOfTrap = reinterpret_cast<int32_t*>(topOfFrame);
- int32_t* endOfTrap = startOfTrap + sizeOfTrap;
- int32_t* endOfCommitedMemory = reinterpret_cast<int32_t*>(m_commitEnd);
-
- // Make sure we're not exceeding the amount of available memory to write to:
- if (endOfTrap > endOfCommitedMemory)
- endOfTrap = endOfCommitedMemory;
-
- // Lay the traps:
- int32_t* p = startOfTrap;
- while (p < endOfTrap)
- *p++ = 0xabadcafe; // A bad word to trigger a crash if deref'ed.
-}
-#endif // ENABLE(DEBUG_JSSTACK)
+#endif // !ENABLE(JIT)
} // namespace JSC