]> git.saurik.com Git - apple/javascriptcore.git/blame - interpreter/JSStackInlines.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / interpreter / JSStackInlines.h
CommitLineData
93a37866
A
1/*
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef JSStackInlines_h
27#define JSStackInlines_h
28
29#include "CallFrame.h"
30#include "CodeBlock.h"
31#include "JSStack.h"
32
33namespace JSC {
34
35inline Register* JSStack::getTopOfFrame(CallFrame* frame)
36{
37 if (UNLIKELY(!frame))
38 return begin();
39 return frame->frameExtent();
40}
41
42inline Register* JSStack::getTopOfStack()
43{
44 return getTopOfFrame(m_topCallFrame);
45}
46
47inline Register* JSStack::getStartOfFrame(CallFrame* frame)
48{
49 CallFrame* callerFrame = frame->callerFrameNoFlags();
50 return getTopOfFrame(callerFrame);
51}
52
53inline CallFrame* JSStack::pushFrame(CallFrame* callerFrame,
54 class CodeBlock* codeBlock, JSScope* scope, int argsCount, JSObject* callee)
55{
56 ASSERT(!!scope);
57 Register* oldEnd = getTopOfStack();
58
59 // Ensure that we have enough space for the parameters:
60 size_t paddedArgsCount = argsCount;
61 if (codeBlock) {
62 size_t numParameters = codeBlock->numParameters();
63 if (paddedArgsCount < numParameters)
64 paddedArgsCount = numParameters;
65 }
66
67 Register* newCallFrameSlot = oldEnd + paddedArgsCount + JSStack::CallFrameHeaderSize;
68#if ENABLE(DEBUG_JSSTACK)
69 newCallFrameSlot += JSStack::FenceSize;
70#endif
71 Register* newEnd = newCallFrameSlot;
72 if (!!codeBlock)
73 newEnd += codeBlock->m_numCalleeRegisters;
74
75 // Ensure that we have the needed stack capacity to push the new frame:
76 if (!grow(newEnd))
77 return 0;
78
79 // Compute the address of the new frame for this invocation:
80 CallFrame* newCallFrame = CallFrame::create(newCallFrameSlot);
81 ASSERT(!!newCallFrame);
82
83 // The caller frame should always be the real previous frame on the stack,
84 // and not a potential GlobalExec that was passed in. Point callerFrame to
85 // the top frame on the stack.
86 callerFrame = m_topCallFrame;
87
88 // Initialize the frame header:
89 newCallFrame->init(codeBlock, 0, scope,
90 callerFrame->addHostCallFrameFlag(), argsCount, callee);
91
92 ASSERT(!!newCallFrame->scope());
93
94 // Pad additional args if needed:
95 // Note: we need to subtract 1 from argsCount and paddedArgsCount to
96 // exclude the this pointer.
97 for (size_t i = argsCount-1; i < paddedArgsCount-1; ++i)
98 newCallFrame->setArgument(i, jsUndefined());
99
100 installFence(newCallFrame, __FUNCTION__, __LINE__);
101 validateFence(newCallFrame, __FUNCTION__, __LINE__);
102 installTrapsAfterFrame(newCallFrame);
103
104 // Push the new frame:
105 m_topCallFrame = newCallFrame;
106
107 return newCallFrame;
108}
109
110inline void JSStack::popFrame(CallFrame* frame)
111{
112 validateFence(frame, __FUNCTION__, __LINE__);
113 CallFrame* callerFrame = frame->callerFrameNoFlags();
114
115 // Pop to the caller:
116 m_topCallFrame = callerFrame;
117
118 // If we are popping the very first frame from the stack i.e. no more
119 // frames before this, then we can now safely shrink the stack. In
120 // this case, we're shrinking all the way to the beginning since there
121 // are no more frames on the stack.
122 if (!callerFrame)
123 shrink(begin());
124
125 installTrapsAfterFrame(callerFrame);
126}
127
128
129#if ENABLE(DEBUG_JSSTACK)
130inline JSValue JSStack::generateFenceValue(size_t argIndex)
131{
132 unsigned fenceBits = 0xfacebad0 | ((argIndex+1) & 0xf);
133 JSValue fenceValue = JSValue(fenceBits);
134 return fenceValue;
135}
136
137// The JSStack fences mechanism works as follows:
138// 1. A fence is a number (JSStack::FenceSize) of JSValues that are initialized
139// with values generated by JSStack::generateFenceValue().
140// 2. When pushFrame() is called, the fence is installed after the max extent
141// of the previous topCallFrame and the last arg of the new frame:
142//
143// | ... |
144// |--------------------------------------|
145// | Frame Header of previous frame |
146// |--------------------------------------|
147// topCallFrame --> | |
148// | Locals of previous frame |
149// |--------------------------------------|
150// | *** the Fence *** |
151// |--------------------------------------|
152// | Args of new frame |
153// |--------------------------------------|
154// | Frame Header of new frame |
155// |--------------------------------------|
156// frame --> | Locals of new frame |
157// | |
158//
159// 3. In popFrame() and elsewhere, we can call JSStack::validateFence() to
160// assert that the fence contains the values we expect.
161
162inline void JSStack::installFence(CallFrame* frame, const char *function, int lineNo)
163{
164 UNUSED_PARAM(function);
165 UNUSED_PARAM(lineNo);
166 Register* startOfFrame = getStartOfFrame(frame);
167
168 // The last argIndex is at:
169 size_t maxIndex = frame->argIndexForRegister(startOfFrame) + 1;
170 size_t startIndex = maxIndex - FenceSize;
171 for (size_t i = startIndex; i < maxIndex; ++i) {
172 JSValue fenceValue = generateFenceValue(i);
173 frame->setArgument(i, fenceValue);
174 }
175}
176
177inline void JSStack::validateFence(CallFrame* frame, const char *function, int lineNo)
178{
179 UNUSED_PARAM(function);
180 UNUSED_PARAM(lineNo);
181 ASSERT(!!frame->scope());
182 Register* startOfFrame = getStartOfFrame(frame);
183 size_t maxIndex = frame->argIndexForRegister(startOfFrame) + 1;
184 size_t startIndex = maxIndex - FenceSize;
185 for (size_t i = startIndex; i < maxIndex; ++i) {
186 JSValue fenceValue = generateFenceValue(i);
187 JSValue actualValue = frame->getArgumentUnsafe(i);
188 ASSERT(fenceValue == actualValue);
189 }
190}
191
192// When debugging the JSStack, we install bad values after the extent of the
193// topCallFrame at the end of pushFrame() and popFrame(). The intention is
194// to trigger crashes in the event that memory in this supposedly unused
195// region is read and consumed without proper initialization. After the trap
196// words are installed, the stack looks like this:
197//
198// | ... |
199// |-----------------------------|
200// | Frame Header of frame |
201// |-----------------------------|
202// topCallFrame --> | |
203// | Locals of frame |
204// |-----------------------------|
205// | *** Trap words *** |
206// |-----------------------------|
207// | Unused space ... |
208// | ... |
209
210inline void JSStack::installTrapsAfterFrame(CallFrame* frame)
211{
212 Register* topOfFrame = getTopOfFrame(frame);
213 const int sizeOfTrap = 64;
214 int32_t* startOfTrap = reinterpret_cast<int32_t*>(topOfFrame);
215 int32_t* endOfTrap = startOfTrap + sizeOfTrap;
216 int32_t* endOfCommitedMemory = reinterpret_cast<int32_t*>(m_commitEnd);
217
218 // Make sure we're not exceeding the amount of available memory to write to:
219 if (endOfTrap > endOfCommitedMemory)
220 endOfTrap = endOfCommitedMemory;
221
222 // Lay the traps:
223 int32_t* p = startOfTrap;
224 while (p < endOfTrap)
225 *p++ = 0xabadcafe; // A bad word to trigger a crash if deref'ed.
226}
227#endif // ENABLE(DEBUG_JSSTACK)
228
229} // namespace JSC
230
231#endif // JSStackInlines_h