|
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 #ifndef jit_CompileInfo_h |
|
8 #define jit_CompileInfo_h |
|
9 |
|
10 #include "jsfun.h" |
|
11 |
|
12 #include "jit/Registers.h" |
|
13 #include "vm/ScopeObject.h" |
|
14 |
|
15 namespace js { |
|
16 namespace jit { |
|
17 |
|
18 inline unsigned |
|
19 StartArgSlot(JSScript *script) |
|
20 { |
|
21 // Reserved slots: |
|
22 // Slot 0: Scope chain. |
|
23 // Slot 1: Return value. |
|
24 |
|
25 // When needed: |
|
26 // Slot 2: Argumentsobject. |
|
27 |
|
28 // Note: when updating this, please also update the assert in SnapshotWriter::startFrame |
|
29 return 2 + (script->argumentsHasVarBinding() ? 1 : 0); |
|
30 } |
|
31 |
|
32 inline unsigned |
|
33 CountArgSlots(JSScript *script, JSFunction *fun) |
|
34 { |
|
35 // Slot x + 0: This value. |
|
36 // Slot x + 1: Argument 1. |
|
37 // ... |
|
38 // Slot x + n: Argument n. |
|
39 |
|
40 // Note: when updating this, please also update the assert in SnapshotWriter::startFrame |
|
41 return StartArgSlot(script) + (fun ? fun->nargs() + 1 : 0); |
|
42 } |
|
43 |
|
44 // Contains information about the compilation source for IR being generated. |
|
45 class CompileInfo |
|
46 { |
|
47 public: |
|
48 CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing, |
|
49 ExecutionMode executionMode, bool scriptNeedsArgsObj) |
|
50 : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing), |
|
51 executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj) |
|
52 { |
|
53 JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY); |
|
54 |
|
55 // The function here can flow in from anywhere so look up the canonical |
|
56 // function to ensure that we do not try to embed a nursery pointer in |
|
57 // jit-code. Precisely because it can flow in from anywhere, it's not |
|
58 // guaranteed to be non-lazy. Hence, don't access its script! |
|
59 if (fun_) { |
|
60 fun_ = fun_->nonLazyScript()->functionNonDelazifying(); |
|
61 JS_ASSERT(fun_->isTenured()); |
|
62 } |
|
63 |
|
64 osrStaticScope_ = osrPc ? script->getStaticScope(osrPc) : nullptr; |
|
65 |
|
66 nimplicit_ = StartArgSlot(script) /* scope chain and argument obj */ |
|
67 + (fun ? 1 : 0); /* this */ |
|
68 nargs_ = fun ? fun->nargs() : 0; |
|
69 nfixedvars_ = script->nfixedvars(); |
|
70 nlocals_ = script->nfixed(); |
|
71 nstack_ = script->nslots() - script->nfixed(); |
|
72 nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; |
|
73 } |
|
74 |
|
75 CompileInfo(unsigned nlocals, ExecutionMode executionMode) |
|
76 : script_(nullptr), fun_(nullptr), osrPc_(nullptr), osrStaticScope_(nullptr), |
|
77 constructing_(false), executionMode_(executionMode), scriptNeedsArgsObj_(false) |
|
78 { |
|
79 nimplicit_ = 0; |
|
80 nargs_ = 0; |
|
81 nfixedvars_ = 0; |
|
82 nlocals_ = nlocals; |
|
83 nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */ |
|
84 nslots_ = nlocals_ + nstack_; |
|
85 } |
|
86 |
|
87 JSScript *script() const { |
|
88 return script_; |
|
89 } |
|
90 JSFunction *funMaybeLazy() const { |
|
91 return fun_; |
|
92 } |
|
93 bool constructing() const { |
|
94 return constructing_; |
|
95 } |
|
96 jsbytecode *osrPc() { |
|
97 return osrPc_; |
|
98 } |
|
99 NestedScopeObject *osrStaticScope() const { |
|
100 return osrStaticScope_; |
|
101 } |
|
102 |
|
103 bool hasOsrAt(jsbytecode *pc) { |
|
104 JS_ASSERT(JSOp(*pc) == JSOP_LOOPENTRY); |
|
105 return pc == osrPc(); |
|
106 } |
|
107 |
|
108 jsbytecode *startPC() const { |
|
109 return script_->code(); |
|
110 } |
|
111 jsbytecode *limitPC() const { |
|
112 return script_->codeEnd(); |
|
113 } |
|
114 |
|
115 const char *filename() const { |
|
116 return script_->filename(); |
|
117 } |
|
118 |
|
119 unsigned lineno() const { |
|
120 return script_->lineno(); |
|
121 } |
|
122 unsigned lineno(jsbytecode *pc) const { |
|
123 return PCToLineNumber(script_, pc); |
|
124 } |
|
125 |
|
126 // Script accessors based on PC. |
|
127 |
|
128 JSAtom *getAtom(jsbytecode *pc) const { |
|
129 return script_->getAtom(GET_UINT32_INDEX(pc)); |
|
130 } |
|
131 |
|
132 PropertyName *getName(jsbytecode *pc) const { |
|
133 return script_->getName(GET_UINT32_INDEX(pc)); |
|
134 } |
|
135 |
|
136 inline RegExpObject *getRegExp(jsbytecode *pc) const; |
|
137 |
|
138 JSObject *getObject(jsbytecode *pc) const { |
|
139 return script_->getObject(GET_UINT32_INDEX(pc)); |
|
140 } |
|
141 |
|
142 inline JSFunction *getFunction(jsbytecode *pc) const; |
|
143 |
|
144 const Value &getConst(jsbytecode *pc) const { |
|
145 return script_->getConst(GET_UINT32_INDEX(pc)); |
|
146 } |
|
147 |
|
148 jssrcnote *getNote(GSNCache &gsn, jsbytecode *pc) const { |
|
149 return GetSrcNote(gsn, script(), pc); |
|
150 } |
|
151 |
|
152 // Total number of slots: args, locals, and stack. |
|
153 unsigned nslots() const { |
|
154 return nslots_; |
|
155 } |
|
156 |
|
157 // Number of slots needed for Scope chain, return value, |
|
158 // maybe argumentsobject and this value. |
|
159 unsigned nimplicit() const { |
|
160 return nimplicit_; |
|
161 } |
|
162 // Number of arguments (without counting this value). |
|
163 unsigned nargs() const { |
|
164 return nargs_; |
|
165 } |
|
166 // Number of slots needed for "fixed vars". Note that this is only non-zero |
|
167 // for function code. |
|
168 unsigned nfixedvars() const { |
|
169 return nfixedvars_; |
|
170 } |
|
171 // Number of slots needed for all local variables. This includes "fixed |
|
172 // vars" (see above) and also block-scoped locals. |
|
173 unsigned nlocals() const { |
|
174 return nlocals_; |
|
175 } |
|
176 unsigned ninvoke() const { |
|
177 return nslots_ - nstack_; |
|
178 } |
|
179 |
|
180 uint32_t scopeChainSlot() const { |
|
181 JS_ASSERT(script()); |
|
182 return 0; |
|
183 } |
|
184 uint32_t returnValueSlot() const { |
|
185 JS_ASSERT(script()); |
|
186 return 1; |
|
187 } |
|
188 uint32_t argsObjSlot() const { |
|
189 JS_ASSERT(hasArguments()); |
|
190 return 2; |
|
191 } |
|
192 uint32_t thisSlot() const { |
|
193 JS_ASSERT(funMaybeLazy()); |
|
194 JS_ASSERT(nimplicit_ > 0); |
|
195 return nimplicit_ - 1; |
|
196 } |
|
197 uint32_t firstArgSlot() const { |
|
198 return nimplicit_; |
|
199 } |
|
200 uint32_t argSlotUnchecked(uint32_t i) const { |
|
201 // During initialization, some routines need to get at arg |
|
202 // slots regardless of how regular argument access is done. |
|
203 JS_ASSERT(i < nargs_); |
|
204 return nimplicit_ + i; |
|
205 } |
|
206 uint32_t argSlot(uint32_t i) const { |
|
207 // This should only be accessed when compiling functions for |
|
208 // which argument accesses don't need to go through the |
|
209 // argument object. |
|
210 JS_ASSERT(!argsObjAliasesFormals()); |
|
211 return argSlotUnchecked(i); |
|
212 } |
|
213 uint32_t firstLocalSlot() const { |
|
214 return nimplicit_ + nargs_; |
|
215 } |
|
216 uint32_t localSlot(uint32_t i) const { |
|
217 return firstLocalSlot() + i; |
|
218 } |
|
219 uint32_t firstStackSlot() const { |
|
220 return firstLocalSlot() + nlocals(); |
|
221 } |
|
222 uint32_t stackSlot(uint32_t i) const { |
|
223 return firstStackSlot() + i; |
|
224 } |
|
225 |
|
226 uint32_t startArgSlot() const { |
|
227 JS_ASSERT(script()); |
|
228 return StartArgSlot(script()); |
|
229 } |
|
230 uint32_t endArgSlot() const { |
|
231 JS_ASSERT(script()); |
|
232 return CountArgSlots(script(), funMaybeLazy()); |
|
233 } |
|
234 |
|
235 uint32_t totalSlots() const { |
|
236 JS_ASSERT(script() && funMaybeLazy()); |
|
237 return nimplicit() + nargs() + nlocals(); |
|
238 } |
|
239 |
|
240 bool isSlotAliased(uint32_t index, NestedScopeObject *staticScope) const { |
|
241 JS_ASSERT(index >= startArgSlot()); |
|
242 |
|
243 if (funMaybeLazy() && index == thisSlot()) |
|
244 return false; |
|
245 |
|
246 uint32_t arg = index - firstArgSlot(); |
|
247 if (arg < nargs()) |
|
248 return script()->formalIsAliased(arg); |
|
249 |
|
250 uint32_t local = index - firstLocalSlot(); |
|
251 if (local < nlocals()) { |
|
252 // First, check if this local is a var. |
|
253 if (local < nfixedvars()) |
|
254 return script()->varIsAliased(local); |
|
255 |
|
256 // Otherwise, it might be part of a block scope. |
|
257 for (; staticScope; staticScope = staticScope->enclosingNestedScope()) { |
|
258 if (!staticScope->is<StaticBlockObject>()) |
|
259 continue; |
|
260 StaticBlockObject &blockObj = staticScope->as<StaticBlockObject>(); |
|
261 if (blockObj.localOffset() < local) { |
|
262 if (local - blockObj.localOffset() < blockObj.numVariables()) |
|
263 return blockObj.isAliased(local - blockObj.localOffset()); |
|
264 return false; |
|
265 } |
|
266 } |
|
267 |
|
268 // In this static scope, this var is dead. |
|
269 return false; |
|
270 } |
|
271 |
|
272 JS_ASSERT(index >= firstStackSlot()); |
|
273 return false; |
|
274 } |
|
275 |
|
276 bool isSlotAliasedAtEntry(uint32_t index) const { |
|
277 return isSlotAliased(index, nullptr); |
|
278 } |
|
279 bool isSlotAliasedAtOsr(uint32_t index) const { |
|
280 return isSlotAliased(index, osrStaticScope()); |
|
281 } |
|
282 |
|
283 bool hasArguments() const { |
|
284 return script()->argumentsHasVarBinding(); |
|
285 } |
|
286 bool argumentsAliasesFormals() const { |
|
287 return script()->argumentsAliasesFormals(); |
|
288 } |
|
289 bool needsArgsObj() const { |
|
290 return scriptNeedsArgsObj_; |
|
291 } |
|
292 bool argsObjAliasesFormals() const { |
|
293 return scriptNeedsArgsObj_ && !script()->strict(); |
|
294 } |
|
295 |
|
296 ExecutionMode executionMode() const { |
|
297 return executionMode_; |
|
298 } |
|
299 |
|
300 bool executionModeIsAnalysis() const { |
|
301 return executionMode_ == DefinitePropertiesAnalysis || executionMode_ == ArgumentsUsageAnalysis; |
|
302 } |
|
303 |
|
304 bool isParallelExecution() const { |
|
305 return executionMode_ == ParallelExecution; |
|
306 } |
|
307 |
|
308 bool canOptimizeOutSlot(uint32_t i) const { |
|
309 if (script()->strict()) |
|
310 return true; |
|
311 |
|
312 // Function.arguments can be used to access all arguments in |
|
313 // non-strict scripts, so we can't optimize out any arguments. |
|
314 return !(firstArgSlot() <= i && i - firstArgSlot() < nargs()); |
|
315 } |
|
316 |
|
317 private: |
|
318 unsigned nimplicit_; |
|
319 unsigned nargs_; |
|
320 unsigned nfixedvars_; |
|
321 unsigned nlocals_; |
|
322 unsigned nstack_; |
|
323 unsigned nslots_; |
|
324 JSScript *script_; |
|
325 JSFunction *fun_; |
|
326 jsbytecode *osrPc_; |
|
327 NestedScopeObject *osrStaticScope_; |
|
328 bool constructing_; |
|
329 ExecutionMode executionMode_; |
|
330 |
|
331 // Whether a script needs an arguments object is unstable over compilation |
|
332 // since the arguments optimization could be marked as failed on the main |
|
333 // thread, so cache a value here and use it throughout for consistency. |
|
334 bool scriptNeedsArgsObj_; |
|
335 }; |
|
336 |
|
337 } // namespace jit |
|
338 } // namespace js |
|
339 |
|
340 #endif /* jit_CompileInfo_h */ |