diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/interpreter/JSStackInlines.h | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-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.h | 213 |
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 |