1 : /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=79 ft=cpp:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey JavaScript engine.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Mozilla Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 2009
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Luke Wagner <luke@mozilla.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either the GNU General Public License Version 2 or later (the "GPL"), or
29 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #ifndef Stack_inl_h__
42 : #define Stack_inl_h__
43 :
44 : #include "jscntxt.h"
45 : #include "jscompartment.h"
46 :
47 : #include "methodjit/MethodJIT.h"
48 : #include "vm/Stack.h"
49 :
50 : #include "jsscriptinlines.h"
51 :
52 : #include "ArgumentsObject-inl.h"
53 : #include "ScopeObject-inl.h"
54 :
55 :
56 : namespace js {
57 :
58 : /*
59 : * We cache name lookup results only for the global object or for native
60 : * non-global objects without prototype or with prototype that never mutates,
61 : * see bug 462734 and bug 487039.
62 : */
63 : static inline bool
64 2593864 : IsCacheableNonGlobalScope(JSObject *obj)
65 : {
66 2593864 : bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
67 :
68 2593864 : JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
69 2593864 : return cacheable;
70 : }
71 :
72 : inline JSObject &
73 980751690 : StackFrame::scopeChain() const
74 : {
75 980751690 : JS_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
76 980751690 : if (!(flags_ & HAS_SCOPECHAIN)) {
77 3843437 : scopeChain_ = callee().toFunction()->environment();
78 3843437 : flags_ |= HAS_SCOPECHAIN;
79 : }
80 980751690 : return *scopeChain_;
81 : }
82 :
83 : inline JSObject &
84 695943 : StackFrame::varObj()
85 : {
86 695943 : JSObject *obj = &scopeChain();
87 1392752 : while (!obj->isVarObj())
88 866 : obj = obj->enclosingScope();
89 695943 : return *obj;
90 : }
91 :
92 : inline JSCompartment *
93 4374165 : StackFrame::compartment() const
94 : {
95 4374165 : JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
96 4374165 : return scopeChain().compartment();
97 : }
98 :
99 : inline void
100 29415162 : StackFrame::initPrev(JSContext *cx)
101 : {
102 29415162 : JS_ASSERT(flags_ & HAS_PREVPC);
103 29415162 : if (FrameRegs *regs = cx->maybeRegs()) {
104 29143535 : prev_ = regs->fp();
105 29143535 : prevpc_ = regs->pc;
106 29143535 : prevInline_ = regs->inlined();
107 87361429 : JS_ASSERT_IF(!prev_->isDummyFrame(),
108 87361429 : uint32_t(prevpc_ - prev_->script()->code) < prev_->script()->length);
109 : } else {
110 271627 : prev_ = NULL;
111 : #ifdef DEBUG
112 271627 : prevpc_ = (jsbytecode *)0xbadc;
113 271627 : prevInline_ = (JSInlinedSite *)0xbadc;
114 : #endif
115 : }
116 29415162 : }
117 :
118 : inline void
119 52321 : StackFrame::resetGeneratorPrev(JSContext *cx)
120 : {
121 52321 : flags_ |= HAS_PREVPC;
122 52321 : initPrev(cx);
123 52321 : }
124 :
125 : inline void
126 131 : StackFrame::initInlineFrame(JSFunction *fun, StackFrame *prevfp, jsbytecode *prevpc)
127 : {
128 : /*
129 : * Note: no need to ensure the scopeChain is instantiated for inline
130 : * frames. Functions which use the scope chain are never inlined.
131 : */
132 131 : flags_ = StackFrame::FUNCTION;
133 131 : exec.fun = fun;
134 131 : resetInlinePrev(prevfp, prevpc);
135 131 : }
136 :
137 : inline void
138 186 : StackFrame::resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc)
139 : {
140 186 : JS_ASSERT_IF(flags_ & StackFrame::HAS_PREVPC, prevInline_);
141 186 : flags_ |= StackFrame::HAS_PREVPC;
142 186 : prev_ = prevfp;
143 186 : prevpc_ = prevpc;
144 186 : prevInline_ = NULL;
145 186 : }
146 :
147 : inline void
148 29081135 : StackFrame::initCallFrame(JSContext *cx, JSFunction &callee,
149 : JSScript *script, uint32_t nactual, StackFrame::Flags flagsArg)
150 : {
151 0 : JS_ASSERT((flagsArg & ~(CONSTRUCTING |
152 : LOWERED_CALL_APPLY |
153 : OVERFLOW_ARGS |
154 29081135 : UNDERFLOW_ARGS)) == 0);
155 29081135 : JS_ASSERT(script == callee.script());
156 :
157 : /* Initialize stack frame members. */
158 29081135 : flags_ = FUNCTION | HAS_PREVPC | HAS_SCOPECHAIN | HAS_BLOCKCHAIN | flagsArg;
159 29081135 : exec.fun = &callee;
160 29081135 : u.nactual = nactual;
161 29081135 : scopeChain_ = callee.environment();
162 29081135 : ncode_ = NULL;
163 29081135 : initPrev(cx);
164 29081135 : blockChain_= NULL;
165 29081135 : JS_ASSERT(!hasBlockChain());
166 29081135 : JS_ASSERT(!hasHookData());
167 29081135 : JS_ASSERT(annotation() == NULL);
168 29081135 : JS_ASSERT(!hasCallObj());
169 :
170 29081135 : SetValueRangeToUndefined(slots(), script->nfixed);
171 29081135 : }
172 :
173 : /*
174 : * Reinitialize the StackFrame fields that have been initialized up to the
175 : * point of FixupArity in the function prologue.
176 : */
177 : inline void
178 1022112 : StackFrame::initFixupFrame(StackFrame *prev, StackFrame::Flags flags, void *ncode, unsigned nactual)
179 : {
180 0 : JS_ASSERT((flags & ~(CONSTRUCTING |
181 : LOWERED_CALL_APPLY |
182 : FUNCTION |
183 : OVERFLOW_ARGS |
184 1022112 : UNDERFLOW_ARGS)) == 0);
185 :
186 1022112 : flags_ = FUNCTION | flags;
187 1022112 : prev_ = prev;
188 1022112 : ncode_ = ncode;
189 1022112 : u.nactual = nactual;
190 1022112 : }
191 :
192 : inline void
193 5 : StackFrame::overwriteCallee(JSObject &newCallee)
194 : {
195 5 : JS_ASSERT(callee().toFunction()->script() == newCallee.toFunction()->script());
196 5 : mutableCalleev().setObject(newCallee);
197 5 : }
198 :
199 : inline Value &
200 76804 : StackFrame::canonicalActualArg(unsigned i) const
201 : {
202 76804 : if (i < numFormalArgs())
203 12466 : return formalArg(i);
204 64338 : JS_ASSERT(i < numActualArgs());
205 64338 : return actualArgs()[i];
206 : }
207 :
208 : template <class Op>
209 : inline bool
210 5264260 : StackFrame::forEachCanonicalActualArg(Op op, unsigned start /* = 0 */, unsigned count /* = unsigned(-1) */)
211 : {
212 5624246 : unsigned nformal = fun()->nargs;
213 5624246 : JS_ASSERT(start <= nformal);
214 :
215 5624246 : Value *formals = formalArgsEnd() - nformal;
216 5624246 : unsigned nactual = numActualArgs();
217 5624246 : if (count == unsigned(-1))
218 5264260 : count = nactual - start;
219 :
220 5624246 : unsigned end = start + count;
221 5624246 : JS_ASSERT(end >= start);
222 5624246 : JS_ASSERT(end <= nactual);
223 :
224 5624246 : if (end <= nformal) {
225 3490705 : Value *p = formals + start;
226 4485986 : for (; start < end; ++p, ++start) {
227 995281 : if (!op(start, p))
228 0 : return false;
229 : }
230 : } else {
231 2481374 : for (Value *p = formals + start; start < nformal; ++p, ++start) {
232 347833 : if (!op(start, p))
233 0 : return false;
234 : }
235 2133541 : JS_ASSERT(start >= nformal);
236 2133541 : Value *actuals = formals - (nactual + 2) + start;
237 9852630 : for (Value *p = actuals; start < end; ++p, ++start) {
238 7719107 : if (!op(start, p))
239 18 : return false;
240 : }
241 : }
242 5624228 : return true;
243 : }
244 :
245 : template <class Op>
246 : inline bool
247 : StackFrame::forEachFormalArg(Op op)
248 : {
249 : Value *formals = formalArgsEnd() - fun()->nargs;
250 : Value *formalsEnd = formalArgsEnd();
251 : unsigned i = 0;
252 : for (Value *p = formals; p != formalsEnd; ++p, ++i) {
253 : if (!op(i, p))
254 : return false;
255 : }
256 : return true;
257 : }
258 :
259 : struct CopyTo
260 : {
261 : Value *dst;
262 282240 : CopyTo(Value *dst) : dst(dst) {}
263 689882 : bool operator()(unsigned, Value *src) {
264 689882 : *dst++ = *src;
265 689882 : return true;
266 : }
267 : };
268 :
269 : inline unsigned
270 15275513 : StackFrame::numActualArgs() const
271 : {
272 : /*
273 : * u.nactual is always coherent, except for method JIT frames where the
274 : * callee does not access its arguments and the number of actual arguments
275 : * matches the number of formal arguments. The JIT requires that all frames
276 : * which do not have an arguments object and use their arguments have a
277 : * coherent u.nactual (even though the below code may not use it), as
278 : * JIT code may access the field directly.
279 : */
280 15275513 : JS_ASSERT(hasArgs());
281 15275513 : if (JS_UNLIKELY(flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS)))
282 4959086 : return u.nactual;
283 10316427 : return numFormalArgs();
284 : }
285 :
286 : inline Value *
287 14303137 : StackFrame::actualArgs() const
288 : {
289 14303137 : JS_ASSERT(hasArgs());
290 14303137 : Value *argv = formalArgs();
291 14303137 : if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
292 1417579 : return argv - (2 + u.nactual);
293 12885558 : return argv;
294 : }
295 :
296 : inline Value *
297 4363539 : StackFrame::actualArgsEnd() const
298 : {
299 4363539 : JS_ASSERT(hasArgs());
300 4363539 : if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
301 1083243 : return formalArgs() - 2;
302 3280296 : return formalArgs() + numActualArgs();
303 : }
304 :
305 : inline void
306 620181 : StackFrame::setArgsObj(ArgumentsObject &obj)
307 : {
308 620181 : JS_ASSERT_IF(hasArgsObj(), &obj == argsObj_);
309 620181 : JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.initialLength());
310 620181 : argsObj_ = &obj;
311 620181 : flags_ |= HAS_ARGS_OBJ;
312 620181 : }
313 :
314 : inline void
315 321649 : StackFrame::setScopeChainNoCallObj(JSObject &obj)
316 : {
317 : #ifdef DEBUG
318 321649 : JS_ASSERT(&obj != NULL);
319 321649 : if (&obj != sInvalidScopeChain) {
320 321649 : if (hasCallObj()) {
321 36585 : JSObject *pobj = &obj;
322 74209 : while (pobj && pobj->getPrivate() != this)
323 1039 : pobj = pobj->enclosingScope();
324 36585 : JS_ASSERT(pobj);
325 : } else {
326 287049 : for (JSObject *pobj = &obj; pobj->isScope(); pobj = pobj->enclosingScope())
327 1985 : JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
328 : }
329 : }
330 : #endif
331 321649 : scopeChain_ = &obj;
332 321649 : flags_ |= HAS_SCOPECHAIN;
333 321649 : }
334 :
335 : inline void
336 703243 : StackFrame::setScopeChainWithOwnCallObj(CallObject &obj)
337 : {
338 703243 : JS_ASSERT(&obj != NULL);
339 703243 : JS_ASSERT(!hasCallObj() && obj.maybeStackFrame() == this);
340 703243 : scopeChain_ = &obj;
341 703243 : flags_ |= HAS_SCOPECHAIN | HAS_CALL_OBJ;
342 703243 : }
343 :
344 : inline CallObject &
345 951371 : StackFrame::callObj() const
346 : {
347 951371 : JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj());
348 :
349 951371 : JSObject *pobj = &scopeChain();
350 1904951 : while (JS_UNLIKELY(!pobj->isCall()))
351 2209 : pobj = pobj->enclosingScope();
352 951371 : return pobj->asCall();
353 : }
354 :
355 : inline bool
356 24505660 : StackFrame::maintainNestingState() const
357 : {
358 : /*
359 : * Whether to invoke the nesting epilogue/prologue to maintain active
360 : * frame counts and check for reentrant outer functions.
361 : */
362 24505660 : return isNonEvalFunctionFrame() && !isGeneratorFrame() && script()->nesting();
363 : }
364 :
365 : inline bool
366 29269891 : StackFrame::functionPrologue(JSContext *cx)
367 : {
368 29269891 : JS_ASSERT(isNonEvalFunctionFrame());
369 :
370 29269891 : JSFunction *fun = this->fun();
371 :
372 29269891 : if (fun->isHeavyweight()) {
373 700076 : if (!CallObject::createForFunction(cx, this))
374 0 : return false;
375 : } else {
376 : /* Force instantiation of the scope chain, for JIT frames. */
377 28569815 : scopeChain();
378 : }
379 :
380 29269891 : if (script()->nesting()) {
381 415882 : JS_ASSERT(maintainNestingState());
382 415882 : types::NestingPrologue(cx, this);
383 : }
384 :
385 29269891 : return true;
386 : }
387 :
388 : inline void
389 19845366 : StackFrame::functionEpilogue()
390 : {
391 19845366 : JS_ASSERT(isNonEvalFunctionFrame());
392 :
393 19845366 : if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
394 : /* NB: there is an ordering dependency here. */
395 1311256 : if (hasCallObj())
396 700831 : js_PutCallObject(this);
397 610425 : else if (hasArgsObj())
398 610425 : js_PutArgsObject(this);
399 : }
400 :
401 19845366 : if (maintainNestingState())
402 320332 : types::NestingEpilogue(this);
403 19845366 : }
404 :
405 : inline void
406 4244412 : StackFrame::updateEpilogueFlags()
407 : {
408 4244412 : if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
409 31320 : if (hasArgsObj() && !argsObj().maybeStackFrame())
410 15644 : flags_ &= ~HAS_ARGS_OBJ;
411 31320 : if (hasCallObj() && !callObj().maybeStackFrame()) {
412 : /*
413 : * For function frames, the call object may or may not have have an
414 : * enclosing DeclEnv object, so we use the callee's parent, since
415 : * it was the initial scope chain. For global (strict) eval frames,
416 : * there is no callee, but the call object's parent is the initial
417 : * scope chain.
418 : */
419 12966 : scopeChain_ = isFunctionFrame()
420 12966 : ? callee().toFunction()->environment()
421 25932 : : &scopeChain_->asScope().enclosingScope();
422 12966 : flags_ &= ~HAS_CALL_OBJ;
423 : }
424 : }
425 :
426 : /*
427 : * For outer/inner function frames, undo the active frame balancing so that
428 : * when we redo it in the epilogue we get the right final value. The other
429 : * nesting epilogue changes (update active args/vars) are idempotent.
430 : */
431 4244412 : if (maintainNestingState())
432 15528 : script()->nesting()->activeFrames++;
433 4244412 : }
434 :
435 : /*****************************************************************************/
436 :
437 : STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
438 : JS_ALWAYS_INLINE bool
439 41462684 : StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals,
440 : JSCompartment *dest) const
441 : {
442 41462684 : assertInvariants();
443 41462684 : JS_ASSERT(from >= firstUnused());
444 : #ifdef XP_WIN
445 : JS_ASSERT(from <= commitEnd_);
446 : #endif
447 41462684 : if (JS_UNLIKELY(conservativeEnd_ - from < nvals))
448 231 : return ensureSpaceSlow(cx, report, from, nvals, dest);
449 41462453 : return true;
450 : }
451 :
452 : inline Value *
453 4318394 : StackSpace::getStackLimit(JSContext *cx, MaybeReportError report)
454 : {
455 4318394 : FrameRegs ®s = cx->regs();
456 4318394 : unsigned nvals = regs.fp()->numSlots() + STACK_JIT_EXTRA;
457 4318394 : return ensureSpace(cx, report, regs.sp, nvals)
458 : ? conservativeEnd_
459 4318394 : : NULL;
460 : }
461 :
462 : /*****************************************************************************/
463 :
464 : JS_ALWAYS_INLINE StackFrame *
465 30103360 : ContextStack::getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
466 : JSFunction *fun, JSScript *script, StackFrame::Flags *flags) const
467 : {
468 30103360 : JS_ASSERT(fun->script() == script);
469 30103360 : unsigned nformal = fun->nargs;
470 :
471 30103360 : Value *firstUnused = args.end();
472 30103360 : JS_ASSERT(firstUnused == space().firstUnused());
473 :
474 : /* Include extra space to satisfy the method-jit stackLimit invariant. */
475 30103360 : unsigned nvals = VALUES_PER_STACK_FRAME + script->nslots + StackSpace::STACK_JIT_EXTRA;
476 :
477 : /* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */
478 :
479 30103360 : if (args.length() == nformal) {
480 24773098 : if (!space().ensureSpace(cx, report, firstUnused, nvals))
481 71 : return NULL;
482 24773027 : return reinterpret_cast<StackFrame *>(firstUnused);
483 : }
484 :
485 5330262 : if (args.length() < nformal) {
486 445425 : *flags = StackFrame::Flags(*flags | StackFrame::UNDERFLOW_ARGS);
487 445425 : unsigned nmissing = nformal - args.length();
488 445425 : if (!space().ensureSpace(cx, report, firstUnused, nmissing + nvals))
489 1 : return NULL;
490 445424 : SetValueRangeToUndefined(firstUnused, nmissing);
491 445424 : return reinterpret_cast<StackFrame *>(firstUnused + nmissing);
492 : }
493 :
494 4884837 : *flags = StackFrame::Flags(*flags | StackFrame::OVERFLOW_ARGS);
495 4884837 : unsigned ncopy = 2 + nformal;
496 4884837 : if (!space().ensureSpace(cx, report, firstUnused, ncopy + nvals))
497 41 : return NULL;
498 4884796 : Value *dst = firstUnused;
499 4884796 : Value *src = args.base();
500 4884796 : PodCopy(dst, src, ncopy);
501 4884796 : return reinterpret_cast<StackFrame *>(firstUnused + ncopy);
502 : }
503 :
504 : JS_ALWAYS_INLINE bool
505 23863477 : ContextStack::pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
506 : JSFunction &callee, JSScript *script,
507 : InitialFrameFlags initial)
508 : {
509 23863477 : JS_ASSERT(onTop());
510 23863477 : JS_ASSERT(regs.sp == args.end());
511 : /* Cannot assert callee == args.callee() since this is called from LeaveTree. */
512 23863477 : JS_ASSERT(script == callee.script());
513 :
514 23863477 : StackFrame::Flags flags = ToFrameFlags(initial);
515 23863477 : StackFrame *fp = getCallFrame(cx, REPORT_ERROR, args, &callee, script, &flags);
516 23863477 : if (!fp)
517 73 : return false;
518 :
519 : /* Initialize frame, locals, regs. */
520 23863404 : fp->initCallFrame(cx, callee, script, args.length(), flags);
521 :
522 : /*
523 : * N.B. regs may differ from the active registers, if the parent is about
524 : * to repoint the active registers to regs. See UncachedInlineCall.
525 : */
526 23863404 : regs.prepareToRun(*fp, script);
527 23863404 : return true;
528 : }
529 :
530 : JS_ALWAYS_INLINE bool
531 11970199 : ContextStack::pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
532 : JSFunction &callee, JSScript *script,
533 : InitialFrameFlags initial, Value **stackLimit)
534 : {
535 11970199 : if (!pushInlineFrame(cx, regs, args, callee, script, initial))
536 21 : return false;
537 11970178 : *stackLimit = space().conservativeEnd_;
538 11970178 : return true;
539 : }
540 :
541 : JS_ALWAYS_INLINE StackFrame *
542 1022124 : ContextStack::getFixupFrame(JSContext *cx, MaybeReportError report,
543 : const CallArgs &args, JSFunction *fun, JSScript *script,
544 : void *ncode, InitialFrameFlags initial, Value **stackLimit)
545 : {
546 1022124 : JS_ASSERT(onTop());
547 1022124 : JS_ASSERT(fun->script() == args.callee().toFunction()->script());
548 1022124 : JS_ASSERT(fun->script() == script);
549 :
550 1022124 : StackFrame::Flags flags = ToFrameFlags(initial);
551 1022124 : StackFrame *fp = getCallFrame(cx, report, args, fun, script, &flags);
552 1022124 : if (!fp)
553 12 : return NULL;
554 :
555 : /* Do not init late prologue or regs; this is done by jit code. */
556 1022112 : fp->initFixupFrame(cx->fp(), flags, ncode, args.length());
557 :
558 1022112 : *stackLimit = space().conservativeEnd_;
559 1022112 : return fp;
560 : }
561 :
562 : JS_ALWAYS_INLINE void
563 14039849 : ContextStack::popInlineFrame(FrameRegs ®s)
564 : {
565 14039849 : JS_ASSERT(onTop());
566 14039849 : JS_ASSERT(®s == &seg_->regs());
567 :
568 14039849 : StackFrame *fp = regs.fp();
569 14039849 : fp->functionEpilogue();
570 :
571 14039849 : Value *newsp = fp->actualArgs() - 1;
572 14039849 : JS_ASSERT(newsp >= fp->prev()->base());
573 :
574 14039849 : newsp[-1] = fp->returnValue();
575 14039849 : regs.popFrame(newsp);
576 14039849 : }
577 :
578 : inline void
579 16 : ContextStack::popFrameAfterOverflow()
580 : {
581 : /* Restore the regs to what they were on entry to JSOP_CALL. */
582 16 : FrameRegs ®s = seg_->regs();
583 16 : StackFrame *fp = regs.fp();
584 16 : regs.popFrame(fp->actualArgsEnd());
585 16 : }
586 :
587 : inline JSScript *
588 80389535 : ContextStack::currentScript(jsbytecode **ppc) const
589 : {
590 80389535 : if (ppc)
591 27268929 : *ppc = NULL;
592 :
593 80389535 : FrameRegs *regs = maybeRegs();
594 80389535 : StackFrame *fp = regs ? regs->fp() : NULL;
595 160787945 : while (fp && fp->isDummyFrame())
596 8875 : fp = fp->prev();
597 80389535 : if (!fp)
598 2007 : return NULL;
599 :
600 : #ifdef JS_METHODJIT
601 80387528 : mjit::CallSite *inlined = regs->inlined();
602 80387528 : if (inlined) {
603 430 : mjit::JITChunk *chunk = fp->jit()->chunk(regs->pc);
604 430 : JS_ASSERT(inlined->inlineIndex < chunk->nInlineFrames);
605 430 : mjit::InlineFrame *frame = &chunk->inlineFrames()[inlined->inlineIndex];
606 430 : JSScript *script = frame->fun->script();
607 430 : if (script->compartment() != cx_->compartment)
608 0 : return NULL;
609 430 : if (ppc)
610 186 : *ppc = script->code + inlined->pcOffset;
611 430 : return script;
612 : }
613 : #endif
614 :
615 80387098 : JSScript *script = fp->script();
616 80387098 : if (script->compartment() != cx_->compartment)
617 8875 : return NULL;
618 :
619 80378223 : if (ppc)
620 27257870 : *ppc = fp->pcQuadratic(*this);
621 80378223 : return script;
622 : }
623 :
624 : inline JSObject *
625 55618458 : ContextStack::currentScriptedScopeChain() const
626 : {
627 55618458 : return &fp()->scopeChain();
628 : }
629 :
630 : } /* namespace js */
631 : #endif /* Stack_inl_h__ */
|