Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / js / src / jsinterpinlines.h
blobc55c868b3febdd701554f983701775a0aba086b9
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=4 sw=4 et tw=99:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is SpiderMonkey code.
19 * The Initial Developer of the Original Code is
20 * Mozilla Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2010
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Luke Wagner <lw@mozilla.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or 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.
39 * ***** END LICENSE BLOCK ***** */
41 #ifndef jsinterpinlines_h__
42 #define jsinterpinlines_h__
44 #include "jsapi.h"
45 #include "jsbool.h"
46 #include "jsinterp.h"
47 #include "jsnum.h"
48 #include "jsprobes.h"
49 #include "jsstr.h"
50 #include "methodjit/MethodJIT.h"
52 #include "jsfuninlines.h"
54 inline void
55 JSStackFrame::initPrev(JSContext *cx)
57 JS_ASSERT(flags_ & JSFRAME_HAS_PREVPC);
58 if (JSFrameRegs *regs = cx->regs) {
59 prev_ = regs->fp;
60 prevpc_ = regs->pc;
61 JS_ASSERT_IF(!prev_->isDummyFrame() && !prev_->hasImacropc(),
62 uint32(prevpc_ - prev_->script()->code) < prev_->script()->length);
63 } else {
64 prev_ = NULL;
65 #ifdef DEBUG
66 prevpc_ = (jsbytecode *)0xbadc;
67 #endif
71 inline void
72 JSStackFrame::resetGeneratorPrev(JSContext *cx)
74 flags_ |= JSFRAME_HAS_PREVPC;
75 initPrev(cx);
78 inline void
79 JSStackFrame::initCallFrame(JSContext *cx, JSObject &callee, JSFunction *fun,
80 uint32 nactual, uint32 flagsArg)
82 JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
83 JSFRAME_OVERFLOW_ARGS |
84 JSFRAME_UNDERFLOW_ARGS)) == 0);
85 JS_ASSERT(fun == callee.getFunctionPrivate());
87 /* Initialize stack frame members. */
88 flags_ = JSFRAME_FUNCTION | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN | flagsArg;
89 exec.fun = fun;
90 args.nactual = nactual; /* only need to write if over/under-flow */
91 scopeChain_ = callee.getParent();
92 initPrev(cx);
93 JS_ASSERT(!hasImacropc());
94 JS_ASSERT(!hasHookData());
95 JS_ASSERT(annotation() == NULL);
97 JS_ASSERT(!hasCallObj());
100 inline void
101 JSStackFrame::resetInvokeCallFrame()
103 /* Undo changes to frame made during execution; see initCallFrame */
105 if (hasArgsObj())
106 args.nactual = argsObj().getArgsInitialLength();
108 JS_ASSERT(!(flags_ & ~(JSFRAME_FUNCTION |
109 JSFRAME_OVERFLOW_ARGS |
110 JSFRAME_UNDERFLOW_ARGS |
111 JSFRAME_HAS_CALL_OBJ |
112 JSFRAME_HAS_ARGS_OBJ |
113 JSFRAME_OVERRIDE_ARGS |
114 JSFRAME_HAS_PREVPC |
115 JSFRAME_HAS_RVAL |
116 JSFRAME_HAS_SCOPECHAIN |
117 JSFRAME_HAS_ANNOTATION |
118 JSFRAME_FINISHED_IN_INTERPRETER)));
119 flags_ &= JSFRAME_FUNCTION |
120 JSFRAME_OVERFLOW_ARGS |
121 JSFRAME_HAS_PREVPC |
122 JSFRAME_UNDERFLOW_ARGS;
124 JS_ASSERT_IF(!hasCallObj(), scopeChain_ == calleeValue().toObject().getParent());
125 JS_ASSERT_IF(hasCallObj(), scopeChain_ == callObj().getParent());
126 if (hasCallObj())
127 scopeChain_ = callObj().getParent();
129 JS_ASSERT(exec.fun == calleeValue().toObject().getFunctionPrivate());
130 JS_ASSERT(!hasImacropc());
131 JS_ASSERT(!hasHookData());
132 JS_ASSERT(annotation() == NULL);
133 JS_ASSERT(!hasCallObj());
136 inline void
137 JSStackFrame::initCallFrameCallerHalf(JSContext *cx, uint32 flagsArg,
138 void *ncode)
140 JS_ASSERT((flagsArg & ~(JSFRAME_CONSTRUCTING |
141 JSFRAME_FUNCTION |
142 JSFRAME_OVERFLOW_ARGS |
143 JSFRAME_UNDERFLOW_ARGS)) == 0);
145 flags_ = JSFRAME_FUNCTION | flagsArg;
146 prev_ = cx->regs->fp;
147 ncode_ = ncode;
151 * The "early prologue" refers to the members that are stored for the benefit
152 * of slow paths before initializing the rest of the members.
154 inline void
155 JSStackFrame::initCallFrameEarlyPrologue(JSFunction *fun, uint32 nactual)
157 exec.fun = fun;
158 if (flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS))
159 args.nactual = nactual;
163 * The "late prologue" refers to the members that are stored after having
164 * checked for stack overflow and formal/actual arg mismatch.
166 inline void
167 JSStackFrame::initCallFrameLatePrologue()
169 SetValueRangeToUndefined(slots(), script()->nfixed);
172 inline void
173 JSStackFrame::initEvalFrame(JSContext *cx, JSScript *script, JSStackFrame *prev, uint32 flagsArg)
175 JS_ASSERT(flagsArg & JSFRAME_EVAL);
176 JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
177 JS_ASSERT(prev->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
179 /* Copy (callee, thisv). */
180 js::Value *dstvp = (js::Value *)this - 2;
181 js::Value *srcvp = prev->flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL)
182 ? (js::Value *)prev - 2
183 : prev->formalArgs() - 2;
184 dstvp[0] = srcvp[0];
185 dstvp[1] = srcvp[1];
186 JS_ASSERT_IF(prev->flags_ & JSFRAME_FUNCTION,
187 dstvp[0].toObject().isFunction());
189 /* Initialize stack frame members. */
190 flags_ = flagsArg | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN |
191 (prev->flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL | JSFRAME_HAS_CALL_OBJ));
192 if (isFunctionFrame()) {
193 exec = prev->exec;
194 args.script = script;
195 } else {
196 exec.script = script;
199 scopeChain_ = &prev->scopeChain();
200 JS_ASSERT_IF(isFunctionFrame(), &callObj() == &prev->callObj());
202 prev_ = prev;
203 prevpc_ = prev->pc(cx);
204 JS_ASSERT(!hasImacropc());
205 JS_ASSERT(!hasHookData());
206 setAnnotation(prev->annotation());
209 inline void
210 JSStackFrame::initGlobalFrame(JSScript *script, JSObject &chain, uint32 flagsArg)
212 JS_ASSERT((flagsArg & ~(JSFRAME_EVAL | JSFRAME_DEBUGGER)) == 0);
214 /* Initialize (callee, thisv). */
215 js::Value *vp = (js::Value *)this - 2;
216 vp[0].setUndefined();
217 vp[1].setUndefined(); /* Set after frame pushed using thisObject */
219 /* Initialize stack frame members. */
220 flags_ = flagsArg | JSFRAME_GLOBAL | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN;
221 exec.script = script;
222 args.script = (JSScript *)0xbad;
223 scopeChain_ = &chain;
224 prev_ = NULL;
225 JS_ASSERT(!hasImacropc());
226 JS_ASSERT(!hasHookData());
227 JS_ASSERT(annotation() == NULL);
230 inline void
231 JSStackFrame::initDummyFrame(JSContext *cx, JSObject &chain)
233 js::PodZero(this);
234 flags_ = JSFRAME_DUMMY | JSFRAME_HAS_PREVPC | JSFRAME_HAS_SCOPECHAIN;
235 initPrev(cx);
236 chain.isGlobal();
237 setScopeChainNoCallObj(chain);
240 inline void
241 JSStackFrame::stealFrameAndSlots(js::Value *vp, JSStackFrame *otherfp,
242 js::Value *othervp, js::Value *othersp)
244 JS_ASSERT(vp == (js::Value *)this - (otherfp->formalArgsEnd() - othervp));
245 JS_ASSERT(othervp == otherfp->actualArgs() - 2);
246 JS_ASSERT(othersp >= otherfp->slots());
247 JS_ASSERT(othersp <= otherfp->base() + otherfp->numSlots());
249 PodCopy(vp, othervp, othersp - othervp);
250 JS_ASSERT(vp == this->actualArgs() - 2);
252 /* Catch bad-touching of non-canonical args (e.g., generator_trace). */
253 if (otherfp->hasOverflowArgs())
254 Debug_SetValueRangeToCrashOnTouch(othervp, othervp + 2 + otherfp->numFormalArgs());
257 * Repoint Call, Arguments, Block and With objects to the new live frame.
258 * Call and Arguments are done directly because we have pointers to them.
259 * Block and With objects are done indirectly through 'liveFrame'. See
260 * js_LiveFrameToFloating comment in jsiter.h.
262 if (hasCallObj()) {
263 callObj().setPrivate(this);
264 otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ;
265 if (js_IsNamedLambda(fun())) {
266 JSObject *env = callObj().getParent();
267 JS_ASSERT(env->getClass() == &js_DeclEnvClass);
268 env->setPrivate(this);
271 if (hasArgsObj()) {
272 JSObject &args = argsObj();
273 JS_ASSERT(args.isArguments());
274 if (args.isNormalArguments())
275 args.setPrivate(this);
276 else
277 JS_ASSERT(!args.getPrivate());
278 otherfp->flags_ &= ~JSFRAME_HAS_ARGS_OBJ;
282 inline js::Value &
283 JSStackFrame::canonicalActualArg(uintN i) const
285 if (i < numFormalArgs())
286 return formalArg(i);
287 JS_ASSERT(i < numActualArgs());
288 return actualArgs()[i];
291 template <class Op>
292 inline void
293 JSStackFrame::forEachCanonicalActualArg(Op op)
295 uintN nformal = fun()->nargs;
296 js::Value *formals = formalArgsEnd() - nformal;
297 uintN nactual = numActualArgs();
298 if (nactual <= nformal) {
299 uintN i = 0;
300 js::Value *actualsEnd = formals + nactual;
301 for (js::Value *p = formals; p != actualsEnd; ++p, ++i)
302 op(i, p);
303 } else {
304 uintN i = 0;
305 js::Value *formalsEnd = formalArgsEnd();
306 for (js::Value *p = formals; p != formalsEnd; ++p, ++i)
307 op(i, p);
308 js::Value *actuals = formalsEnd - (nactual + 2);
309 js::Value *actualsEnd = formals - 2;
310 for (js::Value *p = actuals; p != actualsEnd; ++p, ++i)
311 op(i, p);
315 template <class Op>
316 inline void
317 JSStackFrame::forEachFormalArg(Op op)
319 js::Value *formals = formalArgsEnd() - fun()->nargs;
320 js::Value *formalsEnd = formalArgsEnd();
321 uintN i = 0;
322 for (js::Value *p = formals; p != formalsEnd; ++p, ++i)
323 op(i, p);
326 namespace js {
328 struct STATIC_SKIP_INFERENCE CopyNonHoleArgsTo
330 CopyNonHoleArgsTo(JSObject *aobj, Value *dst) : aobj(aobj), dst(dst) {}
331 JSObject *aobj;
332 Value *dst;
333 void operator()(uintN argi, Value *src) {
334 if (aobj->getArgsElement(argi).isMagic(JS_ARGS_HOLE))
335 dst->setUndefined();
336 else
337 *dst = *src;
338 ++dst;
342 struct CopyTo
344 Value *dst;
345 CopyTo(Value *dst) : dst(dst) {}
346 void operator()(uintN, Value *src) {
347 *dst++ = *src;
353 JS_ALWAYS_INLINE void
354 JSStackFrame::clearMissingArgs()
356 if (flags_ & JSFRAME_UNDERFLOW_ARGS)
357 SetValueRangeToUndefined(formalArgs() + numActualArgs(), formalArgsEnd());
360 inline bool
361 JSStackFrame::computeThis(JSContext *cx)
363 js::Value &thisv = thisValue();
364 if (thisv.isObject())
365 return true;
366 if (isFunctionFrame()) {
367 if (fun()->inStrictMode())
368 return true;
370 * Eval function frames have their own |this| slot, which is a copy of the function's
371 * |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the
372 * eval's frame will get the wrapper, but the function's frame will not. To prevent
373 * this, we always wrap a function's |this| before pushing an eval frame, and should
374 * thus never see an unwrapped primitive in a non-strict eval function frame.
376 JS_ASSERT(!isEvalFrame());
378 if (!js::BoxThisForVp(cx, &thisv - 1))
379 return false;
380 return true;
383 inline JSObject &
384 JSStackFrame::varobj(js::StackSegment *seg) const
386 JS_ASSERT(seg->contains(this));
387 return isFunctionFrame() ? callObj() : seg->getInitialVarObj();
390 inline JSObject &
391 JSStackFrame::varobj(JSContext *cx) const
393 JS_ASSERT(cx->activeSegment()->contains(this));
394 return isFunctionFrame() ? callObj() : cx->activeSegment()->getInitialVarObj();
397 inline uintN
398 JSStackFrame::numActualArgs() const
400 JS_ASSERT(hasArgs());
401 if (JS_UNLIKELY(flags_ & (JSFRAME_OVERFLOW_ARGS | JSFRAME_UNDERFLOW_ARGS)))
402 return hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
403 return numFormalArgs();
406 inline js::Value *
407 JSStackFrame::actualArgs() const
409 JS_ASSERT(hasArgs());
410 js::Value *argv = formalArgs();
411 if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS)) {
412 uintN nactual = hasArgsObj() ? argsObj().getArgsInitialLength() : args.nactual;
413 return argv - (2 + nactual);
415 return argv;
418 inline js::Value *
419 JSStackFrame::actualArgsEnd() const
421 JS_ASSERT(hasArgs());
422 if (JS_UNLIKELY(flags_ & JSFRAME_OVERFLOW_ARGS))
423 return formalArgs() - 2;
424 return formalArgs() + numActualArgs();
427 inline void
428 JSStackFrame::setArgsObj(JSObject &obj)
430 JS_ASSERT_IF(hasArgsObj(), &obj == args.obj);
431 JS_ASSERT_IF(!hasArgsObj(), numActualArgs() == obj.getArgsInitialLength());
432 args.obj = &obj;
433 flags_ |= JSFRAME_HAS_ARGS_OBJ;
436 inline void
437 JSStackFrame::clearArgsObj()
439 JS_ASSERT(hasArgsObj());
440 args.nactual = args.obj->getArgsInitialLength();
441 flags_ ^= JSFRAME_HAS_ARGS_OBJ;
444 inline void
445 JSStackFrame::setScopeChainNoCallObj(JSObject &obj)
447 #ifdef DEBUG
448 JS_ASSERT(&obj != NULL);
449 JSObject *callObjBefore = maybeCallObj();
450 if (!hasCallObj() && &scopeChain() != sInvalidScopeChain) {
451 for (JSObject *pobj = &scopeChain(); pobj; pobj = pobj->getParent())
452 JS_ASSERT_IF(pobj->isCall(), pobj->getPrivate() != this);
454 #endif
455 scopeChain_ = &obj;
456 flags_ |= JSFRAME_HAS_SCOPECHAIN;
457 JS_ASSERT(callObjBefore == maybeCallObj());
460 inline void
461 JSStackFrame::setScopeChainAndCallObj(JSObject &obj)
463 JS_ASSERT(&obj != NULL);
464 JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this);
465 scopeChain_ = &obj;
466 flags_ |= JSFRAME_HAS_SCOPECHAIN | JSFRAME_HAS_CALL_OBJ;
469 inline void
470 JSStackFrame::clearCallObj()
472 JS_ASSERT(hasCallObj());
473 flags_ ^= JSFRAME_HAS_CALL_OBJ;
476 inline JSObject &
477 JSStackFrame::callObj() const
479 JS_ASSERT(hasCallObj());
480 JSObject *pobj = &scopeChain();
481 while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) {
482 JS_ASSERT(js_IsCacheableNonGlobalScope(pobj) || pobj->isWith());
483 pobj = pobj->getParent();
485 return *pobj;
488 inline JSObject *
489 JSStackFrame::maybeCallObj() const
491 return hasCallObj() ? &callObj() : NULL;
494 namespace js {
496 class AutoPreserveEnumerators {
497 JSContext *cx;
498 JSObject *enumerators;
500 public:
501 AutoPreserveEnumerators(JSContext *cx) : cx(cx), enumerators(cx->enumerators)
505 ~AutoPreserveEnumerators()
507 cx->enumerators = enumerators;
511 struct AutoInterpPreparer {
512 JSContext *cx;
513 JSScript *script;
515 AutoInterpPreparer(JSContext *cx, JSScript *script)
516 : cx(cx), script(script)
518 cx->interpLevel++;
521 ~AutoInterpPreparer()
523 --cx->interpLevel;
527 inline void
528 PutActivationObjects(JSContext *cx, JSStackFrame *fp)
530 JS_ASSERT(fp->isFunctionFrame() && !fp->isEvalFrame());
532 /* The order is important as js_PutCallObject needs to access argsObj. */
533 if (fp->hasCallObj()) {
534 js_PutCallObject(cx, fp);
535 } else if (fp->hasArgsObj()) {
536 js_PutArgsObject(cx, fp);
540 class InvokeSessionGuard
542 InvokeArgsGuard args_;
543 InvokeFrameGuard frame_;
544 Value savedCallee_, savedThis_;
545 Value *formals_, *actuals_;
546 unsigned nformals_;
547 JSScript *script_;
548 Value *stackLimit_;
549 jsbytecode *stop_;
551 bool optimized() const { return frame_.pushed(); }
553 public:
554 InvokeSessionGuard() : args_(), frame_() {}
555 ~InvokeSessionGuard() {}
557 bool start(JSContext *cx, const Value &callee, const Value &thisv, uintN argc);
558 bool invoke(JSContext *cx) const;
560 bool started() const {
561 return args_.pushed();
564 Value &operator[](unsigned i) const {
565 JS_ASSERT(i < argc());
566 Value &arg = i < nformals_ ? formals_[i] : actuals_[i];
567 JS_ASSERT_IF(optimized(), &arg == &frame_.fp()->canonicalActualArg(i));
568 JS_ASSERT_IF(!optimized(), &arg == &args_[i]);
569 return arg;
572 uintN argc() const {
573 return args_.argc();
576 const Value &rval() const {
577 return optimized() ? frame_.fp()->returnValue() : args_.rval();
581 inline bool
582 InvokeSessionGuard::invoke(JSContext *cx) const
584 /* N.B. Must be kept in sync with Invoke */
586 /* Refer to canonical (callee, this) for optimized() sessions. */
587 formals_[-2] = savedCallee_;
588 formals_[-1] = savedThis_;
590 #ifdef JS_METHODJIT
591 void *code;
592 if (!optimized() || !(code = script_->getJIT(false /* !constructing */)->invokeEntry))
593 #else
594 if (!optimized())
595 #endif
596 return Invoke(cx, args_, 0);
598 /* Clear any garbage left from the last Invoke. */
599 JSStackFrame *fp = frame_.fp();
600 fp->clearMissingArgs();
601 fp->resetInvokeCallFrame();
602 SetValueRangeToUndefined(fp->slots(), script_->nfixed);
604 JSBool ok;
606 AutoPreserveEnumerators preserve(cx);
607 Probes::enterJSFun(cx, fp->fun(), script_);
608 #ifdef JS_METHODJIT
609 AutoInterpPreparer prepareInterp(cx, script_);
610 ok = mjit::EnterMethodJIT(cx, fp, code, stackLimit_);
611 cx->regs->pc = stop_;
612 #else
613 cx->regs->pc = script_->code;
614 ok = Interpret(cx, cx->fp());
615 #endif
616 Probes::exitJSFun(cx, fp->fun(), script_);
619 PutActivationObjects(cx, fp);
621 /* Don't clobber callee with rval; rval gets read from fp->rval. */
622 return ok;
625 namespace detail {
627 template<typename T> class PrimitiveBehavior { };
629 template<>
630 class PrimitiveBehavior<JSString *> {
631 public:
632 static inline bool isType(const Value &v) { return v.isString(); }
633 static inline JSString *extract(const Value &v) { return v.toString(); }
634 static inline Class *getClass() { return &js_StringClass; }
637 template<>
638 class PrimitiveBehavior<bool> {
639 public:
640 static inline bool isType(const Value &v) { return v.isBoolean(); }
641 static inline bool extract(const Value &v) { return v.toBoolean(); }
642 static inline Class *getClass() { return &js_BooleanClass; }
645 template<>
646 class PrimitiveBehavior<double> {
647 public:
648 static inline bool isType(const Value &v) { return v.isNumber(); }
649 static inline double extract(const Value &v) { return v.toNumber(); }
650 static inline Class *getClass() { return &js_NumberClass; }
653 } // namespace detail
655 template <typename T>
656 bool
657 GetPrimitiveThis(JSContext *cx, Value *vp, T *v)
659 typedef detail::PrimitiveBehavior<T> Behavior;
661 const Value &thisv = vp[1];
662 if (Behavior::isType(thisv)) {
663 *v = Behavior::extract(thisv);
664 return true;
667 if (thisv.isObject() && thisv.toObject().getClass() == Behavior::getClass()) {
668 *v = Behavior::extract(thisv.toObject().getPrimitiveThis());
669 return true;
672 ReportIncompatibleMethod(cx, vp, Behavior::getClass());
673 return false;
677 * Return an object on which we should look for the properties of |value|.
678 * This helps us implement the custom [[Get]] method that ES5's GetValue
679 * algorithm uses for primitive values, without actually constructing the
680 * temporary object that the specification does.
682 * For objects, return the object itself. For string, boolean, and number
683 * primitive values, return the appropriate constructor's prototype. For
684 * undefined and null, throw an error and return NULL, attributing the
685 * problem to the value at |spindex| on the stack.
687 JS_ALWAYS_INLINE JSObject *
688 ValuePropertyBearer(JSContext *cx, const Value &v, int spindex)
690 if (v.isObject())
691 return &v.toObject();
693 JSProtoKey protoKey;
694 if (v.isString()) {
695 protoKey = JSProto_String;
696 } else if (v.isNumber()) {
697 protoKey = JSProto_Number;
698 } else if (v.isBoolean()) {
699 protoKey = JSProto_Boolean;
700 } else {
701 JS_ASSERT(v.isNull() || v.isUndefined());
702 js_ReportIsNullOrUndefined(cx, spindex, v, NULL);
703 return NULL;
706 JSObject *pobj;
707 if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
708 return NULL;
709 return pobj;
712 static inline bool
713 ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
715 if (!fp->isExecuteFrame())
716 Probes::exitJSFun(cx, fp->maybeFun(), fp->maybeScript());
718 JSInterpreterHook hook =
719 fp->isExecuteFrame() ? cx->debugHooks->executeHook : cx->debugHooks->callHook;
721 void* hookData;
722 if (JS_UNLIKELY(hook != NULL) && (hookData = fp->maybeHookData()))
723 hook(cx, fp, JS_FALSE, &ok, hookData);
725 if (fp->isEvalFrame()) {
727 * The parent (ancestor for nested eval) of a non-strict eval frame
728 * owns its activation objects. Strict mode eval frames own their own
729 * Call objects but never have an arguments object (the first non-eval
730 * parent frame has it).
732 if (fp->script()->strictModeCode) {
733 JS_ASSERT(!fp->isYielding());
734 JS_ASSERT(!fp->hasArgsObj());
735 JS_ASSERT(fp->hasCallObj());
736 JS_ASSERT(fp->callObj().callIsForEval());
737 js_PutCallObject(cx, fp);
739 } else {
741 * Otherwise only function frames have activation objects. A yielding
742 * frame's activation objects are transferred to the floating frame,
743 * stored in the generator, and thus need not be synced.
745 if (fp->isFunctionFrame() && !fp->isYielding()) {
746 JS_ASSERT_IF(fp->hasCallObj(), !fp->callObj().callIsForEval());
747 PutActivationObjects(cx, fp);
752 * If inline-constructing, replace primitive rval with the new object
753 * passed in via |this|, and instrument this constructor invocation.
755 if (fp->isConstructing() && ok) {
756 if (fp->returnValue().isPrimitive())
757 fp->setReturnValue(ObjectValue(fp->constructorThis()));
758 JS_RUNTIME_METER(cx->runtime, constructs);
761 return ok;
766 #endif /* jsinterpinlines_h__ */