diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-05-24 08:28:08 +0000 |
commit | a4e969f4965059196ca948db781e52f7cfebf19e (patch) | |
tree | 6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/JavaScriptCore/interpreter/JSStackInlines.h | |
parent | 41386e9cb918eed93b3f13648cbef387e371e451 (diff) | |
download | WebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz |
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/JavaScriptCore/interpreter/JSStackInlines.h')
-rw-r--r-- | Source/JavaScriptCore/interpreter/JSStackInlines.h | 263 |
1 files changed, 31 insertions, 232 deletions
diff --git a/Source/JavaScriptCore/interpreter/JSStackInlines.h b/Source/JavaScriptCore/interpreter/JSStackInlines.h index 5a2aff117..69508ab5d 100644 --- a/Source/JavaScriptCore/interpreter/JSStackInlines.h +++ b/Source/JavaScriptCore/interpreter/JSStackInlines.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 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 @@ -33,262 +33,61 @@ namespace JSC { -inline Register* JSStack::getTopOfFrame(CallFrame* frame) +inline bool JSStack::ensureCapacityFor(Register* newTopOfStack) { - if (UNLIKELY(!frame)) - return getBaseOfStack(); - return frame->frameExtent(); -} - -inline Register* JSStack::getTopOfStack() -{ - return getTopOfFrame(m_topCallFrame); -} - -inline Register* JSStack::getStartOfFrame(CallFrame* frame) -{ - CallFrame* callerFrame = frame->callerFrameSkippingVMEntrySentinel(); - return getTopOfFrame(callerFrame); -} - -inline bool JSStack::entryCheck(class CodeBlock* codeBlock, int argsCount) -{ - 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 - (2 * JSStack::CallFrameHeaderSize) + 1; - -#if ENABLE(DEBUG_JSSTACK) - newCallFrameSlot -= JSStack::FenceSize; +#if !ENABLE(JIT) + return grow(newTopOfStack); +#else + ASSERT(wtfThreadData().stack().isGrowingDownward()); + return newTopOfStack >= m_vm.stackLimit(); #endif - - Register* newEnd = newCallFrameSlot; - if (!!codeBlock) - newEnd += virtualRegisterForLocal(codeBlock->frameRegisterCount()).offset(); - - // Ensure that we have the needed stack capacity to push the new frame: - if (!grow(newEnd)) - return false; - - return true; } -inline CallFrame* JSStack::pushFrame(class CodeBlock* codeBlock, JSScope* scope, int argsCount, JSObject* callee) -{ - 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 - (2 * JSStack::CallFrameHeaderSize) + 1; - -#if ENABLE(DEBUG_JSSTACK) - newCallFrameSlot -= JSStack::FenceSize; -#endif - - Register* newEnd = newCallFrameSlot; - if (!!codeBlock) - newEnd += virtualRegisterForLocal(codeBlock->frameRegisterCount()).offset(); - - // Ensure that we have the needed stack capacity to push the new frame: - if (!grow(newEnd)) - return 0; - - // Compute the address of the new VM sentinel frame for this invocation: - CallFrame* newVMEntrySentinelFrame = CallFrame::create(newCallFrameSlot + paddedArgsCount + JSStack::CallFrameHeaderSize); - ASSERT(!!newVMEntrySentinelFrame); - - // 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. - CallFrame* callerFrame = m_topCallFrame; - - // Initialize the VM sentinel frame header: - newVMEntrySentinelFrame->initializeVMEntrySentinelFrame(callerFrame); - - // Initialize the callee frame header: - newCallFrame->init(codeBlock, 0, scope, newVMEntrySentinelFrame, argsCount, callee); +#if !ENABLE(JIT) - 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; +inline Register* JSStack::topOfFrameFor(CallFrame* frame) +{ + if (UNLIKELY(!frame)) + return baseOfStack(); + return frame->topOfFrame() - 1; } -inline void JSStack::popFrame(CallFrame* frame) +inline Register* JSStack::topOfStack() { - validateFence(frame, __FUNCTION__, __LINE__); - - // Pop off the callee frame and the sentinel frame. - CallFrame* callerFrame = frame->callerFrame()->vmEntrySentinelCallerFrame(); - - // 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(getBaseOfStack()); - - installTrapsAfterFrame(callerFrame); + return topOfFrameFor(m_topCallFrame); } -inline void JSStack::shrink(Register* newEnd) +inline void JSStack::shrink(Register* newTopOfStack) { + Register* newEnd = newTopOfStack - 1; if (newEnd >= m_end) return; - updateStackLimit(newEnd); - if (m_end == getBaseOfStack() && (m_commitEnd - getBaseOfStack()) >= maxExcessCapacity) + 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(); } -inline bool JSStack::grow(Register* newEnd) +inline bool JSStack::grow(Register* newTopOfStack) { + Register* newEnd = newTopOfStack - 1; if (newEnd >= m_end) return true; - return growSlowCase(newEnd); + return growSlowCase(newTopOfStack); } -inline void JSStack::updateStackLimit(Register* newEnd) +inline void JSStack::setStackLimit(Register* newTopOfStack) { + Register* newEnd = newTopOfStack - 1; m_end = newEnd; -#if USE(SEPARATE_C_AND_JS_STACK) - m_vm.setJSStackLimit(newEnd); -#endif -} - -#if ENABLE(DEBUG_JSSTACK) -inline JSValue JSStack::generateFenceValue(size_t argIndex) -{ - unsigned fenceBits = 0xfacebad0 | ((argIndex+1) & 0xf); - JSValue fenceValue = JSValue(fenceBits); - return fenceValue; + m_vm.setJSStackLimit(newTopOfStack); } -// 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 *** | -// |--------------------------------------| -// | VM entry sentinel frame header | -// |--------------------------------------| -// | 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) -{ - 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); - } -} - -inline void JSStack::validateFence(CallFrame* frame, const char *function, int lineNo) -{ - 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); - } -} - -// 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 |