]>
git.saurik.com Git - apple/javascriptcore.git/blob - interpreter/JSStackInlines.h
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef JSStackInlines_h
27 #define JSStackInlines_h
29 #include "CallFrame.h"
30 #include "CodeBlock.h"
35 inline Register
* JSStack::getTopOfFrame(CallFrame
* frame
)
39 return frame
->frameExtent();
42 inline Register
* JSStack::getTopOfStack()
44 return getTopOfFrame(m_topCallFrame
);
47 inline Register
* JSStack::getStartOfFrame(CallFrame
* frame
)
49 CallFrame
* callerFrame
= frame
->callerFrameNoFlags();
50 return getTopOfFrame(callerFrame
);
53 inline CallFrame
* JSStack::pushFrame(CallFrame
* callerFrame
,
54 class CodeBlock
* codeBlock
, JSScope
* scope
, int argsCount
, JSObject
* callee
)
57 Register
* oldEnd
= getTopOfStack();
59 // Ensure that we have enough space for the parameters:
60 size_t paddedArgsCount
= argsCount
;
62 size_t numParameters
= codeBlock
->numParameters();
63 if (paddedArgsCount
< numParameters
)
64 paddedArgsCount
= numParameters
;
67 Register
* newCallFrameSlot
= oldEnd
+ paddedArgsCount
+ JSStack::CallFrameHeaderSize
;
68 #if ENABLE(DEBUG_JSSTACK)
69 newCallFrameSlot
+= JSStack::FenceSize
;
71 Register
* newEnd
= newCallFrameSlot
;
73 newEnd
+= codeBlock
->m_numCalleeRegisters
;
75 // Ensure that we have the needed stack capacity to push the new frame:
79 // Compute the address of the new frame for this invocation:
80 CallFrame
* newCallFrame
= CallFrame::create(newCallFrameSlot
);
81 ASSERT(!!newCallFrame
);
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
;
88 // Initialize the frame header:
89 newCallFrame
->init(codeBlock
, 0, scope
,
90 callerFrame
->addHostCallFrameFlag(), argsCount
, callee
);
92 ASSERT(!!newCallFrame
->scope());
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());
100 installFence(newCallFrame
, __FUNCTION__
, __LINE__
);
101 validateFence(newCallFrame
, __FUNCTION__
, __LINE__
);
102 installTrapsAfterFrame(newCallFrame
);
104 // Push the new frame:
105 m_topCallFrame
= newCallFrame
;
110 inline void JSStack::popFrame(CallFrame
* frame
)
112 validateFence(frame
, __FUNCTION__
, __LINE__
);
113 CallFrame
* callerFrame
= frame
->callerFrameNoFlags();
115 // Pop to the caller:
116 m_topCallFrame
= callerFrame
;
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.
125 installTrapsAfterFrame(callerFrame
);
129 #if ENABLE(DEBUG_JSSTACK)
130 inline JSValue
JSStack::generateFenceValue(size_t argIndex
)
132 unsigned fenceBits
= 0xfacebad0 | ((argIndex
+1) & 0xf);
133 JSValue fenceValue
= JSValue(fenceBits
);
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:
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 |
159 // 3. In popFrame() and elsewhere, we can call JSStack::validateFence() to
160 // assert that the fence contains the values we expect.
162 inline void JSStack::installFence(CallFrame
* frame
, const char *function
, int lineNo
)
164 UNUSED_PARAM(function
);
165 UNUSED_PARAM(lineNo
);
166 Register
* startOfFrame
= getStartOfFrame(frame
);
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
);
177 inline void JSStack::validateFence(CallFrame
* frame
, const char *function
, int lineNo
)
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
);
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:
199 // |-----------------------------|
200 // | Frame Header of frame |
201 // |-----------------------------|
202 // topCallFrame --> | |
203 // | Locals of frame |
204 // |-----------------------------|
205 // | *** Trap words *** |
206 // |-----------------------------|
207 // | Unused space ... |
210 inline void JSStack::installTrapsAfterFrame(CallFrame
* frame
)
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
);
218 // Make sure we're not exceeding the amount of available memory to write to:
219 if (endOfTrap
> endOfCommitedMemory
)
220 endOfTrap
= endOfCommitedMemory
;
223 int32_t* p
= startOfTrap
;
224 while (p
< endOfTrap
)
225 *p
++ = 0xabadcafe; // A bad word to trigger a crash if deref'ed.
227 #endif // ENABLE(DEBUG_JSSTACK)
231 #endif // JSStackInlines_h