1 : /* -*- Mode: c++; c-basic-offset: 4; tab-width: 40; indent-tabs-mode: nil -*- */
2 : /* vim: set ts=40 sw=4 et tw=99: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is the Mozilla SpiderMonkey bytecode analysis
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Mozilla Foundation
20 : * Portions created by the Initial Developer are Copyright (C) 2010
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /* Definitions for javascript analysis. */
40 :
41 : #ifndef jsanalyze_h___
42 : #define jsanalyze_h___
43 :
44 : #include "jsautooplen.h"
45 : #include "jscompartment.h"
46 : #include "jscntxt.h"
47 : #include "jsinfer.h"
48 : #include "jsscript.h"
49 :
50 : #include "ds/LifoAlloc.h"
51 : #include "js/TemplateLib.h"
52 :
53 : struct JSScript;
54 :
55 : /* Forward declaration of downstream register allocations computed for join points. */
56 : namespace js { namespace mjit { struct RegisterAllocation; } }
57 :
58 : namespace js {
59 : namespace analyze {
60 :
61 : /*
62 : * There are three analyses we can perform on a JSScript, outlined below.
63 : * The results of all three are stored in ScriptAnalysis, but the analyses
64 : * themselves can be performed separately. Along with type inference results,
65 : * per-script analysis results are tied to the per-compartment analysis pool
66 : * and are freed on every garbage collection.
67 : *
68 : * - Basic bytecode analysis. For each bytecode, determine the stack depth at
69 : * that point and control flow information needed for compilation. Also does
70 : * a defined-variables analysis to look for local variables which have uses
71 : * before definitions.
72 : *
73 : * - Lifetime analysis. Makes a backwards pass over the script to approximate
74 : * the regions where each variable is live, avoiding a full fixpointing
75 : * live-variables pass. This is based on the algorithm described in:
76 : *
77 : * "Quality and Speed in Linear-scan Register Allocation"
78 : * Traub et. al.
79 : * PLDI, 1998
80 : *
81 : * - SSA analysis of the script's variables and stack values. For each stack
82 : * value popped and non-escaping local variable or argument read, determines
83 : * which push(es) or write(s) produced that value.
84 : *
85 : * Intermediate type inference results are additionally stored here. The above
86 : * analyses are independent from type inference.
87 : */
88 :
89 : /* Information about a bytecode instruction. */
90 : class Bytecode
91 : {
92 : friend class ScriptAnalysis;
93 :
94 : public:
95 9170109 : Bytecode() { PodZero(this); }
96 :
97 : /* --------- Bytecode analysis --------- */
98 :
99 : /* Whether there are any incoming jumps to this instruction. */
100 : bool jumpTarget : 1;
101 :
102 : /* Whether there is fallthrough to this instruction from a non-branching instruction. */
103 : bool fallthrough : 1;
104 :
105 : /* Whether this instruction is the fall through point of a conditional jump. */
106 : bool jumpFallthrough : 1;
107 :
108 : /* Whether this instruction can be branched to from a switch statement. Implies jumpTarget. */
109 : bool switchTarget : 1;
110 :
111 : /*
112 : * Whether this instruction must always execute, unless the script throws
113 : * an exception which it does not later catch.
114 : */
115 : bool unconditional : 1;
116 :
117 : /* Whether this instruction has been analyzed to get its output defines and stack. */
118 : bool analyzed : 1;
119 :
120 : /* Whether this is a catch/finally entry point. */
121 : bool exceptionEntry : 1;
122 :
123 : /* Whether this is in a try block. */
124 : bool inTryBlock : 1;
125 :
126 : /* Whether this is in a loop. */
127 : bool inLoop : 1;
128 :
129 : /* Method JIT safe point. */
130 : bool safePoint : 1;
131 :
132 : /*
133 : * Side effects of this bytecode were not determined by type inference.
134 : * Either a property set with unknown lvalue, or call with unknown callee.
135 : */
136 : bool monitoredTypes : 1;
137 :
138 : /* Call whose result should be monitored. */
139 : bool monitoredTypesReturn : 1;
140 :
141 : /*
142 : * Dynamically observed state about the execution of this opcode. These are
143 : * hints about the script for use during compilation.
144 : */
145 : bool arrayWriteHole: 1; /* SETELEM which has written to an array hole. */
146 : bool getStringElement:1; /* GETELEM which has accessed string properties. */
147 : bool accessGetter: 1; /* Property read on a shape with a getter hook. */
148 :
149 : /* Stack depth before this opcode. */
150 : uint32_t stackDepth;
151 :
152 : private:
153 :
154 : union {
155 : /* If this is a JOF_TYPESET opcode, index into the observed types for the op. */
156 : types::TypeSet *observedTypes;
157 :
158 : /* If this is a loop head (TRACE or NOTRACE), information about the loop. */
159 : LoopAnalysis *loop;
160 : };
161 :
162 : /* --------- Lifetime analysis --------- */
163 :
164 : /* Any allocation computed downstream for this bytecode. */
165 : mjit::RegisterAllocation *allocation;
166 :
167 : /* --------- SSA analysis --------- */
168 :
169 : /* Generated location of each value popped by this bytecode. */
170 : SSAValue *poppedValues;
171 :
172 : /* Points where values pushed or written by this bytecode are popped. */
173 : SSAUseChain **pushedUses;
174 :
175 : union {
176 : /*
177 : * If this is a join point (implies jumpTarget), any slots at this
178 : * point which can have a different values than at the immediate
179 : * predecessor in the bytecode. Array is terminated by an entry with
180 : * a zero slot.
181 : */
182 : SlotValue *newValues;
183 :
184 : /*
185 : * Vector used during SSA analysis to store values in need of merging
186 : * at this point. If this has incoming forward jumps and we have not
187 : * yet reached this point, stores values for entries on the stack and
188 : * for variables which have changed since the branch. If this is a loop
189 : * head and we haven't reached the back edge yet, stores loop phi nodes
190 : * for variables and entries live at the head of the loop.
191 : */
192 : Vector<SlotValue> *pendingValues;
193 : };
194 :
195 : /* --------- Type inference --------- */
196 :
197 : /* Types for all values pushed by this bytecode. */
198 : types::TypeSet *pushedTypes;
199 :
200 : /* Any type barriers in place at this bytecode. */
201 : types::TypeBarrier *typeBarriers;
202 : };
203 :
204 : static inline unsigned
205 41761257 : GetDefCount(JSScript *script, unsigned offset)
206 : {
207 41761257 : JS_ASSERT(offset < script->length);
208 41761257 : jsbytecode *pc = script->code + offset;
209 :
210 : /*
211 : * Add an extra pushed value for OR/AND opcodes, so that they are included
212 : * in the pushed array of stack values for type inference.
213 : */
214 41761257 : switch (JSOp(*pc)) {
215 : case JSOP_OR:
216 : case JSOP_AND:
217 23346 : return 1;
218 : case JSOP_FILTER:
219 136 : return 2;
220 : case JSOP_PICK:
221 : /*
222 : * Pick pops and pushes how deep it looks in the stack + 1
223 : * items. i.e. if the stack were |a b[2] c[1] d[0]|, pick 2
224 : * would pop b, c, and d to rearrange the stack to |a c[0]
225 : * d[1] b[2]|.
226 : */
227 65509 : return (pc[1] + 1);
228 : default:
229 41672266 : return StackDefs(script, pc);
230 : }
231 : }
232 :
233 : static inline unsigned
234 16050989 : GetUseCount(JSScript *script, unsigned offset)
235 : {
236 16050989 : JS_ASSERT(offset < script->length);
237 16050989 : jsbytecode *pc = script->code + offset;
238 :
239 16050989 : if (JSOp(*pc) == JSOP_PICK)
240 29648 : return (pc[1] + 1);
241 16021341 : if (js_CodeSpec[*pc].nuses == -1)
242 958118 : return StackUses(script, pc);
243 15063223 : return js_CodeSpec[*pc].nuses;
244 : }
245 :
246 : /*
247 : * For opcodes which assign to a local variable or argument, track an extra def
248 : * during SSA analysis for the value's use chain and assigned type.
249 : */
250 : static inline bool
251 24111911 : ExtendedDef(jsbytecode *pc)
252 : {
253 24111911 : switch ((JSOp)*pc) {
254 : case JSOP_SETARG:
255 : case JSOP_INCARG:
256 : case JSOP_DECARG:
257 : case JSOP_ARGINC:
258 : case JSOP_ARGDEC:
259 : case JSOP_SETLOCAL:
260 : case JSOP_INCLOCAL:
261 : case JSOP_DECLOCAL:
262 : case JSOP_LOCALINC:
263 : case JSOP_LOCALDEC:
264 1201037 : return true;
265 : default:
266 22910874 : return false;
267 : }
268 : }
269 :
270 : /* Return whether op bytecodes do not fallthrough (they may do a jump). */
271 : static inline bool
272 9173327 : BytecodeNoFallThrough(JSOp op)
273 : {
274 9173327 : switch (op) {
275 : case JSOP_GOTO:
276 : case JSOP_DEFAULT:
277 : case JSOP_RETURN:
278 : case JSOP_STOP:
279 : case JSOP_RETRVAL:
280 : case JSOP_THROW:
281 : case JSOP_TABLESWITCH:
282 : case JSOP_LOOKUPSWITCH:
283 : case JSOP_FILTER:
284 362949 : return true;
285 : case JSOP_GOSUB:
286 : /* These fall through indirectly, after executing a 'finally'. */
287 937 : return false;
288 : default:
289 8809441 : return false;
290 : }
291 : }
292 :
293 : /*
294 : * For opcodes which access local variables or arguments, we track an extra
295 : * use during SSA analysis for the value of the variable before/after the op.
296 : */
297 : static inline bool
298 4736006 : ExtendedUse(jsbytecode *pc)
299 : {
300 4736006 : if (ExtendedDef(pc))
301 261647 : return true;
302 4474359 : switch ((JSOp)*pc) {
303 : case JSOP_GETARG:
304 : case JSOP_CALLARG:
305 : case JSOP_GETLOCAL:
306 : case JSOP_CALLLOCAL:
307 160142 : return true;
308 : default:
309 4314217 : return false;
310 : }
311 : }
312 :
313 : static inline JSOp
314 136 : ReverseCompareOp(JSOp op)
315 : {
316 136 : switch (op) {
317 : case JSOP_GT:
318 68 : return JSOP_LT;
319 : case JSOP_GE:
320 32 : return JSOP_LE;
321 : case JSOP_LT:
322 24 : return JSOP_GT;
323 : case JSOP_LE:
324 12 : return JSOP_GE;
325 : default:
326 0 : JS_NOT_REACHED("unrecognized op");
327 : return op;
328 : }
329 : }
330 :
331 : static inline unsigned
332 278430 : FollowBranch(JSContext *cx, JSScript *script, unsigned offset)
333 : {
334 : /*
335 : * Get the target offset of a branch. For GOTO opcodes implementing
336 : * 'continue' statements, short circuit any artificial backwards jump
337 : * inserted by the emitter.
338 : */
339 278430 : jsbytecode *pc = script->code + offset;
340 278430 : unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
341 278430 : if (targetOffset < offset) {
342 22718 : jsbytecode *target = script->code + targetOffset;
343 22718 : JSOp nop = JSOp(*target);
344 22718 : if (nop == JSOP_GOTO)
345 87 : return targetOffset + GET_JUMP_OFFSET(target);
346 : }
347 278343 : return targetOffset;
348 : }
349 :
350 : /* Common representation of slots throughout analyses and the compiler. */
351 235507 : static inline uint32_t CalleeSlot() {
352 235507 : return 0;
353 : }
354 29467035 : static inline uint32_t ThisSlot() {
355 29467035 : return 1;
356 : }
357 45887032 : static inline uint32_t ArgSlot(uint32_t arg) {
358 45887032 : return 2 + arg;
359 : }
360 4848574 : static inline uint32_t LocalSlot(JSScript *script, uint32_t local) {
361 4848574 : return 2 + (script->function() ? script->function()->nargs : 0) + local;
362 : }
363 2246841 : static inline uint32_t TotalSlots(JSScript *script) {
364 2246841 : return LocalSlot(script, 0) + script->nfixed;
365 : }
366 :
367 51530 : static inline uint32_t StackSlot(JSScript *script, uint32_t index) {
368 51530 : return TotalSlots(script) + index;
369 : }
370 :
371 1497247 : static inline uint32_t GetBytecodeSlot(JSScript *script, jsbytecode *pc)
372 : {
373 1497247 : switch (JSOp(*pc)) {
374 :
375 : case JSOP_GETARG:
376 : case JSOP_CALLARG:
377 : case JSOP_SETARG:
378 : case JSOP_INCARG:
379 : case JSOP_DECARG:
380 : case JSOP_ARGINC:
381 : case JSOP_ARGDEC:
382 178748 : return ArgSlot(GET_SLOTNO(pc));
383 :
384 : case JSOP_GETLOCAL:
385 : case JSOP_CALLLOCAL:
386 : case JSOP_SETLOCAL:
387 : case JSOP_INCLOCAL:
388 : case JSOP_DECLOCAL:
389 : case JSOP_LOCALINC:
390 : case JSOP_LOCALDEC:
391 1296797 : return LocalSlot(script, GET_SLOTNO(pc));
392 :
393 : case JSOP_THIS:
394 21702 : return ThisSlot();
395 :
396 : default:
397 0 : JS_NOT_REACHED("Bad slot opcode");
398 : return 0;
399 : }
400 : }
401 :
402 : /* Slot opcodes which update SSA information. */
403 : static inline bool
404 4081349 : BytecodeUpdatesSlot(JSOp op)
405 : {
406 4081349 : switch (op) {
407 : case JSOP_SETARG:
408 : case JSOP_SETLOCAL:
409 : case JSOP_INCARG:
410 : case JSOP_DECARG:
411 : case JSOP_ARGINC:
412 : case JSOP_ARGDEC:
413 : case JSOP_INCLOCAL:
414 : case JSOP_DECLOCAL:
415 : case JSOP_LOCALINC:
416 : case JSOP_LOCALDEC:
417 314764 : return true;
418 : default:
419 3766585 : return false;
420 : }
421 : }
422 :
423 : static inline int32_t
424 15620 : GetBytecodeInteger(jsbytecode *pc)
425 : {
426 15620 : switch (JSOp(*pc)) {
427 693 : case JSOP_ZERO: return 0;
428 248 : case JSOP_ONE: return 1;
429 2945 : case JSOP_UINT16: return GET_UINT16(pc);
430 24 : case JSOP_UINT24: return GET_UINT24(pc);
431 11700 : case JSOP_INT8: return GET_INT8(pc);
432 10 : case JSOP_INT32: return GET_INT32(pc);
433 : default:
434 0 : JS_NOT_REACHED("Bad op");
435 : return 0;
436 : }
437 : }
438 :
439 : /*
440 : * Information about the lifetime of a local or argument. These form a linked
441 : * list describing successive intervals in the program where the variable's
442 : * value may be live. At points in the script not in one of these segments
443 : * (points in a 'lifetime hole'), the variable is dead and registers containing
444 : * its type/payload can be discarded without needing to be synced.
445 : */
446 : struct Lifetime
447 : {
448 : /*
449 : * Start and end offsets of this lifetime. The variable is live at the
450 : * beginning of every bytecode in this (inclusive) range.
451 : */
452 : uint32_t start;
453 : uint32_t end;
454 :
455 : /*
456 : * In a loop body, endpoint to extend this lifetime with if the variable is
457 : * live in the next iteration.
458 : */
459 : uint32_t savedEnd;
460 :
461 : /*
462 : * This is an artificial segment extending the lifetime of this variable
463 : * when it is live at the head of the loop. It will not be used until the
464 : * next iteration.
465 : */
466 : bool loopTail;
467 :
468 : /*
469 : * The start of this lifetime is a bytecode writing the variable. Each
470 : * write to a variable is associated with a lifetime.
471 : */
472 : bool write;
473 :
474 : /* Next lifetime. The variable is dead from this->end to next->start. */
475 : Lifetime *next;
476 :
477 62271 : Lifetime(uint32_t offset, uint32_t savedEnd, Lifetime *next)
478 : : start(offset), end(offset), savedEnd(savedEnd),
479 62271 : loopTail(false), write(false), next(next)
480 62271 : {}
481 : };
482 :
483 : /* Basic information for a loop. */
484 : class LoopAnalysis
485 : {
486 : public:
487 : /* Any loop this one is nested in. */
488 : LoopAnalysis *parent;
489 :
490 : /* Offset of the head of the loop. */
491 : uint32_t head;
492 :
493 : /*
494 : * Offset of the unique jump going to the head of the loop. The code
495 : * between the head and the backedge forms the loop body.
496 : */
497 : uint32_t backedge;
498 :
499 : /* Target offset of the initial jump or fallthrough into the loop. */
500 : uint32_t entry;
501 :
502 : /*
503 : * Start of the last basic block in the loop, excluding the initial jump to
504 : * entry. All code between lastBlock and the backedge runs in every
505 : * iteration, and if entry >= lastBlock all code between entry and the
506 : * backedge runs when the loop is initially entered.
507 : */
508 : uint32_t lastBlock;
509 :
510 : /*
511 : * This loop contains safe points in its body which the interpreter might
512 : * join at directly.
513 : */
514 : bool hasSafePoints;
515 :
516 : /* This loop has calls or inner loops. */
517 : bool hasCallsLoops;
518 : };
519 :
520 : /* Current lifetime information for a variable. */
521 : struct LifetimeVariable
522 : {
523 : /* If the variable is currently live, the lifetime segment. */
524 : Lifetime *lifetime;
525 :
526 : /* If the variable is currently dead, the next live segment. */
527 : Lifetime *saved;
528 :
529 : /* Jump preceding the basic block which killed this variable. */
530 : uint32_t savedEnd : 31;
531 :
532 : /* If the variable needs to be kept alive until lifetime->start. */
533 : bool ensured : 1;
534 :
535 : /* Whether this variable is live at offset. */
536 205883 : Lifetime * live(uint32_t offset) const {
537 205883 : if (lifetime && lifetime->end >= offset)
538 18692 : return lifetime;
539 187191 : Lifetime *segment = lifetime ? lifetime : saved;
540 995420 : while (segment && segment->start <= offset) {
541 724197 : if (segment->end >= offset)
542 103159 : return segment;
543 621038 : segment = segment->next;
544 : }
545 84032 : return NULL;
546 : }
547 :
548 : /*
549 : * Get the offset of the first write to the variable in an inclusive range,
550 : * UINT32_MAX if the variable is not written in the range.
551 : */
552 33843 : uint32_t firstWrite(uint32_t start, uint32_t end) const {
553 33843 : Lifetime *segment = lifetime ? lifetime : saved;
554 216304 : while (segment && segment->start <= end) {
555 155472 : if (segment->start >= start && segment->write)
556 6854 : return segment->start;
557 148618 : segment = segment->next;
558 : }
559 26989 : return UINT32_MAX;
560 : }
561 23874 : uint32_t firstWrite(LoopAnalysis *loop) const {
562 23874 : return firstWrite(loop->head, loop->backedge);
563 : }
564 :
565 : /* Return true if the variable cannot decrease during the body of a loop. */
566 734 : bool nonDecreasing(JSScript *script, LoopAnalysis *loop) const {
567 734 : Lifetime *segment = lifetime ? lifetime : saved;
568 4830 : while (segment && segment->start <= loop->backedge) {
569 3420 : if (segment->start >= loop->head && segment->write) {
570 734 : switch (JSOp(script->code[segment->start])) {
571 : case JSOP_INCLOCAL:
572 : case JSOP_LOCALINC:
573 : case JSOP_INCARG:
574 : case JSOP_ARGINC:
575 : break;
576 : default:
577 58 : return false;
578 : }
579 : }
580 3362 : segment = segment->next;
581 : }
582 676 : return true;
583 : }
584 :
585 : /*
586 : * If the variable is only written once in the body of a loop, offset of
587 : * that write. UINT32_MAX otherwise.
588 : */
589 56243 : uint32_t onlyWrite(LoopAnalysis *loop) const {
590 56243 : uint32_t offset = UINT32_MAX;
591 56243 : Lifetime *segment = lifetime ? lifetime : saved;
592 301129 : while (segment && segment->start <= loop->backedge) {
593 190196 : if (segment->start >= loop->head && segment->write) {
594 20258 : if (offset != UINT32_MAX)
595 1553 : return UINT32_MAX;
596 18705 : offset = segment->start;
597 : }
598 188643 : segment = segment->next;
599 : }
600 54690 : return offset;
601 : }
602 :
603 : #ifdef DEBUG
604 : void print() const;
605 : #endif
606 : };
607 :
608 : struct SSAPhiNode;
609 :
610 : /*
611 : * Representation of values on stack or in slots at each point in the script.
612 : * Values are independent from the bytecode position, and mean the same thing
613 : * everywhere in the script. SSA values are immutable, except for contents of
614 : * the values and types in an SSAPhiNode.
615 : */
616 : class SSAValue
617 : {
618 : friend class ScriptAnalysis;
619 :
620 : public:
621 : enum Kind {
622 : EMPTY = 0, /* Invalid entry. */
623 : PUSHED = 1, /* Value pushed by some bytecode. */
624 : VAR = 2, /* Initial or written value to some argument or local. */
625 : PHI = 3 /* Selector for one of several values. */
626 : };
627 :
628 30737258 : Kind kind() const {
629 30737258 : JS_ASSERT(u.pushed.kind == u.var.kind && u.pushed.kind == u.phi.kind);
630 :
631 : /* Use a bitmask because MSVC wants to use -1 for PHI nodes. */
632 30737258 : return (Kind) (u.pushed.kind & 0x3);
633 : }
634 :
635 52245 : bool operator==(const SSAValue &o) const {
636 52245 : return !memcmp(this, &o, sizeof(SSAValue));
637 : }
638 :
639 : /* Accessors for values pushed by a bytecode within this script. */
640 :
641 4185594 : uint32_t pushedOffset() const {
642 4185594 : JS_ASSERT(kind() == PUSHED);
643 4185594 : return u.pushed.offset;
644 : }
645 :
646 4065330 : uint32_t pushedIndex() const {
647 4065330 : JS_ASSERT(kind() == PUSHED);
648 4065330 : return u.pushed.index;
649 : }
650 :
651 : /* Accessors for initial and written values of arguments and (undefined) locals. */
652 :
653 471969 : bool varInitial() const {
654 471969 : JS_ASSERT(kind() == VAR);
655 471969 : return u.var.initial;
656 : }
657 :
658 331493 : uint32_t varSlot() const {
659 331493 : JS_ASSERT(kind() == VAR);
660 331493 : return u.var.slot;
661 : }
662 :
663 186132 : uint32_t varOffset() const {
664 186132 : JS_ASSERT(!varInitial());
665 186132 : return u.var.offset;
666 : }
667 :
668 : /* Accessors for phi nodes. */
669 :
670 : uint32_t phiSlot() const;
671 : uint32_t phiLength() const;
672 : const SSAValue &phiValue(uint32_t i) const;
673 : types::TypeSet *phiTypes() const;
674 :
675 : /* Offset at which this phi node was created. */
676 153534 : uint32_t phiOffset() const {
677 153534 : JS_ASSERT(kind() == PHI);
678 153534 : return u.phi.offset;
679 : }
680 :
681 319234 : SSAPhiNode *phiNode() const {
682 319234 : JS_ASSERT(kind() == PHI);
683 319234 : return u.phi.node;
684 : }
685 :
686 : /* Other accessors. */
687 :
688 : #ifdef DEBUG
689 : void print() const;
690 : #endif
691 :
692 4223949 : void clear() {
693 4223949 : PodZero(this);
694 4223949 : JS_ASSERT(kind() == EMPTY);
695 4223949 : }
696 :
697 2211128 : void initPushed(uint32_t offset, uint32_t index) {
698 2211128 : clear();
699 2211128 : u.pushed.kind = PUSHED;
700 2211128 : u.pushed.offset = offset;
701 2211128 : u.pushed.index = index;
702 2211128 : }
703 :
704 427804 : static SSAValue PushedValue(uint32_t offset, uint32_t index) {
705 : SSAValue v;
706 427804 : v.initPushed(offset, index);
707 : return v;
708 : }
709 :
710 12959 : void initInitial(uint32_t slot) {
711 12959 : clear();
712 12959 : u.var.kind = VAR;
713 12959 : u.var.initial = true;
714 12959 : u.var.slot = slot;
715 12959 : }
716 :
717 43130 : void initWritten(uint32_t slot, uint32_t offset) {
718 43130 : clear();
719 43130 : u.var.kind = VAR;
720 43130 : u.var.initial = false;
721 43130 : u.var.slot = slot;
722 43130 : u.var.offset = offset;
723 43130 : }
724 :
725 174 : static SSAValue WrittenVar(uint32_t slot, uint32_t offset) {
726 : SSAValue v;
727 174 : v.initWritten(slot, offset);
728 : return v;
729 : }
730 :
731 15290 : void initPhi(uint32_t offset, SSAPhiNode *node) {
732 15290 : clear();
733 15290 : u.phi.kind = PHI;
734 15290 : u.phi.offset = offset;
735 15290 : u.phi.node = node;
736 15290 : }
737 :
738 111 : static SSAValue PhiValue(uint32_t offset, SSAPhiNode *node) {
739 : SSAValue v;
740 111 : v.initPhi(offset, node);
741 : return v;
742 : }
743 :
744 : private:
745 : union {
746 : struct {
747 : Kind kind : 2;
748 : uint32_t offset : 30;
749 : uint32_t index;
750 : } pushed;
751 : struct {
752 : Kind kind : 2;
753 : bool initial : 1;
754 : uint32_t slot : 29;
755 : uint32_t offset;
756 : } var;
757 : struct {
758 : Kind kind : 2;
759 : uint32_t offset : 30;
760 : SSAPhiNode *node;
761 : } phi;
762 : } u;
763 : };
764 :
765 : /*
766 : * Mutable component of a phi node, with the possible values of the phi
767 : * and the possible types of the node as determined by type inference.
768 : * When phi nodes are copied around, any updates to the original will
769 : * be seen by all copies made.
770 : */
771 : struct SSAPhiNode
772 : {
773 : types::TypeSet types;
774 : uint32_t slot;
775 : uint32_t length;
776 : SSAValue *options;
777 : SSAUseChain *uses;
778 15179 : SSAPhiNode() { PodZero(this); }
779 : };
780 :
781 : inline uint32_t
782 18560 : SSAValue::phiSlot() const
783 : {
784 18560 : return u.phi.node->slot;
785 : }
786 :
787 : inline uint32_t
788 0 : SSAValue::phiLength() const
789 : {
790 0 : JS_ASSERT(kind() == PHI);
791 0 : return u.phi.node->length;
792 : }
793 :
794 : inline const SSAValue &
795 0 : SSAValue::phiValue(uint32_t i) const
796 : {
797 0 : JS_ASSERT(kind() == PHI && i < phiLength());
798 0 : return u.phi.node->options[i];
799 : }
800 :
801 : inline types::TypeSet *
802 : SSAValue::phiTypes() const
803 : {
804 : JS_ASSERT(kind() == PHI);
805 : return &u.phi.node->types;
806 : }
807 :
808 : class SSAUseChain
809 : {
810 : public:
811 : bool popped : 1;
812 : uint32_t offset : 31;
813 : /* FIXME: Assert that only the proper arm of this union is accessed. */
814 : union {
815 : uint32_t which;
816 : SSAPhiNode *phi;
817 : } u;
818 : SSAUseChain *next;
819 :
820 23019 : SSAUseChain() { PodZero(this); }
821 : };
822 :
823 : class SlotValue
824 : {
825 : public:
826 : uint32_t slot;
827 : SSAValue value;
828 63912 : SlotValue(uint32_t slot, const SSAValue &value) : slot(slot), value(value) {}
829 : };
830 :
831 : /* Analysis information about a script. */
832 : class ScriptAnalysis
833 : {
834 : friend class Bytecode;
835 :
836 : JSScript *script;
837 :
838 : Bytecode **codeArray;
839 :
840 : uint32_t numSlots;
841 :
842 : bool outOfMemory;
843 : bool hadFailure;
844 :
845 : bool *escapedSlots;
846 :
847 : /* Which analyses have been performed. */
848 : bool ranBytecode_;
849 : bool ranSSA_;
850 : bool ranLifetimes_;
851 : bool ranInference_;
852 :
853 : #ifdef DEBUG
854 : /* Whether the compartment was in debug mode when we performed the analysis. */
855 : bool originalDebugMode_: 1;
856 : #endif
857 :
858 : /* --------- Bytecode analysis --------- */
859 :
860 : bool usesReturnValue_:1;
861 : bool usesScopeChain_:1;
862 : bool usesThisValue_:1;
863 : bool hasFunctionCalls_:1;
864 : bool modifiesArguments_:1;
865 : bool extendsScope_:1;
866 : bool addsScopeObjects_:1;
867 : bool localsAliasStack_:1;
868 : bool isInlineable:1;
869 : bool isCompileable:1;
870 : bool canTrackVars:1;
871 :
872 : uint32_t numReturnSites_;
873 :
874 : /* --------- Lifetime analysis --------- */
875 :
876 : LifetimeVariable *lifetimes;
877 :
878 : public:
879 :
880 166090 : ScriptAnalysis(JSScript *script) {
881 166090 : PodZero(this);
882 166090 : this->script = script;
883 : #ifdef DEBUG
884 166090 : this->originalDebugMode_ = script->compartment()->debugMode();
885 : #endif
886 166090 : }
887 :
888 102703212 : bool ranBytecode() { return ranBytecode_; }
889 78853 : bool ranSSA() { return ranSSA_; }
890 451748 : bool ranLifetimes() { return ranLifetimes_; }
891 863138813 : bool ranInference() { return ranInference_; }
892 :
893 : void analyzeBytecode(JSContext *cx);
894 : void analyzeSSA(JSContext *cx);
895 : void analyzeLifetimes(JSContext *cx);
896 : void analyzeTypes(JSContext *cx);
897 :
898 : /* Analyze the effect of invoking 'new' on script. */
899 : void analyzeTypesNew(JSContext *cx);
900 :
901 4560168 : bool OOM() { return outOfMemory; }
902 596223 : bool failed() { return hadFailure; }
903 4573 : bool inlineable(uint32_t argc) { return isInlineable && argc == script->function()->nargs; }
904 103394 : bool compileable() { return isCompileable; }
905 :
906 : /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
907 121901 : bool usesReturnValue() const { return usesReturnValue_; }
908 :
909 : /* Whether there are NAME bytecodes which can access the frame's scope chain. */
910 43919 : bool usesScopeChain() const { return usesScopeChain_; }
911 :
912 2971 : bool usesThisValue() const { return usesThisValue_; }
913 24523 : bool hasFunctionCalls() const { return hasFunctionCalls_; }
914 2997 : uint32_t numReturnSites() const { return numReturnSites_; }
915 :
916 : /*
917 : * True if all named formal arguments are not modified. If the arguments
918 : * object cannot escape, the arguments are never modified within the script.
919 : */
920 400 : bool modifiesArguments() { return modifiesArguments_; }
921 :
922 : /*
923 : * True if the script may extend declarations in its top level scope with
924 : * dynamic fun/var declarations or through eval.
925 : */
926 1431 : bool extendsScope() { return extendsScope_; }
927 :
928 : /* True if the script may add block or with objects to its scope chain. */
929 80784 : bool addsScopeObjects() { return addsScopeObjects_; }
930 :
931 : /*
932 : * True if there are any LOCAL opcodes aliasing values on the stack (above
933 : * script->nfixed).
934 : */
935 26595 : bool localsAliasStack() { return localsAliasStack_; }
936 :
937 : /* Accessors for bytecode information. */
938 :
939 106028900 : Bytecode& getCode(uint32_t offset) {
940 106028900 : JS_ASSERT(offset < script->length);
941 106028900 : JS_ASSERT(codeArray[offset]);
942 106028900 : return *codeArray[offset];
943 : }
944 80790330 : Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script->code); }
945 :
946 78264448 : Bytecode* maybeCode(uint32_t offset) {
947 78264448 : JS_ASSERT(offset < script->length);
948 78264448 : return codeArray[offset];
949 : }
950 10557055 : Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script->code); }
951 :
952 643913 : bool jumpTarget(uint32_t offset) {
953 643913 : JS_ASSERT(offset < script->length);
954 643913 : return codeArray[offset] && codeArray[offset]->jumpTarget;
955 : }
956 643913 : bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script->code); }
957 :
958 51270 : bool popGuaranteed(jsbytecode *pc) {
959 51270 : jsbytecode *next = pc + GetBytecodeLength(pc);
960 51270 : return JSOp(*next) == JSOP_POP && !jumpTarget(next);
961 : }
962 :
963 29841 : bool incrementInitialValueObserved(jsbytecode *pc) {
964 29841 : const JSCodeSpec *cs = &js_CodeSpec[*pc];
965 29841 : return (cs->format & JOF_POST) && !popGuaranteed(pc);
966 : }
967 :
968 76883322 : types::TypeSet *bytecodeTypes(const jsbytecode *pc) {
969 76883322 : JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
970 76883322 : return getCode(pc).observedTypes;
971 : }
972 :
973 2592532 : const SSAValue &poppedValue(uint32_t offset, uint32_t which) {
974 2592532 : JS_ASSERT(offset < script->length);
975 2592532 : JS_ASSERT(which < GetUseCount(script, offset) +
976 2592532 : (ExtendedUse(script->code + offset) ? 1 : 0));
977 2592532 : return getCode(offset).poppedValues[which];
978 : }
979 2559236 : const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which) {
980 2559236 : return poppedValue(pc - script->code, which);
981 : }
982 :
983 470063 : const SlotValue *newValues(uint32_t offset) {
984 470063 : JS_ASSERT(offset < script->length);
985 470063 : return getCode(offset).newValues;
986 : }
987 470063 : const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script->code); }
988 :
989 15109299 : types::TypeSet *pushedTypes(uint32_t offset, uint32_t which = 0) {
990 15109299 : JS_ASSERT(offset < script->length);
991 15109299 : JS_ASSERT(which < GetDefCount(script, offset) +
992 15109299 : (ExtendedDef(script->code + offset) ? 1 : 0));
993 15109299 : types::TypeSet *array = getCode(offset).pushedTypes;
994 15109299 : JS_ASSERT(array);
995 15109299 : return array + which;
996 : }
997 10966093 : types::TypeSet *pushedTypes(const jsbytecode *pc, uint32_t which) {
998 10966093 : return pushedTypes(pc - script->code, which);
999 : }
1000 :
1001 : bool hasPushedTypes(const jsbytecode *pc) { return getCode(pc).pushedTypes != NULL; }
1002 :
1003 518031 : types::TypeBarrier *typeBarriers(JSContext *cx, uint32_t offset) {
1004 518031 : if (getCode(offset).typeBarriers)
1005 297994 : pruneTypeBarriers(cx, offset);
1006 518031 : return getCode(offset).typeBarriers;
1007 : }
1008 518031 : types::TypeBarrier *typeBarriers(JSContext *cx, const jsbytecode *pc) {
1009 518031 : return typeBarriers(cx, pc - script->code);
1010 : }
1011 : void addTypeBarrier(JSContext *cx, const jsbytecode *pc,
1012 : types::TypeSet *target, types::Type type);
1013 : void addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc,
1014 : types::TypeSet *target, JSObject *singleton, jsid singletonId);
1015 :
1016 : /* Remove obsolete type barriers at the given offset. */
1017 : void pruneTypeBarriers(JSContext *cx, uint32_t offset);
1018 :
1019 : /*
1020 : * Remove still-active type barriers at the given offset. If 'all' is set,
1021 : * then all barriers are removed, otherwise only those deemed excessive
1022 : * are removed.
1023 : */
1024 : void breakTypeBarriers(JSContext *cx, uint32_t offset, bool all);
1025 :
1026 : /* Break all type barriers used in computing v. */
1027 : void breakTypeBarriersSSA(JSContext *cx, const SSAValue &v);
1028 :
1029 : inline void addPushedType(JSContext *cx, uint32_t offset, uint32_t which, types::Type type);
1030 :
1031 2588735 : types::TypeSet *getValueTypes(const SSAValue &v) {
1032 2588735 : switch (v.kind()) {
1033 : case SSAValue::PUSHED:
1034 2268466 : return pushedTypes(v.pushedOffset(), v.pushedIndex());
1035 : case SSAValue::VAR:
1036 108650 : JS_ASSERT(!slotEscapes(v.varSlot()));
1037 108650 : if (v.varInitial()) {
1038 54265 : return types::TypeScript::SlotTypes(script, v.varSlot());
1039 : } else {
1040 : /*
1041 : * Results of intermediate assignments have the same type as
1042 : * the first type pushed by the assignment op. Note that this
1043 : * may not be the exact same value as was pushed, due to
1044 : * post-inc/dec ops.
1045 : */
1046 54385 : return pushedTypes(v.varOffset(), 0);
1047 : }
1048 : case SSAValue::PHI:
1049 211619 : return &v.phiNode()->types;
1050 : default:
1051 : /* Cannot compute types for empty SSA values. */
1052 0 : JS_NOT_REACHED("Bad SSA value");
1053 : return NULL;
1054 : }
1055 : }
1056 :
1057 4 : types::TypeSet *poppedTypes(uint32_t offset, uint32_t which) {
1058 4 : return getValueTypes(poppedValue(offset, which));
1059 : }
1060 2395381 : types::TypeSet *poppedTypes(const jsbytecode *pc, uint32_t which) {
1061 2395381 : return getValueTypes(poppedValue(pc, which));
1062 : }
1063 :
1064 : /* Whether an arithmetic operation is operating on integers, with an integer result. */
1065 : bool integerOperation(JSContext *cx, jsbytecode *pc);
1066 :
1067 3950606 : bool trackUseChain(const SSAValue &v) {
1068 3950606 : JS_ASSERT_IF(v.kind() == SSAValue::VAR, trackSlot(v.varSlot()));
1069 3950606 : return v.kind() != SSAValue::EMPTY &&
1070 3950606 : (v.kind() != SSAValue::VAR || !v.varInitial());
1071 : }
1072 :
1073 : /*
1074 : * Get the use chain for an SSA value. May be invalid for some opcodes in
1075 : * scripts where localsAliasStack(). You have been warned!
1076 : */
1077 1913882 : SSAUseChain *& useChain(const SSAValue &v) {
1078 1913882 : JS_ASSERT(trackUseChain(v));
1079 1913882 : if (v.kind() == SSAValue::PUSHED)
1080 1796864 : return getCode(v.pushedOffset()).pushedUses[v.pushedIndex()];
1081 117018 : if (v.kind() == SSAValue::VAR)
1082 63130 : return getCode(v.varOffset()).pushedUses[GetDefCount(script, v.varOffset())];
1083 53888 : return v.phiNode()->uses;
1084 : }
1085 :
1086 928895 : mjit::RegisterAllocation *&getAllocation(uint32_t offset) {
1087 928895 : JS_ASSERT(offset < script->length);
1088 928895 : return getCode(offset).allocation;
1089 : }
1090 928253 : mjit::RegisterAllocation *&getAllocation(const jsbytecode *pc) {
1091 928253 : return getAllocation(pc - script->code);
1092 : }
1093 :
1094 246979 : LoopAnalysis *getLoop(uint32_t offset) {
1095 246979 : JS_ASSERT(offset < script->length);
1096 246979 : return getCode(offset).loop;
1097 : }
1098 246436 : LoopAnalysis *getLoop(const jsbytecode *pc) { return getLoop(pc - script->code); }
1099 :
1100 : /* For a JSOP_CALL* op, get the pc of the corresponding JSOP_CALL/NEW/etc. */
1101 47667 : jsbytecode *getCallPC(jsbytecode *pc)
1102 : {
1103 47667 : SSAUseChain *uses = useChain(SSAValue::PushedValue(pc - script->code, 0));
1104 47667 : JS_ASSERT(uses && uses->popped);
1105 47667 : JS_ASSERT(js_CodeSpec[script->code[uses->offset]].format & JOF_INVOKE);
1106 47667 : return script->code + uses->offset;
1107 : }
1108 :
1109 : /* Accessors for local variable information. */
1110 :
1111 : /*
1112 : * Escaping slots include all slots that can be accessed in ways other than
1113 : * through the corresponding LOCAL/ARG opcode. This includes all closed
1114 : * slots in the script, all slots in scripts which use eval or are in debug
1115 : * mode, and slots which are aliased by NAME or similar opcodes in the
1116 : * containing script (which does not imply the variable is closed).
1117 : */
1118 2969271 : bool slotEscapes(uint32_t slot) {
1119 2969271 : JS_ASSERT(script->compartment()->activeAnalysis);
1120 2969271 : if (slot >= numSlots)
1121 238094 : return true;
1122 2731177 : return escapedSlots[slot];
1123 : }
1124 :
1125 : /*
1126 : * Whether we distinguish different writes of this variable while doing
1127 : * SSA analysis. Escaping locals can be written in other scripts, and the
1128 : * presence of NAME opcodes which could alias local variables or arguments
1129 : * keeps us from tracking variable values at each point.
1130 : */
1131 1529962 : bool trackSlot(uint32_t slot) { return !slotEscapes(slot) && canTrackVars; }
1132 :
1133 290440 : const LifetimeVariable & liveness(uint32_t slot) {
1134 290440 : JS_ASSERT(script->compartment()->activeAnalysis);
1135 290440 : JS_ASSERT(!slotEscapes(slot));
1136 290440 : return lifetimes[slot];
1137 : }
1138 :
1139 : /*
1140 : * If a NAME or similar opcode is definitely accessing a particular slot
1141 : * of a script this one is nested in, get that script/slot.
1142 : */
1143 : struct NameAccess {
1144 : JSScript *script;
1145 : types::TypeScriptNesting *nesting;
1146 : uint32_t slot;
1147 :
1148 : /* Decompose the slot above. */
1149 : bool arg;
1150 : uint32_t index;
1151 :
1152 29343 : const Value **basePointer() const {
1153 29343 : return arg ? &nesting->argArray : &nesting->varArray;
1154 : }
1155 : };
1156 : NameAccess resolveNameAccess(JSContext *cx, jsid id, bool addDependency = false);
1157 :
1158 : void printSSA(JSContext *cx);
1159 : void printTypes(JSContext *cx);
1160 :
1161 : void clearAllocations();
1162 :
1163 : private:
1164 0 : void setOOM(JSContext *cx) {
1165 0 : if (!outOfMemory)
1166 0 : js_ReportOutOfMemory(cx);
1167 0 : outOfMemory = true;
1168 0 : hadFailure = true;
1169 0 : }
1170 :
1171 : /* Bytecode helpers */
1172 : inline bool addJump(JSContext *cx, unsigned offset,
1173 : unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop,
1174 : unsigned stackDepth);
1175 : void checkAliasedName(JSContext *cx, jsbytecode *pc);
1176 :
1177 : /* Lifetime helpers */
1178 : inline void addVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
1179 : LifetimeVariable **&saved, unsigned &savedCount);
1180 : inline void killVariable(JSContext *cx, LifetimeVariable &var, unsigned offset,
1181 : LifetimeVariable **&saved, unsigned &savedCount);
1182 : inline void extendVariable(JSContext *cx, LifetimeVariable &var, unsigned start, unsigned end);
1183 : inline void ensureVariable(LifetimeVariable &var, unsigned until);
1184 :
1185 : /* Current value for a variable or stack value, as tracked during SSA. */
1186 : struct SSAValueInfo
1187 : {
1188 : SSAValue v;
1189 :
1190 : /*
1191 : * Sizes of branchTargets the last time this slot was written. Branches less
1192 : * than this threshold do not need to be inspected if the slot is written
1193 : * again, as they will already reflect the slot's value at the branch.
1194 : */
1195 : int32_t branchSize;
1196 : };
1197 :
1198 : /* SSA helpers */
1199 : bool makePhi(JSContext *cx, uint32_t slot, uint32_t offset, SSAValue *pv);
1200 : void insertPhi(JSContext *cx, SSAValue &phi, const SSAValue &v);
1201 : void mergeValue(JSContext *cx, uint32_t offset, const SSAValue &v, SlotValue *pv);
1202 : void checkPendingValue(JSContext *cx, const SSAValue &v, uint32_t slot,
1203 : Vector<SlotValue> *pending);
1204 : void checkBranchTarget(JSContext *cx, uint32_t targetOffset, Vector<uint32_t> &branchTargets,
1205 : SSAValueInfo *values, uint32_t stackDepth);
1206 : void checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
1207 : Vector<uint32_t> &exceptionTargets);
1208 : void mergeBranchTarget(JSContext *cx, SSAValueInfo &value, uint32_t slot,
1209 : const Vector<uint32_t> &branchTargets, uint32_t currentOffset);
1210 : void mergeExceptionTarget(JSContext *cx, const SSAValue &value, uint32_t slot,
1211 : const Vector<uint32_t> &exceptionTargets);
1212 : void mergeAllExceptionTargets(JSContext *cx, SSAValueInfo *values,
1213 : const Vector<uint32_t> &exceptionTargets);
1214 : void freezeNewValues(JSContext *cx, uint32_t offset);
1215 :
1216 38594 : struct TypeInferenceState {
1217 : Vector<SSAPhiNode *> phiNodes;
1218 : bool hasGetSet;
1219 : bool hasHole;
1220 : types::TypeSet *forTypes;
1221 38594 : TypeInferenceState(JSContext *cx)
1222 38594 : : phiNodes(cx), hasGetSet(false), hasHole(false), forTypes(NULL)
1223 38594 : {}
1224 : };
1225 :
1226 : /* Type inference helpers */
1227 : bool analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state);
1228 : bool followEscapingArguments(JSContext *cx, const SSAValue &v, Vector<SSAValue> *seen);
1229 : bool followEscapingArguments(JSContext *cx, SSAUseChain *use, Vector<SSAValue> *seen);
1230 :
1231 : public:
1232 : #ifdef DEBUG
1233 : void assertMatchingDebugMode();
1234 : #else
1235 : void assertMatchingDebugMode() { }
1236 : #endif
1237 : };
1238 :
1239 : /* Protect analysis structures from GC while they are being used. */
1240 : class AutoEnterAnalysis
1241 : {
1242 : JSCompartment *compartment;
1243 : bool oldActiveAnalysis;
1244 : bool left;
1245 :
1246 260776 : void construct(JSCompartment *compartment)
1247 : {
1248 260776 : this->compartment = compartment;
1249 260776 : oldActiveAnalysis = compartment->activeAnalysis;
1250 260776 : compartment->activeAnalysis = true;
1251 260776 : left = false;
1252 260776 : }
1253 :
1254 : public:
1255 213121 : AutoEnterAnalysis(JSContext *cx) { construct(cx->compartment); }
1256 47655 : AutoEnterAnalysis(JSCompartment *compartment) { construct(compartment); }
1257 :
1258 260794 : void leave()
1259 : {
1260 260794 : if (!left) {
1261 260776 : left = true;
1262 260776 : compartment->activeAnalysis = oldActiveAnalysis;
1263 : }
1264 260794 : }
1265 :
1266 260776 : ~AutoEnterAnalysis()
1267 : {
1268 260776 : leave();
1269 260776 : }
1270 : };
1271 :
1272 : /* SSA value as used by CrossScriptSSA, identifies the frame it came from. */
1273 : struct CrossSSAValue
1274 : {
1275 : unsigned frame;
1276 : SSAValue v;
1277 468893 : CrossSSAValue(unsigned frame, const SSAValue &v) : frame(frame), v(v) {}
1278 : };
1279 :
1280 : /*
1281 : * Analysis for managing SSA values from multiple call stack frames. These are
1282 : * created by the backend compiler when inlining functions, and allow for
1283 : * values to be tracked as they flow into or out of the inlined frames.
1284 : */
1285 : class CrossScriptSSA
1286 95862 : {
1287 : public:
1288 :
1289 : static const uint32_t OUTER_FRAME = UINT32_MAX;
1290 : static const unsigned INVALID_FRAME = uint32_t(-2);
1291 :
1292 6266 : struct Frame {
1293 : uint32_t index;
1294 : JSScript *script;
1295 : uint32_t depth; /* Distance from outer frame to this frame, in sizeof(Value) */
1296 : uint32_t parent;
1297 : jsbytecode *parentpc;
1298 :
1299 98804 : Frame(uint32_t index, JSScript *script, uint32_t depth, uint32_t parent, jsbytecode *parentpc)
1300 98804 : : index(index), script(script), depth(depth), parent(parent), parentpc(parentpc)
1301 98804 : {}
1302 : };
1303 :
1304 355883 : const Frame &getFrame(uint32_t index) {
1305 355883 : if (index == OUTER_FRAME)
1306 324742 : return outerFrame;
1307 31141 : return inlineFrames[index];
1308 : }
1309 :
1310 444176 : unsigned numFrames() { return 1 + inlineFrames.length(); }
1311 353994 : const Frame &iterFrame(unsigned i) {
1312 353994 : if (i == 0)
1313 128314 : return outerFrame;
1314 225680 : return inlineFrames[i - 1];
1315 : }
1316 :
1317 33573 : JSScript *outerScript() { return outerFrame.script; }
1318 :
1319 : /* Total length of scripts preceding a frame. */
1320 96663 : size_t frameLength(uint32_t index) {
1321 96663 : if (index == OUTER_FRAME)
1322 93731 : return 0;
1323 2932 : size_t res = outerFrame.script->length;
1324 67468 : for (unsigned i = 0; i < index; i++)
1325 64536 : res += inlineFrames[i].script->length;
1326 2932 : return res;
1327 : }
1328 :
1329 4310 : types::TypeSet *getValueTypes(const CrossSSAValue &cv) {
1330 4310 : return getFrame(cv.frame).script->analysis()->getValueTypes(cv.v);
1331 : }
1332 :
1333 2942 : bool addInlineFrame(JSScript *script, uint32_t depth, uint32_t parent, jsbytecode *parentpc)
1334 : {
1335 2942 : uint32_t index = inlineFrames.length();
1336 2942 : return inlineFrames.append(Frame(index, script, depth, parent, parentpc));
1337 : }
1338 :
1339 95862 : CrossScriptSSA(JSContext *cx, JSScript *outer)
1340 95862 : : cx(cx), outerFrame(OUTER_FRAME, outer, 0, INVALID_FRAME, NULL), inlineFrames(cx)
1341 95862 : {}
1342 :
1343 : CrossSSAValue foldValue(const CrossSSAValue &cv);
1344 :
1345 : private:
1346 : JSContext *cx;
1347 :
1348 : Frame outerFrame;
1349 : Vector<Frame> inlineFrames;
1350 : };
1351 :
1352 : #ifdef DEBUG
1353 : void PrintBytecode(JSContext *cx, JSScript *script, jsbytecode *pc);
1354 : #endif
1355 :
1356 : static inline bool
1357 3754 : SpeculateApplyOptimization(jsbytecode *pc)
1358 : {
1359 3754 : JS_ASSERT(*pc == JSOP_ARGUMENTS);
1360 3754 : jsbytecode *nextpc = pc + JSOP_ARGUMENTS_LENGTH;
1361 3754 : return *nextpc == JSOP_FUNAPPLY && GET_ARGC(nextpc) == 2;
1362 : }
1363 :
1364 : } /* namespace analyze */
1365 : } /* namespace js */
1366 :
1367 : namespace js {
1368 : namespace tl {
1369 :
1370 : template <> struct IsPodType<js::analyze::LifetimeVariable> { static const bool result = true; };
1371 : template <> struct IsPodType<js::analyze::LoopAnalysis> { static const bool result = true; };
1372 : template <> struct IsPodType<js::analyze::SlotValue> { static const bool result = true; };
1373 : template <> struct IsPodType<js::analyze::SSAValue> { static const bool result = true; };
1374 : template <> struct IsPodType<js::analyze::SSAUseChain> { static const bool result = true; };
1375 :
1376 : } /* namespace tl */
1377 : } /* namespace js */
1378 :
1379 : #endif // jsanalyze_h___
|