js/src/jsanalyze.h

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:ffab974a9dc1
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/. */
6
7 /* Definitions for javascript analysis. */
8
9 #ifndef jsanalyze_h
10 #define jsanalyze_h
11
12 #include "jscompartment.h"
13
14 namespace js {
15 namespace analyze {
16
17 class Bytecode;
18 struct LifetimeVariable;
19 class SlotValue;
20 class SSAValue;
21 struct SSAValueInfo;
22 class SSAUseChain;
23
24 // Common representation of slots between ScriptAnalysis, TypeScript, and in the
25 // case of TotalSlots, Ion.
26 static inline uint32_t ThisSlot() {
27 return 0;
28 }
29 static inline uint32_t ArgSlot(uint32_t arg) {
30 return 1 + arg;
31 }
32 static inline uint32_t LocalSlot(JSScript *script, uint32_t local) {
33 return 1 + local +
34 (script->functionNonDelazifying() ? script->functionNonDelazifying()->nargs() : 0);
35 }
36 static inline uint32_t TotalSlots(JSScript *script) {
37 return LocalSlot(script, 0) + script->nfixed();
38 }
39
40 // Analysis information about a script. FIXME: At this point, the entire
41 // purpose of this class is to compute JSScript::needsArgsObj, and to support
42 // isReachable() in order for jsinfer.cpp:FindPreviousInnerInitializer to get
43 // the previous opcode. For that purpose, it is completely overkill.
44 class ScriptAnalysis
45 {
46 friend class Bytecode;
47
48 JSScript *script_;
49
50 Bytecode **codeArray;
51
52 uint32_t numSlots;
53
54 bool *escapedSlots;
55
56 #ifdef DEBUG
57 /* Whether the compartment was in debug mode when we performed the analysis. */
58 bool originalDebugMode_: 1;
59 #endif
60
61 /* --------- Bytecode analysis --------- */
62
63 bool canTrackVars:1;
64 bool argumentsContentsObserved_:1;
65
66 /* --------- Lifetime analysis --------- */
67
68 LifetimeVariable *lifetimes;
69
70 public:
71 ScriptAnalysis(JSScript *script) {
72 mozilla::PodZero(this);
73 this->script_ = script;
74 #ifdef DEBUG
75 this->originalDebugMode_ = script_->compartment()->debugMode();
76 #endif
77 }
78
79 MOZ_WARN_UNUSED_RESULT
80 bool analyzeBytecode(JSContext *cx);
81
82 bool isReachable(const jsbytecode *pc) { return maybeCode(pc); }
83
84 private:
85 MOZ_WARN_UNUSED_RESULT
86 bool analyzeSSA(JSContext *cx);
87 MOZ_WARN_UNUSED_RESULT
88 bool analyzeLifetimes(JSContext *cx);
89
90 /* Accessors for bytecode information. */
91 Bytecode& getCode(uint32_t offset) {
92 JS_ASSERT(offset < script_->length());
93 JS_ASSERT(codeArray[offset]);
94 return *codeArray[offset];
95 }
96 Bytecode& getCode(const jsbytecode *pc) { return getCode(script_->pcToOffset(pc)); }
97
98 Bytecode* maybeCode(uint32_t offset) {
99 JS_ASSERT(offset < script_->length());
100 return codeArray[offset];
101 }
102 Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(script_->pcToOffset(pc)); }
103
104 inline bool jumpTarget(uint32_t offset);
105 inline bool jumpTarget(const jsbytecode *pc);
106
107 inline const SSAValue &poppedValue(uint32_t offset, uint32_t which);
108 inline const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which);
109
110 inline const SlotValue *newValues(uint32_t offset);
111 inline const SlotValue *newValues(const jsbytecode *pc);
112
113 inline bool trackUseChain(const SSAValue &v);
114
115 /*
116 * Get the use chain for an SSA value.
117 */
118 inline SSAUseChain *& useChain(const SSAValue &v);
119
120
121 /* For a JSOP_CALL* op, get the pc of the corresponding JSOP_CALL/NEW/etc. */
122 inline jsbytecode *getCallPC(jsbytecode *pc);
123
124 /* Accessors for local variable information. */
125
126 /*
127 * Escaping slots include all slots that can be accessed in ways other than
128 * through the corresponding LOCAL/ARG opcode. This includes all closed
129 * slots in the script, all slots in scripts which use eval or are in debug
130 * mode, and slots which are aliased by NAME or similar opcodes in the
131 * containing script (which does not imply the variable is closed).
132 */
133 inline bool slotEscapes(uint32_t slot);
134
135 /*
136 * Whether we distinguish different writes of this variable while doing
137 * SSA analysis. Escaping locals can be written in other scripts, and the
138 * presence of NAME opcodes which could alias local variables or arguments
139 * keeps us from tracking variable values at each point.
140 */
141 inline bool trackSlot(uint32_t slot);
142
143 inline const LifetimeVariable & liveness(uint32_t slot);
144
145 void printSSA(JSContext *cx);
146 void printTypes(JSContext *cx);
147
148 /* Bytecode helpers */
149 MOZ_WARN_UNUSED_RESULT
150 inline bool addJump(JSContext *cx, unsigned offset,
151 unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop,
152 unsigned stackDepth);
153
154 /* Lifetime helpers */
155 MOZ_WARN_UNUSED_RESULT
156 inline bool addVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
157 LifetimeVariable **&saved, unsigned &savedCount);
158 MOZ_WARN_UNUSED_RESULT
159 inline bool killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
160 LifetimeVariable **&saved, unsigned &savedCount);
161 MOZ_WARN_UNUSED_RESULT
162 inline bool extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
163
164 inline void ensureVariable(LifetimeVariable &var, unsigned until);
165
166 /* SSA helpers */
167 MOZ_WARN_UNUSED_RESULT
168 bool makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv);
169 MOZ_WARN_UNUSED_RESULT
170 bool insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v);
171 MOZ_WARN_UNUSED_RESULT
172 bool mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv);
173 MOZ_WARN_UNUSED_RESULT
174 bool checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot,
175 Vector<SlotValue> *pending);
176 MOZ_WARN_UNUSED_RESULT
177 bool checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets,
178 SSAValueInfo *values, uint32_t stackDepth);
179 MOZ_WARN_UNUSED_RESULT
180 bool checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
181 Vector<uint32_t> &exceptionTargets);
182 MOZ_WARN_UNUSED_RESULT
183 bool mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
184 const Vector<uint32_t> &branchTargets, uint32_t currentOffset);
185 MOZ_WARN_UNUSED_RESULT
186 bool mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
187 const Vector<uint32_t> &exceptionTargets);
188 MOZ_WARN_UNUSED_RESULT
189 bool mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
190 const Vector<uint32_t> &exceptionTargets);
191 MOZ_WARN_UNUSED_RESULT
192 bool freezeNewValues(JSContext *cx, uint32_t offset);
193
194 typedef Vector<SSAValue, 16> SeenVector;
195 bool needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v);
196 bool needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use);
197 bool needsArgsObj(JSContext *cx);
198
199 public:
200 #ifdef DEBUG
201 void assertMatchingDebugMode();
202 void assertMatchingStackDepthAtOffset(uint32_t offset, uint32_t stackDepth);
203 #else
204 void assertMatchingDebugMode() { }
205 void assertMatchingStackDepthAtOffset(uint32_t offset, uint32_t stackDepth) { }
206 #endif
207 };
208
209 #ifdef DEBUG
210 void PrintBytecode(JSContext *cx, HandleScript script, jsbytecode *pc);
211 #endif
212
213 } /* namespace analyze */
214 } /* namespace js */
215
216 #endif /* jsanalyze_h */

mercurial