• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #ifndef V8_JUMP_TARGET_H_
29 #define V8_JUMP_TARGET_H_
30 
31 #include "macro-assembler.h"
32 
33 namespace v8 {
34 namespace internal {
35 
36 // Forward declarations.
37 class FrameElement;
38 class Result;
39 class VirtualFrame;
40 
41 // -------------------------------------------------------------------------
42 // Jump targets
43 //
44 // A jump target is an abstraction of a basic-block entry in generated
45 // code.  It collects all the virtual frames reaching the block by
46 // forward jumps and pairs them with labels for the merge code along
47 // all forward-reaching paths.  When bound, an expected frame for the
48 // block is determined and code is generated to merge to the expected
49 // frame.  For backward jumps, the merge code is generated at the edge
50 // leaving the predecessor block.
51 //
52 // A jump target must have been reached via control flow (either by
53 // jumping, branching, or falling through) at the time it is bound.
54 // In particular, this means that at least one of the control-flow
55 // graph edges reaching the target must be a forward edge.
56 
57 class JumpTarget : public ZoneObject {  // Shadows are dynamically allocated.
58  public:
59   // Forward-only jump targets can only be reached by forward CFG edges.
60   enum Directionality { FORWARD_ONLY, BIDIRECTIONAL };
61 
62   // Construct a jump target used to generate code and to provide
63   // access to a current frame.
JumpTarget(Directionality direction)64   explicit JumpTarget(Directionality direction)
65       : direction_(direction),
66         reaching_frames_(0),
67         merge_labels_(0),
68         entry_frame_(NULL) {
69   }
70 
71   // Construct a jump target.
JumpTarget()72   JumpTarget()
73       : direction_(FORWARD_ONLY),
74         reaching_frames_(0),
75         merge_labels_(0),
76         entry_frame_(NULL) {
77   }
78 
~JumpTarget()79   virtual ~JumpTarget() {}
80 
81   // Set the direction of the jump target.
set_direction(Directionality direction)82   virtual void set_direction(Directionality direction) {
83     direction_ = direction;
84   }
85 
86   // Treat the jump target as a fresh one.  The state is reset.
87   void Unuse();
88 
89   inline CodeGenerator* cgen();
90 
entry_label()91   Label* entry_label() { return &entry_label_; }
92 
entry_frame()93   VirtualFrame* entry_frame() const { return entry_frame_; }
set_entry_frame(VirtualFrame * frame)94   void set_entry_frame(VirtualFrame* frame) {
95     entry_frame_ = frame;
96   }
97 
98   // Predicates testing the state of the encapsulated label.
is_bound()99   bool is_bound() const { return entry_label_.is_bound(); }
is_linked()100   bool is_linked() const {
101     return !is_bound() && !reaching_frames_.is_empty();
102   }
is_unused()103   bool is_unused() const {
104     // This is !is_bound() && !is_linked().
105     return !is_bound() && reaching_frames_.is_empty();
106   }
107 
108   // Emit a jump to the target.  There must be a current frame at the
109   // jump and there will be no current frame after the jump.
110   virtual void Jump();
111   virtual void Jump(Result* arg);
112 
113   // Emit a conditional branch to the target.  There must be a current
114   // frame at the branch.  The current frame will fall through to the
115   // code after the branch.  The arg is a result that is live both at
116   // the target and the fall-through.
117   virtual void Branch(Condition cc, Hint hint = no_hint);
118   virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
119 
120   // Bind a jump target.  If there is no current frame at the binding
121   // site, there must be at least one frame reaching via a forward
122   // jump.
123   virtual void Bind();
124   virtual void Bind(Result* arg);
125 
126   // Emit a call to a jump target.  There must be a current frame at
127   // the call.  The frame at the target is the same as the current
128   // frame except for an extra return address on top of it.  The frame
129   // after the call is the same as the frame before the call.
130   void Call();
131 
set_compiling_deferred_code(bool flag)132   static void set_compiling_deferred_code(bool flag) {
133     compiling_deferred_code_ = flag;
134   }
135 
136  protected:
137   // Directionality flag set at initialization time.
138   Directionality direction_;
139 
140   // A list of frames reaching this block via forward jumps.
141   ZoneList<VirtualFrame*> reaching_frames_;
142 
143   // A parallel list of labels for merge code.
144   ZoneList<Label> merge_labels_;
145 
146   // The frame used on entry to the block and expected at backward
147   // jumps to the block.  Set when the jump target is bound, but may
148   // or may not be set for forward-only blocks.
149   VirtualFrame* entry_frame_;
150 
151   // The actual entry label of the block.
152   Label entry_label_;
153 
154   // Implementations of Jump, Branch, and Bind with all arguments and
155   // return values using the virtual frame.
156   void DoJump();
157   void DoBranch(Condition cc, Hint hint);
158   void DoBind();
159 
160  private:
161   static bool compiling_deferred_code_;
162 
163   // Add a virtual frame reaching this labeled block via a forward jump,
164   // and a corresponding merge code label.
165   void AddReachingFrame(VirtualFrame* frame);
166 
167   // Perform initialization required during entry frame computation
168   // after setting the virtual frame element at index in frame to be
169   // target.
170   inline void InitializeEntryElement(int index, FrameElement* target);
171 
172   // Compute a frame to use for entry to this block.
173   void ComputeEntryFrame();
174 
175   DISALLOW_COPY_AND_ASSIGN(JumpTarget);
176 };
177 
178 
179 // -------------------------------------------------------------------------
180 // Break targets
181 //
182 // A break target is a jump target that can be used to break out of a
183 // statement that keeps extra state on the stack (eg, for/in or
184 // try/finally).  They know the expected stack height at the target
185 // and will drop state from nested statements as part of merging.
186 //
187 // Break targets are used for return, break, and continue targets.
188 
189 class BreakTarget : public JumpTarget {
190  public:
191   // Construct a break target.
BreakTarget()192   BreakTarget() {}
193 
~BreakTarget()194   virtual ~BreakTarget() {}
195 
196   // Set the direction of the break target.
197   virtual void set_direction(Directionality direction);
198 
199   // Copy the state of this break target to the destination.  The
200   // lists of forward-reaching frames and merge-point labels are
201   // copied.  All virtual frame pointers are copied, not the
202   // pointed-to frames.  The previous state of the destination is
203   // overwritten, without deallocating pointed-to virtual frames.
204   void CopyTo(BreakTarget* destination);
205 
206   // Emit a jump to the target.  There must be a current frame at the
207   // jump and there will be no current frame after the jump.
208   virtual void Jump();
209   virtual void Jump(Result* arg);
210 
211   // Emit a conditional branch to the target.  There must be a current
212   // frame at the branch.  The current frame will fall through to the
213   // code after the branch.
214   virtual void Branch(Condition cc, Hint hint = no_hint);
215   virtual void Branch(Condition cc, Result* arg, Hint hint = no_hint);
216 
217   // Bind a break target.  If there is no current frame at the binding
218   // site, there must be at least one frame reaching via a forward
219   // jump.
220   virtual void Bind();
221   virtual void Bind(Result* arg);
222 
223   // Setter for expected height.
set_expected_height(int expected)224   void set_expected_height(int expected) { expected_height_ = expected; }
225 
226  private:
227   // The expected height of the expression stack where the target will
228   // be bound, statically known at initialization time.
229   int expected_height_;
230 
231   DISALLOW_COPY_AND_ASSIGN(BreakTarget);
232 };
233 
234 
235 // -------------------------------------------------------------------------
236 // Shadow break targets
237 //
238 // A shadow break target represents a break target that is temporarily
239 // shadowed by another one (represented by the original during
240 // shadowing).  They are used to catch jumps to labels in certain
241 // contexts, e.g. try blocks.  After shadowing ends, the formerly
242 // shadowed target is again represented by the original and the
243 // ShadowTarget can be used as a jump target in its own right,
244 // representing the formerly shadowing target.
245 
246 class ShadowTarget : public BreakTarget {
247  public:
248   // Construct a shadow jump target.  After construction the shadow
249   // target object holds the state of the original target, and the
250   // original target is actually a fresh one that intercepts control
251   // flow intended for the shadowed one.
252   explicit ShadowTarget(BreakTarget* shadowed);
253 
~ShadowTarget()254   virtual ~ShadowTarget() {}
255 
256   // End shadowing.  After shadowing ends, the original jump target
257   // again gives access to the formerly shadowed target and the shadow
258   // target object gives access to the formerly shadowing target.
259   void StopShadowing();
260 
261   // During shadowing, the currently shadowing target.  After
262   // shadowing, the target that was shadowed.
other_target()263   BreakTarget* other_target() const { return other_target_; }
264 
265  private:
266   // During shadowing, the currently shadowing target.  After
267   // shadowing, the target that was shadowed.
268   BreakTarget* other_target_;
269 
270 #ifdef DEBUG
271   bool is_shadowing_;
272 #endif
273 
274   DISALLOW_COPY_AND_ASSIGN(ShadowTarget);
275 };
276 
277 
278 } }  // namespace v8::internal
279 
280 #endif  // V8_JUMP_TARGET_H_
281