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 #include "v8.h" 29 30 #include "codegen-inl.h" 31 #include "jump-target-inl.h" 32 #include "register-allocator-inl.h" 33 34 namespace v8 { 35 namespace internal { 36 37 // ------------------------------------------------------------------------- 38 // JumpTarget implementation. 39 40 #define __ ACCESS_MASM(cgen()->masm()) 41 42 void JumpTarget::DoJump() { 43 ASSERT(cgen()->has_valid_frame()); 44 // Live non-frame registers are not allowed at unconditional jumps 45 // because we have no way of invalidating the corresponding results 46 // which are still live in the C++ code. 47 ASSERT(cgen()->HasValidEntryRegisters()); 48 49 if (is_bound()) { 50 // Backward jump. There already a frame expectation at the target. 51 ASSERT(direction_ == BIDIRECTIONAL); 52 cgen()->frame()->MergeTo(entry_frame_); 53 cgen()->DeleteFrame(); 54 } else { 55 // Use the current frame as the expected one at the target if necessary. 56 if (entry_frame_ == NULL) { 57 entry_frame_ = cgen()->frame(); 58 RegisterFile empty; 59 cgen()->SetFrame(NULL, &empty); 60 } else { 61 cgen()->frame()->MergeTo(entry_frame_); 62 cgen()->DeleteFrame(); 63 } 64 65 // The predicate is_linked() should be made true. Its implementation 66 // detects the presence of a frame pointer in the reaching_frames_ list. 67 if (!is_linked()) { 68 reaching_frames_.Add(NULL); 69 ASSERT(is_linked()); 70 } 71 } 72 __ jmp(&entry_label_); 73 } 74 75 76 void JumpTarget::DoBranch(Condition cc, Hint ignored) { 77 ASSERT(cgen()->has_valid_frame()); 78 79 if (is_bound()) { 80 ASSERT(direction_ == BIDIRECTIONAL); 81 // Backward branch. We have an expected frame to merge to on the 82 // backward edge. 83 cgen()->frame()->MergeTo(entry_frame_); 84 } else { 85 // Clone the current frame to use as the expected one at the target if 86 // necessary. 87 if (entry_frame_ == NULL) { 88 entry_frame_ = new VirtualFrame(cgen()->frame()); 89 } 90 // The predicate is_linked() should be made true. Its implementation 91 // detects the presence of a frame pointer in the reaching_frames_ list. 92 if (!is_linked()) { 93 reaching_frames_.Add(NULL); 94 ASSERT(is_linked()); 95 } 96 } 97 __ b(cc, &entry_label_); 98 } 99 100 101 void JumpTarget::Call() { 102 // Call is used to push the address of the catch block on the stack as 103 // a return address when compiling try/catch and try/finally. We 104 // fully spill the frame before making the call. The expected frame 105 // at the label (which should be the only one) is the spilled current 106 // frame plus an in-memory return address. The "fall-through" frame 107 // at the return site is the spilled current frame. 108 ASSERT(cgen()->has_valid_frame()); 109 // There are no non-frame references across the call. 110 ASSERT(cgen()->HasValidEntryRegisters()); 111 ASSERT(!is_linked()); 112 113 // Calls are always 'forward' so we use a copy of the current frame (plus 114 // one for a return address) as the expected frame. 115 ASSERT(entry_frame_ == NULL); 116 VirtualFrame* target_frame = new VirtualFrame(cgen()->frame()); 117 target_frame->Adjust(1); 118 entry_frame_ = target_frame; 119 120 // The predicate is_linked() should now be made true. Its implementation 121 // detects the presence of a frame pointer in the reaching_frames_ list. 122 reaching_frames_.Add(NULL); 123 ASSERT(is_linked()); 124 125 __ bl(&entry_label_); 126 } 127 128 129 void JumpTarget::DoBind() { 130 ASSERT(!is_bound()); 131 132 // Live non-frame registers are not allowed at the start of a basic 133 // block. 134 ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters()); 135 136 if (cgen()->has_valid_frame()) { 137 // If there is a current frame we can use it on the fall through. 138 if (entry_frame_ == NULL) { 139 entry_frame_ = new VirtualFrame(cgen()->frame()); 140 } else { 141 ASSERT(cgen()->frame()->Equals(entry_frame_)); 142 } 143 } else { 144 // If there is no current frame we must have an entry frame which we can 145 // copy. 146 ASSERT(entry_frame_ != NULL); 147 RegisterFile empty; 148 cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty); 149 } 150 151 // The predicate is_linked() should be made false. Its implementation 152 // detects the presence (or absence) of frame pointers in the 153 // reaching_frames_ list. If we inserted a bogus frame to make 154 // is_linked() true, remove it now. 155 if (is_linked()) { 156 reaching_frames_.Clear(); 157 } 158 159 __ bind(&entry_label_); 160 } 161 162 163 void BreakTarget::Jump() { 164 // On ARM we do not currently emit merge code for jumps, so we need to do 165 // it explicitly here. The only merging necessary is to drop extra 166 // statement state from the stack. 167 ASSERT(cgen()->has_valid_frame()); 168 int count = cgen()->frame()->height() - expected_height_; 169 cgen()->frame()->Drop(count); 170 DoJump(); 171 } 172 173 174 void BreakTarget::Jump(Result* arg) { 175 // On ARM we do not currently emit merge code for jumps, so we need to do 176 // it explicitly here. The only merging necessary is to drop extra 177 // statement state from the stack. 178 ASSERT(cgen()->has_valid_frame()); 179 int count = cgen()->frame()->height() - expected_height_; 180 cgen()->frame()->Drop(count); 181 cgen()->frame()->Push(arg); 182 DoJump(); 183 } 184 185 186 void BreakTarget::Bind() { 187 #ifdef DEBUG 188 // All the forward-reaching frames should have been adjusted at the 189 // jumps to this target. 190 for (int i = 0; i < reaching_frames_.length(); i++) { 191 ASSERT(reaching_frames_[i] == NULL || 192 reaching_frames_[i]->height() == expected_height_); 193 } 194 #endif 195 // Drop leftover statement state from the frame before merging, even 196 // on the fall through. This is so we can bind the return target 197 // with state on the frame. 198 if (cgen()->has_valid_frame()) { 199 int count = cgen()->frame()->height() - expected_height_; 200 // On ARM we do not currently emit merge code at binding sites, so we need 201 // to do it explicitly here. The only merging necessary is to drop extra 202 // statement state from the stack. 203 cgen()->frame()->Drop(count); 204 } 205 206 DoBind(); 207 } 208 209 210 void BreakTarget::Bind(Result* arg) { 211 #ifdef DEBUG 212 // All the forward-reaching frames should have been adjusted at the 213 // jumps to this target. 214 for (int i = 0; i < reaching_frames_.length(); i++) { 215 ASSERT(reaching_frames_[i] == NULL || 216 reaching_frames_[i]->height() == expected_height_ + 1); 217 } 218 #endif 219 // Drop leftover statement state from the frame before merging, even 220 // on the fall through. This is so we can bind the return target 221 // with state on the frame. 222 if (cgen()->has_valid_frame()) { 223 int count = cgen()->frame()->height() - expected_height_; 224 // On ARM we do not currently emit merge code at binding sites, so we need 225 // to do it explicitly here. The only merging necessary is to drop extra 226 // statement state from the stack. 227 cgen()->frame()->ForgetElements(count); 228 cgen()->frame()->Push(arg); 229 } 230 DoBind(); 231 *arg = cgen()->frame()->Pop(); 232 } 233 234 235 #undef __ 236 237 238 } } // namespace v8::internal 239