]> git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/JSStackInlines.h
JavaScriptCore-1218.0.1.tar.gz
[apple/javascriptcore.git] / interpreter / JSStackInlines.h
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
33 namespace JSC {
34
35 inline Register* JSStack::getTopOfFrame(CallFrame* frame)
36 {
37 if (UNLIKELY(!frame))
38 return begin();
39 return frame->frameExtent();
40 }
41
42 inline Register* JSStack::getTopOfStack()
43 {
44 return getTopOfFrame(m_topCallFrame);
45 }
46
47 inline Register* JSStack::getStartOfFrame(CallFrame* frame)
48 {
49 CallFrame* callerFrame = frame->callerFrameNoFlags();
50 return getTopOfFrame(callerFrame);
51 }
52
53 inline 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
110 inline 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)
130 inline 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
162 inline 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
177 inline 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
210 inline 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