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/BytecodeAnalysis.h"
9 #include "jsopcode.h"
10 #include "jit/IonSpewer.h"
11 #include "jsopcodeinlines.h"
13 using namespace js;
14 using namespace js::jit;
16 BytecodeAnalysis::BytecodeAnalysis(TempAllocator &alloc, JSScript *script)
17 : script_(script),
18 infos_(alloc),
19 usesScopeChain_(false),
20 hasTryFinally_(false),
21 hasSetArg_(false)
22 {
23 }
25 // Bytecode range containing only catch or finally code.
26 struct CatchFinallyRange
27 {
28 uint32_t start; // Inclusive.
29 uint32_t end; // Exclusive.
31 CatchFinallyRange(uint32_t start, uint32_t end)
32 : start(start), end(end)
33 {
34 JS_ASSERT(end > start);
35 }
37 bool contains(uint32_t offset) const {
38 return start <= offset && offset < end;
39 }
40 };
42 bool
43 BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn)
44 {
45 if (!infos_.growByUninitialized(script_->length()))
46 return false;
48 jsbytecode *end = script_->codeEnd();
50 // Clear all BytecodeInfo.
51 mozilla::PodZero(infos_.begin(), infos_.length());
52 infos_[0].init(/*stackDepth=*/0);
54 Vector<CatchFinallyRange, 0, IonAllocPolicy> catchFinallyRanges(alloc);
56 for (jsbytecode *pc = script_->code(); pc < end; pc += GetBytecodeLength(pc)) {
57 JSOp op = JSOp(*pc);
58 unsigned offset = script_->pcToOffset(pc);
60 IonSpew(IonSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s",
61 int(script_->pcToOffset(pc)), int(script_->length()), js_CodeName[op]);
63 // If this bytecode info has not yet been initialized, it's not reachable.
64 if (!infos_[offset].initialized)
65 continue;
68 unsigned stackDepth = infos_[offset].stackDepth;
69 #ifdef DEBUG
70 for (jsbytecode *chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++)
71 JS_ASSERT(!infos_[script_->pcToOffset(chkpc)].initialized);
72 #endif
74 unsigned nuses = GetUseCount(script_, offset);
75 unsigned ndefs = GetDefCount(script_, offset);
77 JS_ASSERT(stackDepth >= nuses);
78 stackDepth -= nuses;
79 stackDepth += ndefs;
81 // If stack depth exceeds max allowed by analysis, fail fast.
82 JS_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);
84 switch (op) {
85 case JSOP_TABLESWITCH: {
86 unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
87 jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
88 int32_t low = GET_JUMP_OFFSET(pc2);
89 pc2 += JUMP_OFFSET_LEN;
90 int32_t high = GET_JUMP_OFFSET(pc2);
91 pc2 += JUMP_OFFSET_LEN;
93 infos_[defaultOffset].init(stackDepth);
94 infos_[defaultOffset].jumpTarget = true;
96 for (int32_t i = low; i <= high; i++) {
97 unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
98 if (targetOffset != offset) {
99 infos_[targetOffset].init(stackDepth);
100 infos_[targetOffset].jumpTarget = true;
101 }
102 pc2 += JUMP_OFFSET_LEN;
103 }
104 break;
105 }
107 case JSOP_TRY: {
108 JSTryNote *tn = script_->trynotes()->vector;
109 JSTryNote *tnlimit = tn + script_->trynotes()->length;
110 for (; tn < tnlimit; tn++) {
111 unsigned startOffset = script_->mainOffset() + tn->start;
112 if (startOffset == offset + 1) {
113 unsigned catchOffset = startOffset + tn->length;
115 if (tn->kind != JSTRY_ITER) {
116 infos_[catchOffset].init(stackDepth);
117 infos_[catchOffset].jumpTarget = true;
118 }
119 }
120 }
122 // Get the pc of the last instruction in the try block. It's a JSOP_GOTO to
123 // jump over the catch/finally blocks.
124 jssrcnote *sn = GetSrcNote(gsn, script_, pc);
125 JS_ASSERT(SN_TYPE(sn) == SRC_TRY);
127 jsbytecode *endOfTry = pc + js_GetSrcNoteOffset(sn, 0);
128 JS_ASSERT(JSOp(*endOfTry) == JSOP_GOTO);
130 jsbytecode *afterTry = endOfTry + GET_JUMP_OFFSET(endOfTry);
131 JS_ASSERT(afterTry > endOfTry);
133 // Pop CatchFinallyRanges that are no longer needed.
134 while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset)
135 catchFinallyRanges.popBack();
137 CatchFinallyRange range(script_->pcToOffset(endOfTry), script_->pcToOffset(afterTry));
138 if (!catchFinallyRanges.append(range))
139 return false;
140 break;
141 }
143 case JSOP_LOOPENTRY:
144 for (size_t i = 0; i < catchFinallyRanges.length(); i++) {
145 if (catchFinallyRanges[i].contains(offset))
146 infos_[offset].loopEntryInCatchOrFinally = true;
147 }
148 break;
150 case JSOP_NAME:
151 case JSOP_BINDNAME:
152 case JSOP_SETNAME:
153 case JSOP_DELNAME:
154 case JSOP_GETALIASEDVAR:
155 case JSOP_SETALIASEDVAR:
156 case JSOP_LAMBDA:
157 case JSOP_LAMBDA_ARROW:
158 case JSOP_DEFFUN:
159 case JSOP_DEFVAR:
160 case JSOP_DEFCONST:
161 case JSOP_SETCONST:
162 usesScopeChain_ = true;
163 break;
165 case JSOP_FINALLY:
166 hasTryFinally_ = true;
167 break;
169 case JSOP_SETARG:
170 hasSetArg_ = true;
171 break;
173 default:
174 break;
175 }
177 bool jump = IsJumpOpcode(op);
178 if (jump) {
179 // Case instructions do not push the lvalue back when branching.
180 unsigned newStackDepth = stackDepth;
181 if (op == JSOP_CASE)
182 newStackDepth--;
184 unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
186 // If this is a a backedge to an un-analyzed segment, analyze from there.
187 bool jumpBack = (targetOffset < offset) && !infos_[targetOffset].initialized;
189 infos_[targetOffset].init(newStackDepth);
190 infos_[targetOffset].jumpTarget = true;
192 if (jumpBack)
193 pc = script_->offsetToPC(targetOffset);
194 }
196 // Handle any fallthrough from this opcode.
197 if (BytecodeFallsThrough(op)) {
198 jsbytecode *nextpc = pc + GetBytecodeLength(pc);
199 JS_ASSERT(nextpc < end);
200 unsigned nextOffset = script_->pcToOffset(nextpc);
202 infos_[nextOffset].init(stackDepth);
204 if (jump)
205 infos_[nextOffset].jumpFallthrough = true;
207 // Treat the fallthrough of a branch instruction as a jump target.
208 if (jump)
209 infos_[nextOffset].jumpTarget = true;
210 else
211 infos_[nextOffset].fallthrough = true;
212 }
213 }
215 return true;
216 }