Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/Bailouts.h"
9 #include "jscntxt.h"
11 #include "jit/BaselineJIT.h"
12 #include "jit/Ion.h"
13 #include "jit/IonSpewer.h"
14 #include "jit/JitCompartment.h"
15 #include "jit/Snapshots.h"
16 #include "vm/TraceLogging.h"
18 #include "jit/JitFrameIterator-inl.h"
19 #include "vm/Stack-inl.h"
21 using namespace js;
22 using namespace js::jit;
24 // These constructor are exactly the same except for the type of the iterator
25 // which is given to the SnapshotIterator constructor. Doing so avoid the
26 // creation of virtual functions for the IonIterator but may introduce some
27 // weirdness as IonInlineIterator is using a JitFrameIterator reference.
28 //
29 // If a function relies on ionScript() or to use OsiIndex(), due to the
30 // lack of virtual, these functions will use the JitFrameIterator reference
31 // contained in the InlineFrameIterator and thus are not able to recover
32 // correctly the data stored in IonBailoutIterator.
33 //
34 // Currently, such cases should not happen because our only use case of the
35 // JitFrameIterator within InlineFrameIterator is to read the frame content, or
36 // to clone it to find the parent scripted frame. Both use cases are fine and
37 // should not cause any issue since the only potential issue is to read the
38 // bailed out frame.
40 SnapshotIterator::SnapshotIterator(const IonBailoutIterator &iter)
41 : snapshot_(iter.ionScript()->snapshots(),
42 iter.snapshotOffset(),
43 iter.ionScript()->snapshotsRVATableSize(),
44 iter.ionScript()->snapshotsListSize()),
45 recover_(snapshot_,
46 iter.ionScript()->recovers(),
47 iter.ionScript()->recoversSize()),
48 fp_(iter.jsFrame()),
49 machine_(iter.machineState()),
50 ionScript_(iter.ionScript())
51 {
52 }
54 void
55 IonBailoutIterator::dump() const
56 {
57 if (type_ == JitFrame_IonJS) {
58 InlineFrameIterator frames(GetJSContextFromJitCode(), this);
59 for (;;) {
60 frames.dump();
61 if (!frames.more())
62 break;
63 ++frames;
64 }
65 } else {
66 JitFrameIterator::dump();
67 }
68 }
70 uint32_t
71 jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo)
72 {
73 JSContext *cx = GetJSContextFromJitCode();
74 JS_ASSERT(bailoutInfo);
76 // We don't have an exit frame.
77 cx->mainThread().ionTop = nullptr;
78 JitActivationIterator jitActivations(cx->runtime());
79 IonBailoutIterator iter(jitActivations, sp);
80 JitActivation *activation = jitActivations->asJit();
82 TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
83 TraceLogTimestamp(logger, TraceLogger::Bailout);
85 IonSpew(IonSpew_Bailouts, "Took bailout! Snapshot offset: %d", iter.snapshotOffset());
87 JS_ASSERT(IsBaselineEnabled(cx));
89 *bailoutInfo = nullptr;
90 uint32_t retval = BailoutIonToBaseline(cx, activation, iter, false, bailoutInfo);
91 JS_ASSERT(retval == BAILOUT_RETURN_OK ||
92 retval == BAILOUT_RETURN_FATAL_ERROR ||
93 retval == BAILOUT_RETURN_OVERRECURSED);
94 JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
96 if (retval != BAILOUT_RETURN_OK)
97 EnsureExitFrame(iter.jsFrame());
99 return retval;
100 }
102 uint32_t
103 jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut,
104 BaselineBailoutInfo **bailoutInfo)
105 {
106 sp->checkInvariants();
108 JSContext *cx = GetJSContextFromJitCode();
110 // We don't have an exit frame.
111 cx->mainThread().ionTop = nullptr;
112 JitActivationIterator jitActivations(cx->runtime());
113 IonBailoutIterator iter(jitActivations, sp);
114 JitActivation *activation = jitActivations->asJit();
116 TraceLogger *logger = TraceLoggerForMainThread(cx->runtime());
117 TraceLogTimestamp(logger, TraceLogger::Invalidation);
119 IonSpew(IonSpew_Bailouts, "Took invalidation bailout! Snapshot offset: %d", iter.snapshotOffset());
121 // Note: the frame size must be computed before we return from this function.
122 *frameSizeOut = iter.topFrameSize();
124 JS_ASSERT(IsBaselineEnabled(cx));
126 *bailoutInfo = nullptr;
127 uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, bailoutInfo);
128 JS_ASSERT(retval == BAILOUT_RETURN_OK ||
129 retval == BAILOUT_RETURN_FATAL_ERROR ||
130 retval == BAILOUT_RETURN_OVERRECURSED);
131 JS_ASSERT_IF(retval == BAILOUT_RETURN_OK, *bailoutInfo != nullptr);
133 if (retval != BAILOUT_RETURN_OK) {
134 IonJSFrameLayout *frame = iter.jsFrame();
135 IonSpew(IonSpew_Invalidate, "converting to exit frame");
136 IonSpew(IonSpew_Invalidate, " orig calleeToken %p", (void *) frame->calleeToken());
137 IonSpew(IonSpew_Invalidate, " orig frameSize %u", unsigned(frame->prevFrameLocalSize()));
138 IonSpew(IonSpew_Invalidate, " orig ra %p", (void *) frame->returnAddress());
140 frame->replaceCalleeToken(nullptr);
141 EnsureExitFrame(frame);
143 IonSpew(IonSpew_Invalidate, " new calleeToken %p", (void *) frame->calleeToken());
144 IonSpew(IonSpew_Invalidate, " new frameSize %u", unsigned(frame->prevFrameLocalSize()));
145 IonSpew(IonSpew_Invalidate, " new ra %p", (void *) frame->returnAddress());
146 }
148 iter.ionScript()->decref(cx->runtime()->defaultFreeOp());
150 return retval;
151 }
153 IonBailoutIterator::IonBailoutIterator(const JitActivationIterator &activations,
154 const JitFrameIterator &frame)
155 : JitFrameIterator(activations),
156 machine_(frame.machineState())
157 {
158 returnAddressToFp_ = frame.returnAddressToFp();
159 topIonScript_ = frame.ionScript();
160 const OsiIndex *osiIndex = frame.osiIndex();
162 current_ = (uint8_t *) frame.fp();
163 type_ = JitFrame_IonJS;
164 topFrameSize_ = frame.frameSize();
165 snapshotOffset_ = osiIndex->snapshotOffset();
166 }
168 uint32_t
169 jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame,
170 ResumeFromException *rfe,
171 const ExceptionBailoutInfo &excInfo,
172 bool *overrecursed)
173 {
174 // We can be propagating debug mode exceptions without there being an
175 // actual exception pending. For instance, when we return false from an
176 // operation callback like a timeout handler.
177 MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
179 cx->mainThread().ionTop = nullptr;
180 JitActivationIterator jitActivations(cx->runtime());
181 IonBailoutIterator iter(jitActivations, frame.frame());
182 JitActivation *activation = jitActivations->asJit();
184 BaselineBailoutInfo *bailoutInfo = nullptr;
185 uint32_t retval = BailoutIonToBaseline(cx, activation, iter, true, &bailoutInfo, &excInfo);
187 if (retval == BAILOUT_RETURN_OK) {
188 MOZ_ASSERT(bailoutInfo);
190 // Overwrite the kind so HandleException after the bailout returns
191 // false, jumping directly to the exception tail.
192 if (excInfo.propagatingIonExceptionForDebugMode())
193 bailoutInfo->bailoutKind = Bailout_IonExceptionDebugMode;
195 rfe->kind = ResumeFromException::RESUME_BAILOUT;
196 rfe->target = cx->runtime()->jitRuntime()->getBailoutTail()->raw();
197 rfe->bailoutInfo = bailoutInfo;
198 } else {
199 // Bailout failed. If there was a fatal error, clear the
200 // exception to turn this into an uncatchable error. If the
201 // overrecursion check failed, continue popping all inline
202 // frames and have the caller report an overrecursion error.
203 MOZ_ASSERT(!bailoutInfo);
205 if (!excInfo.propagatingIonExceptionForDebugMode())
206 cx->clearPendingException();
208 if (retval == BAILOUT_RETURN_OVERRECURSED)
209 *overrecursed = true;
210 else
211 MOZ_ASSERT(retval == BAILOUT_RETURN_FATAL_ERROR);
212 }
214 return retval;
215 }
217 // Initialize the decl env Object, call object, and any arguments obj of the current frame.
218 bool
219 jit::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
220 {
221 if (fp.isFunctionFrame() &&
222 fp.fun()->isHeavyweight() &&
223 !fp.hasCallObj())
224 {
225 return fp.initFunctionScopeObjects(cx);
226 }
227 return true;
228 }
230 bool
231 jit::CheckFrequentBailouts(JSContext *cx, JSScript *script)
232 {
233 if (script->hasIonScript()) {
234 // Invalidate if this script keeps bailing out without invalidation. Next time
235 // we compile this script LICM will be disabled.
236 IonScript *ionScript = script->ionScript();
238 if (ionScript->numBailouts() >= js_JitOptions.frequentBailoutThreshold &&
239 !script->hadFrequentBailouts())
240 {
241 script->setHadFrequentBailouts();
243 IonSpew(IonSpew_Invalidate, "Invalidating due to too many bailouts");
245 if (!Invalidate(cx, script))
246 return false;
247 }
248 }
250 return true;
251 }