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 2597599 : IsCacheableNonGlobalScope(JSObject *obj)
65 : {
66 2597599 : bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
67 :
68 2597599 : JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
69 2597599 : return cacheable;
70 : }
71 :
72 : inline JSObject &
73 1080834795 : StackFrame::scopeChain() const
74 : {
75 1080834795 : JS_ASSERT_IF(!(flags_ & HAS_SCOPECHAIN), isFunctionFrame());
76 1080834795 : if (!(flags_ & HAS_SCOPECHAIN)) {
77 3840676 : scopeChain_ = callee().toFunction()->environment();
78 3840676 : flags_ |= HAS_SCOPECHAIN;
79 : }
80 1080834795 : return *scopeChain_;
81 : }
82 :
83 : inline JSObject &
84 697741 : StackFrame::varObj()
85 : {
86 697741 : JSObject *obj = &scopeChain();
87 1396348 : while (!obj->isVarObj())
88 866 : obj = obj->enclosingScope();
89 697741 : return *obj;
90 : }
91 :
92 : inline JSCompartment *
93 4374042 : StackFrame::compartment() const
94 : {
95 4374042 : JS_ASSERT_IF(isScriptFrame(), scopeChain().compartment() == script()->compartment());
96 4374042 : return scopeChain().compartment();
97 : }
98 :
99 : inline void
100 29269195 : StackFrame::initPrev(JSContext *cx)
101 : {
102 29269195 : JS_ASSERT(flags_ & HAS_PREVPC);
103 29269195 : if (FrameRegs *regs = cx->maybeRegs()) {
104 29041382 : prev_ = regs->fp();
105 29041382 : prevpc_ = regs->pc;
106 29041382 : prevInline_ = regs->inlined();
107 87054930 : JS_ASSERT_IF(!prev_->isDummyFrame(),
108 87054930 : uint32_t(prevpc_ - prev_->script()->code) < prev_->script()->length);
109 : } else {
110 227813 : prev_ = NULL;
111 : #ifdef DEBUG
112 227813 : prevpc_ = (jsbytecode *)0xbadc;
113 227813 : prevInline_ = (JSInlinedSite *)0xbadc;
114 : #endif
115 : }
116 29269195 : }
117 :
118 : inline void
119 30834 : StackFrame::resetGeneratorPrev(JSContext *cx)
120 : {
121 30834 : flags_ |= HAS_PREVPC;
122 30834 : initPrev(cx);
123 30834 : }
124 :
125 : inline void
126 140 : 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 140 : flags_ = StackFrame::FUNCTION;
133 140 : exec.fun = fun;
134 140 : resetInlinePrev(prevfp, prevpc);
135 140 : }
136 :
137 : inline void
138 195 : StackFrame::resetInlinePrev(StackFrame *prevfp, jsbytecode *prevpc)
139 : {
140 195 : JS_ASSERT_IF(flags_ & StackFrame::HAS_PREVPC, prevInline_);
141 195 : flags_ |= StackFrame::HAS_PREVPC;
142 195 : prev_ = prevfp;
143 195 : prevpc_ = prevpc;
144 195 : prevInline_ = NULL;
145 195 : }
146 :
147 : inline void
148 28978615 : 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 28978615 : UNDERFLOW_ARGS)) == 0);
155 28978615 : JS_ASSERT(script == callee.script());
156 :
157 : /* Initialize stack frame members. */
158 28978615 : flags_ = FUNCTION | HAS_PREVPC | HAS_SCOPECHAIN | HAS_BLOCKCHAIN | flagsArg;
159 28978615 : exec.fun = &callee;
160 28978615 : u.nactual = nactual;
161 28978615 : scopeChain_ = callee.environment();
162 28978615 : ncode_ = NULL;
163 28978615 : initPrev(cx);
164 28978615 : blockChain_= NULL;
165 28978615 : JS_ASSERT(!hasBlockChain());
166 28978615 : JS_ASSERT(!hasHookData());
167 28978615 : JS_ASSERT(annotation() == NULL);
168 28978615 : JS_ASSERT(!hasCallObj());
169 :
170 28978615 : SetValueRangeToUndefined(slots(), script->nfixed);
171 28978615 : }
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 1022182 : 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 1022182 : UNDERFLOW_ARGS)) == 0);
185 :
186 1022182 : flags_ = FUNCTION | flags;
187 1022182 : prev_ = prev;
188 1022182 : ncode_ = ncode;
189 1022182 : u.nactual = nactual;
190 1022182 : }
191 :
192 : inline void
193 0 : StackFrame::overwriteCallee(JSObject &newCallee)
194 : {
195 0 : JS_ASSERT(callee().toFunction()->script() == newCallee.toFunction()->script());
196 0 : mutableCalleev().setObject(newCallee);
197 0 : }
198 :
199 : inline Value &
200 76805 : StackFrame::canonicalActualArg(unsigned i) const
201 : {
202 76805 : if (i < numFormalArgs())
203 12468 : return formalArg(i);
204 64337 : JS_ASSERT(i < numActualArgs());
205 64337 : return actualArgs()[i];
206 : }
207 :
208 : template <class Op>
209 : inline bool
210 5264114 : StackFrame::forEachCanonicalActualArg(Op op, unsigned start /* = 0 */, unsigned count /* = unsigned(-1) */)
211 : {
212 5624074 : unsigned nformal = fun()->nargs;
213 5624074 : JS_ASSERT(start <= nformal);
214 :
215 5624074 : Value *formals = formalArgsEnd() - nformal;
216 5624074 : unsigned nactual = numActualArgs();
217 5624074 : if (count == unsigned(-1))
218 5264114 : count = nactual - start;
219 :
220 5624074 : unsigned end = start + count;
221 5624074 : JS_ASSERT(end >= start);
222 5624074 : JS_ASSERT(end <= nactual);
223 :
224 5624074 : if (end <= nformal) {
225 3490782 : Value *p = formals + start;
226 4486237 : for (; start < end; ++p, ++start) {
227 995455 : if (!op(start, p))
228 0 : return false;
229 : }
230 : } else {
231 2480881 : for (Value *p = formals + start; start < nformal; ++p, ++start) {
232 347589 : if (!op(start, p))
233 0 : return false;
234 : }
235 2133292 : JS_ASSERT(start >= nformal);
236 2133292 : Value *actuals = formals - (nactual + 2) + start;
237 9856543 : for (Value *p = actuals; start < end; ++p, ++start) {
238 7723269 : if (!op(start, p))
239 18 : return false;
240 : }
241 : }
242 5624056 : 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 15275202 : 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 15275202 : JS_ASSERT(hasArgs());
281 15275202 : if (JS_UNLIKELY(flags_ & (OVERFLOW_ARGS | UNDERFLOW_ARGS)))
282 4958540 : return u.nactual;
283 10316662 : return numFormalArgs();
284 : }
285 :
286 : inline Value *
287 14230701 : StackFrame::actualArgs() const
288 : {
289 14230701 : JS_ASSERT(hasArgs());
290 14230701 : Value *argv = formalArgs();
291 14230701 : if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
292 1417567 : return argv - (2 + u.nactual);
293 12813134 : return argv;
294 : }
295 :
296 : inline Value *
297 4363392 : StackFrame::actualArgsEnd() const
298 : {
299 4363392 : JS_ASSERT(hasArgs());
300 4363392 : if (JS_UNLIKELY(flags_ & OVERFLOW_ARGS))
301 1083038 : return formalArgs() - 2;
302 3280354 : return formalArgs() + numActualArgs();
303 : }
304 :
305 : inline void
306 620157 : StackFrame::setArgsObj(ArgumentsObject &obj)
307 : {
308 620157 : JS_ASSERT_IF(hasArgsObj(), &obj == argsObj_);
309 620157 : JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.initialLength());
310 620157 : argsObj_ = &obj;
311 620157 : flags_ |= HAS_ARGS_OBJ;
312 620157 : }
313 :
314 : inline void
315 299685 : StackFrame::setScopeChainNoCallObj(JSObject &obj)
316 : {
317 : #ifdef DEBUG
318 299685 : JS_ASSERT(&obj != NULL);
319 299685 : if (&obj != sInvalidScopeChain) {
320 299685 : if (hasCallObj()) {
321 36581 : JSObject *pobj = &obj;
322 74201 : while (pobj && pobj->getPrivate() != this)
323 1039 : pobj = pobj->enclosingScope();
324 36581 : JS_ASSERT(pobj);
325 : } else {
326 265089 : for (JSObject *pobj = &obj; pobj->isScope(); pobj = pobj->enclosingScope())
327 1985 : JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
328 : }
329 : }
330 : #endif
331 299685 : scopeChain_ = &obj;
332 299685 : flags_ |= HAS_SCOPECHAIN;
333 299685 : }
334 :
335 : inline void
336 703452 : StackFrame::setScopeChainWithOwnCallObj(CallObject &obj)
337 : {
338 703452 : JS_ASSERT(&obj != NULL);
339 703452 : JS_ASSERT(!hasCallObj() && obj.maybeStackFrame() == this);
340 703452 : scopeChain_ = &obj;
341 703452 : flags_ |= HAS_SCOPECHAIN | HAS_CALL_OBJ;
342 703452 : }
343 :
344 : inline CallObject &
345 950931 : StackFrame::callObj() const
346 : {
347 950931 : JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj());
348 :
349 950931 : JSObject *pobj = &scopeChain();
350 1904071 : while (JS_UNLIKELY(!pobj->isCall()))
351 2209 : pobj = pobj->enclosingScope();
352 950931 : return pobj->asCall();
353 : }
354 :
355 : inline bool
356 24387586 : 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 24387586 : return isNonEvalFunctionFrame() && !isGeneratorFrame() && script()->nesting();
363 : }
364 :
365 : inline bool
366 29167371 : StackFrame::functionPrologue(JSContext *cx)
367 : {
368 29167371 : JS_ASSERT(isNonEvalFunctionFrame());
369 :
370 29167371 : JSFunction *fun = this->fun();
371 :
372 29167371 : if (fun->isHeavyweight()) {
373 700285 : if (!CallObject::createForFunction(cx, this))
374 0 : return false;
375 : } else {
376 : /* Force instantiation of the scope chain, for JIT frames. */
377 28467086 : scopeChain();
378 : }
379 :
380 29167371 : if (script()->nesting()) {
381 415918 : JS_ASSERT(maintainNestingState());
382 415918 : types::NestingPrologue(cx, this);
383 : }
384 :
385 29167371 : return true;
386 : }
387 :
388 : inline void
389 19816248 : StackFrame::functionEpilogue()
390 : {
391 19816248 : JS_ASSERT(isNonEvalFunctionFrame());
392 :
393 19816248 : if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
394 : /* NB: there is an ordering dependency here. */
395 1311441 : if (hasCallObj())
396 701040 : js_PutCallObject(this);
397 610401 : else if (hasArgsObj())
398 610401 : js_PutArgsObject(this);
399 : }
400 :
401 19816248 : if (maintainNestingState())
402 320368 : types::NestingEpilogue(this);
403 19816248 : }
404 :
405 : inline void
406 4155420 : StackFrame::updateEpilogueFlags()
407 : {
408 4155420 : if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
409 31254 : if (hasArgsObj() && !argsObj().maybeStackFrame())
410 15633 : flags_ &= ~HAS_ARGS_OBJ;
411 31254 : 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 12928 : scopeChain_ = isFunctionFrame()
420 12928 : ? callee().toFunction()->environment()
421 25856 : : &scopeChain_->asScope().enclosingScope();
422 12928 : 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 4155420 : if (maintainNestingState())
432 15528 : script()->nesting()->activeFrames++;
433 4155420 : }
434 :
435 : /*****************************************************************************/
436 :
437 : STATIC_POSTCONDITION(!return || ubound(from) >= nvals)
438 : JS_ALWAYS_INLINE bool
439 41021978 : StackSpace::ensureSpace(JSContext *cx, MaybeReportError report, Value *from, ptrdiff_t nvals,
440 : JSCompartment *dest) const
441 : {
442 41021978 : assertInvariants();
443 41021978 : JS_ASSERT(from >= firstUnused());
444 : #ifdef XP_WIN
445 : JS_ASSERT(from <= commitEnd_);
446 : #endif
447 41021978 : if (JS_UNLIKELY(conservativeEnd_ - from < nvals))
448 231 : return ensureSpaceSlow(cx, report, from, nvals, dest);
449 41021747 : return true;
450 : }
451 :
452 : inline Value *
453 4229385 : StackSpace::getStackLimit(JSContext *cx, MaybeReportError report)
454 : {
455 4229385 : FrameRegs ®s = cx->regs();
456 4229385 : unsigned nvals = regs.fp()->numSlots() + STACK_JIT_EXTRA;
457 4229385 : return ensureSpace(cx, report, regs.sp, nvals)
458 : ? conservativeEnd_
459 4229385 : : NULL;
460 : }
461 :
462 : /*****************************************************************************/
463 :
464 : JS_ALWAYS_INLINE StackFrame *
465 30000910 : ContextStack::getCallFrame(JSContext *cx, MaybeReportError report, const CallArgs &args,
466 : JSFunction *fun, JSScript *script, StackFrame::Flags *flags) const
467 : {
468 30000910 : JS_ASSERT(fun->script() == script);
469 30000910 : unsigned nformal = fun->nargs;
470 :
471 30000910 : Value *firstUnused = args.end();
472 30000910 : JS_ASSERT(firstUnused == space().firstUnused());
473 :
474 : /* Include extra space to satisfy the method-jit stackLimit invariant. */
475 30000910 : unsigned nvals = VALUES_PER_STACK_FRAME + script->nslots + StackSpace::STACK_JIT_EXTRA;
476 :
477 : /* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */
478 :
479 30000910 : if (args.length() == nformal) {
480 24692683 : if (!space().ensureSpace(cx, report, firstUnused, nvals))
481 71 : return NULL;
482 24692612 : return reinterpret_cast<StackFrame *>(firstUnused);
483 : }
484 :
485 5308227 : if (args.length() < nformal) {
486 423392 : *flags = StackFrame::Flags(*flags | StackFrame::UNDERFLOW_ARGS);
487 423392 : unsigned nmissing = nformal - args.length();
488 423392 : if (!space().ensureSpace(cx, report, firstUnused, nmissing + nvals))
489 1 : return NULL;
490 423391 : SetValueRangeToUndefined(firstUnused, nmissing);
491 423391 : return reinterpret_cast<StackFrame *>(firstUnused + nmissing);
492 : }
493 :
494 4884835 : *flags = StackFrame::Flags(*flags | StackFrame::OVERFLOW_ARGS);
495 4884835 : unsigned ncopy = 2 + nformal;
496 4884835 : if (!space().ensureSpace(cx, report, firstUnused, ncopy + nvals))
497 41 : return NULL;
498 4884794 : Value *dst = firstUnused;
499 4884794 : Value *src = args.base();
500 4884794 : PodCopy(dst, src, ncopy);
501 4884794 : return reinterpret_cast<StackFrame *>(firstUnused + ncopy);
502 : }
503 :
504 : JS_ALWAYS_INLINE bool
505 23760453 : ContextStack::pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
506 : JSFunction &callee, JSScript *script,
507 : InitialFrameFlags initial)
508 : {
509 23760453 : JS_ASSERT(onTop());
510 23760453 : JS_ASSERT(regs.sp == args.end());
511 : /* Cannot assert callee == args.callee() since this is called from LeaveTree. */
512 23760453 : JS_ASSERT(script == callee.script());
513 :
514 23760453 : StackFrame::Flags flags = ToFrameFlags(initial);
515 23760453 : StackFrame *fp = getCallFrame(cx, REPORT_ERROR, args, &callee, script, &flags);
516 23760453 : if (!fp)
517 73 : return false;
518 :
519 : /* Initialize frame, locals, regs. */
520 23760380 : 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 23760380 : regs.prepareToRun(*fp, script);
527 23760380 : return true;
528 : }
529 :
530 : JS_ALWAYS_INLINE bool
531 11875216 : ContextStack::pushInlineFrame(JSContext *cx, FrameRegs ®s, const CallArgs &args,
532 : JSFunction &callee, JSScript *script,
533 : InitialFrameFlags initial, Value **stackLimit)
534 : {
535 11875216 : if (!pushInlineFrame(cx, regs, args, callee, script, initial))
536 21 : return false;
537 11875195 : *stackLimit = space().conservativeEnd_;
538 11875195 : return true;
539 : }
540 :
541 : JS_ALWAYS_INLINE StackFrame *
542 1022194 : ContextStack::getFixupFrame(JSContext *cx, MaybeReportError report,
543 : const CallArgs &args, JSFunction *fun, JSScript *script,
544 : void *ncode, InitialFrameFlags initial, Value **stackLimit)
545 : {
546 1022194 : JS_ASSERT(onTop());
547 1022194 : JS_ASSERT(fun->script() == args.callee().toFunction()->script());
548 1022194 : JS_ASSERT(fun->script() == script);
549 :
550 1022194 : StackFrame::Flags flags = ToFrameFlags(initial);
551 1022194 : StackFrame *fp = getCallFrame(cx, report, args, fun, script, &flags);
552 1022194 : if (!fp)
553 12 : return NULL;
554 :
555 : /* Do not init late prologue or regs; this is done by jit code. */
556 1022182 : fp->initFixupFrame(cx->fp(), flags, ncode, args.length());
557 :
558 1022182 : *stackLimit = space().conservativeEnd_;
559 1022182 : return fp;
560 : }
561 :
562 : JS_ALWAYS_INLINE void
563 14031757 : ContextStack::popInlineFrame(FrameRegs ®s)
564 : {
565 14031757 : JS_ASSERT(onTop());
566 14031757 : JS_ASSERT(®s == &seg_->regs());
567 :
568 14031757 : StackFrame *fp = regs.fp();
569 14031757 : fp->functionEpilogue();
570 :
571 14031757 : Value *newsp = fp->actualArgs() - 1;
572 14031757 : JS_ASSERT(newsp >= fp->prev()->base());
573 :
574 14031757 : newsp[-1] = fp->returnValue();
575 14031757 : regs.popFrame(newsp);
576 14031757 : }
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 80878136 : ContextStack::currentScript(jsbytecode **ppc) const
589 : {
590 80878136 : if (ppc)
591 27316264 : *ppc = NULL;
592 :
593 80878136 : FrameRegs *regs = maybeRegs();
594 80878136 : StackFrame *fp = regs ? regs->fp() : NULL;
595 161765129 : while (fp && fp->isDummyFrame())
596 8857 : fp = fp->prev();
597 80878136 : if (!fp)
598 2007 : return NULL;
599 :
600 : #ifdef JS_METHODJIT
601 80876129 : mjit::CallSite *inlined = regs->inlined();
602 80876129 : if (inlined) {
603 4313 : mjit::JITChunk *chunk = fp->jit()->chunk(regs->pc);
604 4313 : JS_ASSERT(inlined->inlineIndex < chunk->nInlineFrames);
605 4313 : mjit::InlineFrame *frame = &chunk->inlineFrames()[inlined->inlineIndex];
606 4313 : JSScript *script = frame->fun->script();
607 4313 : if (script->compartment() != cx_->compartment)
608 0 : return NULL;
609 4313 : if (ppc)
610 266 : *ppc = script->code + inlined->pcOffset;
611 4313 : return script;
612 : }
613 : #endif
614 :
615 80871816 : JSScript *script = fp->script();
616 80871816 : if (script->compartment() != cx_->compartment)
617 8857 : return NULL;
618 :
619 80862959 : if (ppc)
620 27305143 : *ppc = fp->pcQuadratic(*this);
621 80862959 : return script;
622 : }
623 :
624 : inline JSObject *
625 55901318 : ContextStack::currentScriptedScopeChain() const
626 : {
627 55901318 : return &fp()->scopeChain();
628 : }
629 :
630 : } /* namespace js */
631 : #endif /* Stack_inl_h__ */
|