1 /* -*- Mode: C++; tab-width: 4; 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
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * Brendan Eich <brendan@mozilla.org>
24 * David Anderson <danderson@mozilla.com>
25 * David Mandelin <dmandelin@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 ***** */
44 #include "jslibmath.h"
48 #include "jsstaticcheck.h"
50 #include "assembler/assembler/MacroAssemblerCodeRef.h"
51 #include "assembler/assembler/CodeLocation.h"
52 #include "assembler/assembler/RepatchBuffer.h"
55 #include "methodjit/StubCalls.h"
57 #include "jspropertycache.h"
58 #include "methodjit/MonoIC.h"
60 #include "jspropertycacheinlines.h"
61 #include "jsscopeinlines.h"
62 #include "jsscriptinlines.h"
63 #include "jsstrinlines.h"
64 #include "jsobjinlines.h"
65 #include "jscntxtinlines.h"
66 #include "jsatominlines.h"
68 #include "jsautooplen.h"
71 using namespace js::mjit
;
76 void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
77 *f.returnAddressLocation() = ptr; \
83 void *ptr = JS_FUNC_TO_DATA_PTR(void *, JaegerThrowpoline); \
84 *f.returnAddressLocation() = ptr; \
89 InlineReturn(VMFrame
&f
, JSBool ok
);
92 FindExceptionHandler(JSContext
*cx
)
94 JSStackFrame
*fp
= cx
->fp();
95 JSScript
*script
= fp
->getScript();
98 if (cx
->throwing
&& script
->trynotesOffset
) {
99 // The PC is updated before every stub call, so we can use it here.
100 unsigned offset
= cx
->regs
->pc
- script
->main
;
102 JSTryNoteArray
*tnarray
= script
->trynotes();
103 for (unsigned i
= 0; i
< tnarray
->length
; ++i
) {
104 JSTryNote
*tn
= &tnarray
->vector
[i
];
105 JS_ASSERT(offset
< script
->length
);
106 // The following if condition actually tests two separate conditions:
107 // (1) offset - tn->start >= tn->length
108 // means the PC is not in the range of this try note, so we
109 // should continue searching, after considering:
110 // (2) offset - tn->start == tn->length
111 // means the PC is at the first op of the exception handler
112 // for this try note. This happens when an exception is thrown
113 // during recording: the interpreter sets the PC to the handler
114 // and then exits. In this case, we are in fact at the right
115 // exception handler.
117 // Hypothetically, the op we are at might have thrown an
118 // exception, in which case this would not be the right handler.
119 // But the first ops of exception handlers generated by our
120 // bytecode compiler cannot throw, so this is not possible.
121 if (offset
- tn
->start
> tn
->length
)
123 if (tn
->stackDepth
> cx
->regs
->sp
- fp
->base())
126 jsbytecode
*pc
= script
->main
+ tn
->start
+ tn
->length
;
127 JSBool ok
= js_UnwindScope(cx
, tn
->stackDepth
, JS_TRUE
);
128 JS_ASSERT(cx
->regs
->sp
== fp
->base() + tn
->stackDepth
);
132 JS_ASSERT(js_GetOpcode(cx
, fp
->getScript(), pc
) == JSOP_ENTERBLOCK
);
134 #if JS_HAS_GENERATORS
135 /* Catch cannot intercept the closing of a generator. */
136 if (JS_UNLIKELY(cx
->exception
.isMagic(JS_GENERATOR_CLOSING
)))
141 * Don't clear cx->throwing to save cx->exception from GC
142 * until it is pushed to the stack via [exception] in the
149 * Push (true, exception) pair for finally to indicate that
150 * [retsub] should rethrow the exception.
152 cx
->regs
->sp
[0].setBoolean(true);
153 cx
->regs
->sp
[1] = cx
->exception
;
155 cx
->throwing
= JS_FALSE
;
161 * This is similar to JSOP_ENDITER in the interpreter loop,
162 * except the code now uses the stack slot normally used by
163 * JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2
164 * adjustment and regs.sp[1] after, to save and restore the
167 AutoValueRooter
tvr(cx
, cx
->exception
);
168 JS_ASSERT(js_GetOpcode(cx
, fp
->getScript(), pc
) == JSOP_ENDITER
);
169 cx
->throwing
= JS_FALSE
;
170 ok
= !!js_CloseIterator(cx
, &cx
->regs
->sp
[-1].toObject());
174 cx
->throwing
= JS_TRUE
;
175 cx
->exception
= tvr
.value();
185 InlineReturn(VMFrame
&f
, JSBool ok
)
187 JSContext
*cx
= f
.cx
;
188 JSStackFrame
*fp
= f
.regs
.fp
;
190 JS_ASSERT(f
.fp() != f
.entryFp
);
192 JS_ASSERT(!fp
->hasBlockChain());
193 JS_ASSERT(!js_IsActiveWithOrBlock(cx
, fp
->getScopeChain(), 0));
195 // Marker for debug support.
196 if (JS_UNLIKELY(fp
->hasHookData())) {
197 JSInterpreterHook hook
;
200 hook
= cx
->debugHooks
->callHook
;
203 * Do not pass &ok directly as exposing the address inhibits
204 * optimizations and uninitialised warnings.
207 hook(cx
, fp
, JS_FALSE
, &status
, fp
->getHookData());
208 ok
= (status
== JS_TRUE
);
209 // CHECK_INTERRUPT_HANDLER();
213 fp
->putActivationObjects(cx
);
215 /* :TODO: version stuff */
217 if (fp
->flags
& JSFRAME_CONSTRUCTING
&& fp
->getReturnValue().isPrimitive())
218 fp
->setReturnValue(fp
->getThisValue());
220 Value
*newsp
= fp
->argv
- 1;
222 cx
->stack().popInlineFrame(cx
, fp
, fp
->down
);
224 cx
->regs
->sp
= newsp
;
225 cx
->regs
->sp
[-1] = fp
->getReturnValue();
227 JS_ASSERT(cx
->regs
->pc
!= JSStackFrame::sInvalidPC
);
233 stubs::NewObject(VMFrame
&f
, uint32 argc
)
235 JSContext
*cx
= f
.cx
;
236 Value
*vp
= f
.regs
.sp
- (argc
+ 2);
238 JSObject
*funobj
= &vp
[0].toObject();
239 JS_ASSERT(funobj
->isFunction());
241 jsid id
= ATOM_TO_JSID(cx
->runtime
->atomState
.classPrototypeAtom
);
242 if (!funobj
->getProperty(cx
, id
, &vp
[1]))
245 JSObject
*proto
= vp
[1].isObject() ? &vp
[1].toObject() : NULL
;
246 JSObject
*obj
= NewNonFunction
<WithProto::Class
>(cx
, &js_ObjectClass
, proto
, funobj
->getParent());
250 vp
[1].setObject(*obj
);
256 stubs::SlowCall(VMFrame
&f
, uint32 argc
)
258 Value
*vp
= f
.regs
.sp
- (argc
+ 2);
260 if (!Invoke(f
.cx
, InvokeArgsAlreadyOnTheStack(vp
, argc
), 0))
265 stubs::SlowNew(VMFrame
&f
, uint32 argc
)
267 JSContext
*cx
= f
.cx
;
268 Value
*vp
= f
.regs
.sp
- (argc
+ 2);
270 if (!InvokeConstructor(cx
, InvokeArgsAlreadyOnTheStack(vp
, argc
)))
275 RemovePartialFrame(VMFrame
&f
)
277 /* Unwind the half-pushed frame. */
278 f
.regs
.pc
= f
.fp()->down
->savedPC
;
279 f
.regs
.sp
= f
.fp()->argv
+ f
.fp()->argc
;
281 f
.fp()->down
->savedPC
= JSStackFrame::sInvalidPC
;
283 f
.regs
.fp
= f
.fp()->down
;
287 stubs::CheckStackQuota(VMFrame
&f
)
289 if (JS_LIKELY(f
.ensureSpace(0, f
.fp()->getScript()->nslots
)))
292 RemovePartialFrame(f
);
294 js_ReportOverRecursed(f
.cx
);
299 stubs::CheckArity(VMFrame
&f
)
301 JSContext
*cx
= f
.cx
;
302 JSStackFrame
*fp
= f
.fp();
303 uint32 argc
= fp
->argc
;
304 JSFunction
*fun
= fp
->getFunction();
306 JS_ASSERT(argc
< fun
->nargs
);
309 * Grossssss! *move* the stack frame. If this ends up being perf-critical,
310 * we can figure out how to spot-optimize it. As the frame shrinks it will
313 uint32 flags
= fp
->flags
;
314 JSObject
*scopeChain
= fp
->getScopeChain();
315 Value
*argv
= fp
->argv
;
316 JSStackFrame
*down
= fp
->down
;
317 void *ncode
= fp
->ncode
;
319 /* Pop the inline frame. */
320 RemovePartialFrame(f
);
322 uint32 missing
= fun
->nargs
- argc
;
324 /* Include an extra stack frame for callees. */
325 if (!f
.ensureSpace(missing
, fun
->u
.i
.script
->nslots
+ VALUES_PER_STACK_FRAME
)) {
326 js_ReportOverRecursed(cx
);
331 down
->savedPC
= f
.regs
.pc
;
334 SetValueRangeToUndefined(f
.regs
.sp
, missing
);
335 f
.regs
.sp
+= missing
;
337 JSStackFrame
*newfp
= (JSStackFrame
*)f
.regs
.sp
;
339 newfp
->setFunction(fun
);
340 newfp
->flags
= flags
;
342 newfp
->setScopeChain(scopeChain
);
344 newfp
->ncode
= ncode
;
345 newfp
->setThisValue(argv
[-1]);
351 stubs::CompileFunction(VMFrame
&f
)
354 * We have a partially constructed frame. That's not really good enough to
355 * compile though because we could throw, so get a full, adjusted frame.
357 JSContext
*cx
= f
.cx
;
358 JSStackFrame
*fp
= f
.fp();
359 uint32 argc
= fp
->argc
;
361 JSObject
*obj
= &fp
->argv
[-2].toObject();
362 JSFunction
*fun
= obj
->getFunctionPrivate();
363 JSScript
*script
= fun
->u
.i
.script
;
365 bool callingNew
= !!(fp
->flags
& JSFRAME_CONSTRUCTING
);
367 /* Empty script does nothing. */
368 if (script
->isEmpty()) {
369 RemovePartialFrame(f
);
370 Value
*vp
= f
.regs
.sp
- argc
;
374 vp
[-2].setUndefined();
378 /* CheckArity expects fun to be set. */
379 fp
->setFunction(fun
);
381 if (argc
< fun
->nargs
) {
382 fp
= (JSStackFrame
*)CheckArity(f
);
387 fp
->setCallObj(NULL
);
388 fp
->setArgsObj(NULL
);
389 fp
->setBlockChain(NULL
);
390 fp
->setHookData(NULL
);
391 fp
->setAnnotation(NULL
);
392 fp
->setCallerVersion(fp
->down
->getCallerVersion());
393 fp
->setScript(script
);
394 fp
->clearReturnValue();
396 fp
->savedPC
= JSStackFrame::sInvalidPC
;
400 f
.regs
.sp
= fp
->base();
401 f
.regs
.pc
= script
->code
;
403 SetValueRangeToUndefined(fp
->slots(), script
->nfixed
);
405 if (fun
->isHeavyweight() && !js_GetCallObject(cx
, fp
))
408 CompileStatus status
= CanMethodJIT(cx
, script
, fun
, fp
->getScopeChain());
409 if (status
== Compile_Okay
)
410 return script
->jit
->invoke
;
412 /* Function did not compile... interpret it. */
413 JSBool ok
= Interpret(cx
, fp
);
422 /* Preserved for when calls need to be slow (debug mode, no ICs) */
424 CreateFrame(VMFrame
&f
, uint32 flags
, uint32 argc
)
426 JSContext
*cx
= f
.cx
;
427 JSStackFrame
*fp
= f
.fp();
428 Value
*vp
= f
.regs
.sp
- (argc
+ 2);
429 JSObject
*funobj
= &vp
->toObject();
430 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, funobj
);
432 JS_ASSERT(FUN_INTERPRETED(fun
));
434 JSScript
*newscript
= fun
->u
.i
.script
;
436 /* Allocate the frame. */
437 StackSpace
&stack
= cx
->stack();
438 uintN nslots
= newscript
->nslots
;
439 uintN funargs
= fun
->nargs
;
440 Value
*argv
= vp
+ 2;
442 if (argc
< funargs
) {
443 uintN missing
= funargs
- argc
;
444 if (!f
.ensureSpace(missing
, nslots
))
446 newfp
= stack
.getInlineFrameUnchecked(cx
, f
.regs
.sp
, missing
);
449 for (Value
*v
= argv
+ argc
, *end
= v
+ missing
; v
!= end
; ++v
)
452 if (!f
.ensureSpace(0, nslots
))
454 newfp
= stack
.getInlineFrameUnchecked(cx
, f
.regs
.sp
, 0);
459 /* Initialize the frame. */
461 newfp
->setCallObj(NULL
);
462 newfp
->setArgsObj(NULL
);
463 newfp
->setScript(newscript
);
464 newfp
->setFunction(fun
);
466 newfp
->argv
= vp
+ 2;
467 newfp
->clearReturnValue();
468 newfp
->setAnnotation(NULL
);
469 newfp
->setScopeChain(funobj
->getParent());
470 newfp
->flags
= flags
;
471 newfp
->setBlockChain(NULL
);
472 newfp
->setThisValue(vp
[1]);
473 JS_ASSERT(!fp
->hasIMacroPC());
475 /* Push void to initialize local variables. */
476 Value
*newslots
= newfp
->slots();
477 Value
*newsp
= newslots
+ fun
->u
.i
.nvars
;
478 for (Value
*v
= newslots
; v
!= newsp
; ++v
)
481 /* Scope with a call object parented by callee's parent. */
482 if (fun
->isHeavyweight() && !js_GetCallObject(cx
, newfp
))
485 /* :TODO: Switch version if currentVersion wasn't overridden. */
486 newfp
->setCallerVersion((JSVersion
)cx
->version
);
488 // Marker for debug support.
489 if (JSInterpreterHook hook
= cx
->debugHooks
->callHook
) {
490 newfp
->setHookData(hook(cx
, fp
, JS_TRUE
, 0,
491 cx
->debugHooks
->callHookData
));
493 newfp
->setHookData(NULL
);
496 stack
.pushInlineFrame(cx
, fp
, cx
->regs
->pc
, newfp
);
503 UncachedInlineCall(VMFrame
&f
, uint32 flags
, void **pret
, uint32 argc
)
505 if (!CreateFrame(f
, flags
, argc
))
508 JSContext
*cx
= f
.cx
;
509 JSStackFrame
*fp
= cx
->fp();
510 JSScript
*script
= fp
->getScript();
511 f
.regs
.pc
= script
->code
;
512 f
.regs
.sp
= fp
->base();
514 if (cx
->options
& JSOPTION_METHODJIT
) {
515 if (!script
->ncode
) {
516 if (mjit::TryCompile(cx
, script
, fp
->getFunction(), fp
->getScopeChain()) == Compile_Error
) {
517 InlineReturn(f
, JS_FALSE
);
521 JS_ASSERT(script
->ncode
);
522 if (script
->ncode
!= JS_UNJITTABLE_METHOD
) {
523 *pret
= script
->jit
->invoke
;
528 bool ok
= !!Interpret(cx
, cx
->fp());
529 InlineReturn(f
, JS_TRUE
);
536 stubs::UncachedNew(VMFrame
&f
, uint32 argc
)
538 JSContext
*cx
= f
.cx
;
540 Value
*vp
= f
.regs
.sp
- (argc
+ 2);
543 if (IsFunctionObject(*vp
, &obj
)) {
544 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
546 if (fun
->isInterpreted()) {
547 JSScript
*script
= fun
->u
.i
.script
;
548 if (!stubs::NewObject(f
, argc
))
551 if (script
->isEmpty()) {
557 if (!UncachedInlineCall(f
, JSFRAME_CONSTRUCTING
, &ret
, argc
))
563 if (fun
->isConstructor()) {
564 vp
[1].setMagicWithObjectOrNullPayload(NULL
);
565 Native fn
= fun
->u
.n
.native
;
566 if (!fn(cx
, argc
, vp
))
568 JS_ASSERT(!vp
->isPrimitive());
573 if (!InvokeConstructor(cx
, InvokeArgsAlreadyOnTheStack(vp
, argc
)))
580 stubs::UncachedCall(VMFrame
&f
, uint32 argc
)
582 JSContext
*cx
= f
.cx
;
584 Value
*vp
= f
.regs
.sp
- (argc
+ 2);
587 if (IsFunctionObject(*vp
, &obj
)) {
588 JSFunction
*fun
= GET_FUNCTION_PRIVATE(cx
, obj
);
590 if (fun
->isInterpreted()) {
593 if (fun
->u
.i
.script
->isEmpty()) {
599 if (!UncachedInlineCall(f
, 0, &ret
, argc
))
605 if (fun
->isNative()) {
606 if (!fun
->u
.n
.native(cx
, argc
, vp
))
612 if (!Invoke(f
.cx
, InvokeArgsAlreadyOnTheStack(vp
, argc
), 0))
619 stubs::PutCallObject(VMFrame
&f
)
621 JS_ASSERT(f
.fp()->hasCallObj());
622 js_PutCallObject(f
.cx
, f
.fp());
623 JS_ASSERT(!f
.fp()->hasArgsObj());
627 stubs::PutArgsObject(VMFrame
&f
)
629 js_PutArgsObject(f
.cx
, f
.fp());
633 js_InternalThrow(VMFrame
&f
)
635 JSContext
*cx
= f
.cx
;
637 // Make sure sp is up to date.
638 JS_ASSERT(cx
->regs
== &f
.regs
);
640 // Call the throw hook if necessary
641 JSThrowHook handler
= f
.cx
->debugHooks
->throwHook
;
644 switch (handler(cx
, cx
->fp()->getScript(), cx
->regs
->pc
, Jsvalify(&rval
),
645 cx
->debugHooks
->throwHookData
)) {
647 cx
->throwing
= JS_FALSE
;
651 cx
->throwing
= JS_FALSE
;
652 cx
->fp()->setReturnValue(rval
);
653 return JS_FUNC_TO_DATA_PTR(void *,
654 JS_METHODJIT_DATA(cx
).trampolines
.forceReturn
);
657 cx
->exception
= rval
;
665 jsbytecode
*pc
= NULL
;
667 pc
= FindExceptionHandler(cx
);
671 // If on the 'topmost' frame (where topmost means the first frame
672 // called into through js_Interpret). In this case, we still unwind,
673 // but we shouldn't return from a JS function, because we're not in a
675 bool lastFrame
= (f
.entryFp
== f
.fp());
676 js_UnwindScope(cx
, 0, cx
->throwing
);
680 JS_ASSERT(f
.regs
.sp
== cx
->regs
->sp
);
681 InlineReturn(f
, JS_FALSE
);
684 JS_ASSERT(f
.regs
.sp
== cx
->regs
->sp
);
688 f
.cx
->setCurrentRegs(f
.oldRegs
);
692 return cx
->fp()->getScript()->pcToNative(pc
);
696 stubs::GetCallObject(VMFrame
&f
)
698 JS_ASSERT(f
.fp()->getFunction()->isHeavyweight());
699 if (!js_GetCallObject(f
.cx
, f
.fp()))
704 AdvanceReturnPC(JSContext
*cx
)
706 /* Simulate an inline_return by advancing the pc. */
707 JS_ASSERT(*cx
->regs
->pc
== JSOP_CALL
||
708 *cx
->regs
->pc
== JSOP_NEW
||
709 *cx
->regs
->pc
== JSOP_EVAL
||
710 *cx
->regs
->pc
== JSOP_APPLY
);
711 cx
->regs
->pc
+= JSOP_CALL_LENGTH
;
717 SwallowErrors(VMFrame
&f
, JSStackFrame
*stopFp
)
719 JSContext
*cx
= f
.cx
;
721 /* Remove the bottom frame. */
724 JSStackFrame
*fp
= cx
->fp();
726 /* Look for an imacro with hard-coded exception handlers. */
727 if (fp
->hasIMacroPC() && cx
->throwing
) {
728 cx
->regs
->pc
= fp
->getIMacroPC();
733 JS_ASSERT(!fp
->hasIMacroPC());
735 /* If there's an exception and a handler, set the pc and leave. */
736 jsbytecode
*pc
= FindExceptionHandler(cx
);
743 /* Don't unwind if this was the entry frame. */
747 /* Unwind and return. */
748 ok
&= bool(js_UnwindScope(cx
, 0, cx
->throwing
));
752 /* Update the VMFrame before leaving. */
753 JS_ASSERT(&f
.regs
== cx
->regs
);
755 JS_ASSERT_IF(!ok
, cx
->fp() == stopFp
);
760 AtSafePoint(JSContext
*cx
)
762 JSStackFrame
*fp
= cx
->fp();
763 if (fp
->hasIMacroPC())
766 JSScript
*script
= fp
->getScript();
770 JS_ASSERT(cx
->regs
->pc
>= script
->code
&& cx
->regs
->pc
< script
->code
+ script
->length
);
771 return !!script
->nmap
[cx
->regs
->pc
- script
->code
];
775 PartialInterpret(VMFrame
&f
)
777 JSContext
*cx
= f
.cx
;
778 JSStackFrame
*fp
= cx
->fp();
780 JS_ASSERT(fp
->hasIMacroPC() || !fp
->getScript()->nmap
||
781 !fp
->getScript()->nmap
[cx
->regs
->pc
- fp
->getScript()->code
]);
784 fp
->flags
|= JSFRAME_BAILING
;
785 ok
= Interpret(cx
, fp
);
786 fp
->flags
&= ~JSFRAME_BAILING
;
793 JS_STATIC_ASSERT(JSOP_NOP
== 0);
796 FrameIsFinished(JSContext
*cx
)
798 JSOp op
= JSOp(*cx
->regs
->pc
);
799 return (op
== JSOP_RETURN
||
800 op
== JSOP_RETRVAL
||
807 RemoveExcessFrames(VMFrame
&f
, JSStackFrame
*entryFrame
)
809 JSContext
*cx
= f
.cx
;
810 while (cx
->fp() != entryFrame
) {
811 JSStackFrame
*fp
= cx
->fp();
812 fp
->flags
&= ~JSFRAME_RECORDING
;
814 if (AtSafePoint(cx
)) {
815 JSScript
*script
= fp
->getScript();
816 if (!JaegerShotAtSafePoint(cx
, script
->nmap
[cx
->regs
->pc
- script
->code
])) {
817 if (!SwallowErrors(f
, entryFrame
))
820 /* Could be anywhere - restart outer loop. */
823 InlineReturn(f
, JS_TRUE
);
826 if (!PartialInterpret(f
)) {
827 if (!SwallowErrors(f
, entryFrame
))
831 * Partial interpret could have dropped us anywhere. Deduce the
832 * edge case: at a RETURN, needing to pop a frame.
834 if (!cx
->fp()->hasIMacroPC() && FrameIsFinished(cx
)) {
835 JSOp op
= JSOp(*cx
->regs
->pc
);
836 if (op
== JSOP_RETURN
&& !(cx
->fp()->flags
& JSFRAME_BAILED_AT_RETURN
))
837 fp
->setReturnValue(f
.regs
.sp
[-1]);
838 InlineReturn(f
, JS_TRUE
);
850 DisableTraceHint(VMFrame
&f
, ic::MICInfo
&mic
)
852 JS_ASSERT(mic
.kind
== ic::MICInfo::TRACER
);
855 * Hack: The value that will be patched is before the executable address,
856 * so to get protection right, just unprotect the general region around
859 uint8
*addr
= (uint8
*)(mic
.traceHint
.executableAddress());
860 JSC::RepatchBuffer
repatch(addr
- 64, 128);
861 repatch
.relink(mic
.traceHint
, mic
.load
);
863 JaegerSpew(JSpew_PICs
, "relinking trace hint %p to %p\n", mic
.traceHint
.executableAddress(),
864 mic
.load
.executableAddress());
866 if (mic
.u
.hasSlowTraceHint
) {
867 addr
= (uint8
*)(mic
.slowTraceHint
.executableAddress());
868 JSC::RepatchBuffer
repatch(addr
- 64, 128);
869 repatch
.relink(mic
.slowTraceHint
, mic
.load
);
871 JaegerSpew(JSpew_PICs
, "relinking trace hint %p to %p\n",
872 mic
.slowTraceHint
.executableAddress(),
873 mic
.load
.executableAddress());
880 RunTracer(VMFrame
&f
, ic::MICInfo
&mic
)
883 RunTracer(VMFrame
&f
)
886 JSContext
*cx
= f
.cx
;
887 JSStackFrame
*entryFrame
= f
.fp();
888 TracePointAction tpa
;
890 /* :TODO: nuke PIC? */
895 uintN inlineCallCount
= 0;
896 tpa
= MonitorTracePoint(f
.cx
, inlineCallCount
, blacklist
);
897 JS_ASSERT(!TRACE_RECORDER(cx
));
901 DisableTraceHint(f
, mic
);
904 if ((tpa
== TPA_RanStuff
|| tpa
== TPA_Recorded
) && cx
->throwing
)
907 /* Sync up the VMFrame's view of cx->fp(). */
915 if (!SwallowErrors(f
, entryFrame
))
917 JS_ASSERT(!cx
->fp()->hasIMacroPC());
926 * The tracer could have dropped us off on any frame at any position.
927 * Well, it could not have removed frames (recursion is disabled).
929 * Frames after the entryFrame cannot be entered via JaegerShotAtSafePoint()
930 * unless each is at a safe point. We can JaegerShotAtSafePoint these
931 * frames individually, but we must unwind to the entryFrame.
933 * Note carefully that JaegerShotAtSafePoint can resume methods at
934 * arbitrary safe points whereas JaegerShot cannot.
936 * If we land on entryFrame without a safe point in sight, we'll end up
937 * at the RETURN op. This is an edge case with two paths:
939 * 1) The entryFrame is the last inline frame. If it fell on a RETURN,
940 * move the return value down.
941 * 2) The entryFrame is NOT the last inline frame. Pop the frame.
943 * In both cases, we hijack the stub to return to InjectJaegerReturn. This
944 * moves |oldFp->rval| into the scripted return registers.
948 /* Step 1. Initial removal of excess frames. */
949 if (!RemoveExcessFrames(f
, entryFrame
))
952 /* Step 2. If there's an imacro on the entry frame, remove it. */
953 entryFrame
->flags
&= ~JSFRAME_RECORDING
;
954 while (entryFrame
->hasIMacroPC()) {
955 if (!PartialInterpret(f
)) {
956 if (!SwallowErrors(f
, entryFrame
))
960 /* After partial interpreting, we could have more frames again. */
964 /* Step 3.1. If entryFrame is at a safe point, just leave. */
965 if (AtSafePoint(cx
)) {
966 uint32 offs
= uint32(cx
->regs
->pc
- entryFrame
->getScript()->code
);
967 JS_ASSERT(entryFrame
->getScript()->nmap
[offs
]);
968 return entryFrame
->getScript()->nmap
[offs
];
971 /* Step 3.2. If entryFrame is at a RETURN, then leave slightly differently. */
972 if (JSOp op
= FrameIsFinished(cx
)) {
973 /* We're not guaranteed that the RETURN was run. */
974 if (op
== JSOP_RETURN
&& !(entryFrame
->flags
& JSFRAME_BAILED_AT_RETURN
))
975 entryFrame
->setReturnValue(f
.regs
.sp
[-1]);
977 /* Don't pop the frame if it's maybe owned by an Invoke. */
978 if (f
.fp() != f
.entryFp
) {
979 if (!InlineReturn(f
, JS_TRUE
))
982 void *retPtr
= JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn
);
983 *f
.returnAddressLocation() = retPtr
;
987 /* Step 3.3. Do a partial interp, then restart the whole process. */
988 if (!PartialInterpret(f
)) {
989 if (!SwallowErrors(f
, entryFrame
))
996 #endif /* JS_TRACER */
998 #if defined JS_TRACER
999 # if defined JS_MONOIC
1001 stubs::InvokeTracer(VMFrame
&f
, uint32 index
)
1003 JSScript
*script
= f
.fp()->getScript();
1004 ic::MICInfo
&mic
= script
->mics
[index
];
1006 JS_ASSERT(mic
.kind
== ic::MICInfo::TRACER
);
1008 return RunTracer(f
, mic
);
1014 stubs::InvokeTracer(VMFrame
&f
)
1016 return RunTracer(f
);
1018 # endif /* JS_MONOIC */
1019 #endif /* JS_TRACER */