| OLD | NEW |
| 1 // Copyright 2008 the V8 project authors. All rights reserved. | 1 // Copyright 2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 #include "codegen.h" | 30 #include "codegen.h" |
| 31 #include "jump-target.h" | 31 #include "jump-target.h" |
| 32 | 32 |
| 33 namespace v8 { namespace internal { | 33 namespace v8 { namespace internal { |
| 34 | 34 |
| 35 // ------------------------------------------------------------------------- | 35 // ------------------------------------------------------------------------- |
| 36 // JumpTarget implementation. | 36 // JumpTarget implementation. |
| 37 | 37 |
| 38 #define __ masm_-> | 38 #define __ masm_-> |
| 39 | 39 |
| 40 JumpTarget::JumpTarget(CodeGenerator* cgen) | 40 JumpTarget::JumpTarget(CodeGenerator* cgen, Directionality direction) |
| 41 : expected_frame_(NULL), | 41 : cgen_(cgen), |
| 42 code_generator_(cgen), | 42 direction_(direction), |
| 43 masm_(cgen->masm()) { | 43 reaching_frames_(0), |
| 44 merge_labels_(0), |
| 45 expected_frame_(NULL), |
| 46 is_bound_(false), |
| 47 is_linked_(false) { |
| 48 ASSERT(cgen_ != NULL); |
| 49 masm_ = cgen_->masm(); |
| 44 } | 50 } |
| 45 | 51 |
| 46 | 52 |
| 47 JumpTarget::JumpTarget() | 53 JumpTarget::JumpTarget() |
| 48 : expected_frame_(NULL), | 54 : cgen_(NULL), |
| 49 code_generator_(NULL), | 55 masm_(NULL), |
| 50 masm_(NULL) { | 56 direction_(FORWARD_ONLY), |
| 51 } | 57 reaching_frames_(0), |
| 52 | 58 merge_labels_(0), |
| 53 | 59 expected_frame_(NULL), |
| 54 void JumpTarget::set_code_generator(CodeGenerator* cgen) { | 60 is_bound_(false), |
| 61 is_linked_(false) { |
| 62 } |
| 63 |
| 64 |
| 65 void JumpTarget::Initialize(CodeGenerator* cgen, Directionality direction) { |
| 55 ASSERT(cgen != NULL); | 66 ASSERT(cgen != NULL); |
| 56 ASSERT(code_generator_ == NULL); | 67 ASSERT(cgen_ == NULL); |
| 57 code_generator_ = cgen; | 68 cgen_ = cgen; |
| 58 masm_ = cgen->masm(); | 69 masm_ = cgen->masm(); |
| 70 direction_ = direction; |
| 71 } |
| 72 |
| 73 |
| 74 void JumpTarget::Unuse() { |
| 75 ASSERT(!is_linked()); |
| 76 entry_label_.Unuse(); |
| 77 delete expected_frame_; |
| 78 expected_frame_ = NULL; |
| 79 is_bound_ = false; |
| 80 is_linked_ = false; |
| 81 } |
| 82 |
| 83 |
| 84 void JumpTarget::Reset() { |
| 85 reaching_frames_.Clear(); |
| 86 merge_labels_.Clear(); |
| 87 expected_frame_ = NULL; |
| 88 entry_label_.Unuse(); |
| 89 is_bound_ = false; |
| 90 is_linked_ = false; |
| 59 } | 91 } |
| 60 | 92 |
| 61 | 93 |
| 62 void JumpTarget::Jump() { | 94 void JumpTarget::Jump() { |
| 63 // Precondition: there is a current frame. There may or may not be an | 95 ASSERT(cgen_ != NULL); |
| 64 // expected frame at the label. | 96 ASSERT(cgen_->has_valid_frame()); |
| 65 ASSERT(code_generator_ != NULL); | 97 // Live non-frame registers are not allowed at unconditional jumps |
| 66 | 98 // because we have no way of invalidating the corresponding results |
| 67 VirtualFrame* current_frame = code_generator_->frame(); | 99 // which are still live in the C++ code. |
| 68 ASSERT(current_frame != NULL); | 100 ASSERT(cgen_->HasValidEntryRegisters()); |
| 69 | 101 |
| 70 if (expected_frame_ == NULL) { | 102 if (is_bound()) { |
| 71 expected_frame_ = current_frame; | 103 // Backward jump. There is an expected frame to merge to. |
| 72 code_generator_->set_frame(NULL); | 104 ASSERT(direction_ == BIDIRECTIONAL); |
| 73 // The frame at the actual function return will always have height zero. | 105 cgen_->frame()->MergeTo(expected_frame_); |
| 74 if (code_generator_->IsActualFunctionReturn(this)) { | 106 cgen_->DeleteFrame(); |
| 75 expected_frame_->Forget(expected_frame_->height()); | 107 __ jmp(&entry_label_); |
| 108 } else { |
| 109 // Forward jump. The current frame is added to the end of the list |
| 110 // of frames reaching the target block and a jump to the merge code |
| 111 // is emitted. |
| 112 AddReachingFrame(cgen_->frame()); |
| 113 cgen_->SetFrame(NULL); |
| 114 __ jmp(&merge_labels_.last()); |
| 115 } |
| 116 |
| 117 is_linked_ = !is_bound_; |
| 118 } |
| 119 |
| 120 |
| 121 void JumpTarget::Jump(Result* arg) { |
| 122 UNIMPLEMENTED(); |
| 123 } |
| 124 |
| 125 |
| 126 void JumpTarget::Jump(Result* arg0, Result* arg1) { |
| 127 UNIMPLEMENTED(); |
| 128 } |
| 129 |
| 130 |
| 131 void JumpTarget::Jump(Result* arg0, Result* arg1, Result* arg2) { |
| 132 UNIMPLEMENTED(); |
| 133 } |
| 134 |
| 135 |
| 136 void JumpTarget::Branch(Condition cc, Hint ignored) { |
| 137 ASSERT(cgen_ != NULL); |
| 138 ASSERT(cgen_->has_valid_frame()); |
| 139 |
| 140 if (is_bound()) { |
| 141 // Backward branch. We have an expected frame to merge to on the |
| 142 // backward edge. We negate the condition and emit the merge code |
| 143 // here. |
| 144 // |
| 145 // TODO(210): we should try to avoid negating the condition in the |
| 146 // case where there is no merge code to emit. Otherwise, we emit |
| 147 // a branch around an unconditional jump. |
| 148 ASSERT(direction_ == BIDIRECTIONAL); |
| 149 Label original_fall_through; |
| 150 __ b(NegateCondition(cc), &original_fall_through); |
| 151 // Swap the current frame for a copy of it, saving non-frame |
| 152 // register reference counts and invalidating all non-frame register |
| 153 // references except the reserved ones on the backward edge. |
| 154 VirtualFrame* original_frame = cgen_->frame(); |
| 155 VirtualFrame* working_frame = new VirtualFrame(original_frame); |
| 156 cgen_->SetFrame(working_frame); |
| 157 |
| 158 working_frame->MergeTo(expected_frame_); |
| 159 cgen_->DeleteFrame(); |
| 160 __ jmp(&entry_label_); |
| 161 |
| 162 // Restore the frame and its associated non-frame registers. |
| 163 cgen_->SetFrame(original_frame); |
| 164 __ bind(&original_fall_through); |
| 165 } else { |
| 166 // Forward branch. A copy of the current frame is added to the end |
| 167 // of the list of frames reaching the target block and a branch to |
| 168 // the merge code is emitted. |
| 169 AddReachingFrame(new VirtualFrame(cgen_->frame())); |
| 170 __ b(cc, &merge_labels_.last()); |
| 171 } |
| 172 |
| 173 is_linked_ = !is_bound_; |
| 174 } |
| 175 |
| 176 |
| 177 void JumpTarget::Branch(Condition cc, Result* arg, Hint ignored) { |
| 178 UNIMPLEMENTED(); |
| 179 } |
| 180 |
| 181 |
| 182 void JumpTarget::Branch(Condition cc, |
| 183 Result* arg0, |
| 184 Result* arg1, |
| 185 Hint ignored) { |
| 186 UNIMPLEMENTED(); |
| 187 } |
| 188 |
| 189 |
| 190 void JumpTarget::Branch(Condition cc, |
| 191 Result* arg0, |
| 192 Result* arg1, |
| 193 Result* arg2, |
| 194 Hint ignored) { |
| 195 UNIMPLEMENTED(); |
| 196 } |
| 197 |
| 198 |
| 199 void JumpTarget::Branch(Condition cc, |
| 200 Result* arg0, |
| 201 Result* arg1, |
| 202 Result* arg2, |
| 203 Result* arg3, |
| 204 Hint ignored) { |
| 205 UNIMPLEMENTED(); |
| 206 } |
| 207 |
| 208 |
| 209 void JumpTarget::Call() { |
| 210 // Call is used to push the address of the catch block on the stack as |
| 211 // a return address when compiling try/catch and try/finally. We |
| 212 // fully spill the frame before making the call. The expected frame |
| 213 // at the label (which should be the only one) is the spilled current |
| 214 // frame plus an in-memory return address. The "fall-through" frame |
| 215 // at the return site is the spilled current frame. |
| 216 ASSERT(cgen_ != NULL); |
| 217 ASSERT(cgen_->has_valid_frame()); |
| 218 // There are no non-frame references across the call. |
| 219 ASSERT(cgen_->HasValidEntryRegisters()); |
| 220 ASSERT(!is_linked()); |
| 221 |
| 222 VirtualFrame* target_frame = new VirtualFrame(cgen_->frame()); |
| 223 target_frame->Adjust(1); |
| 224 AddReachingFrame(target_frame); |
| 225 __ bl(&merge_labels_.last()); |
| 226 |
| 227 is_linked_ = !is_bound_; |
| 228 } |
| 229 |
| 230 |
| 231 void JumpTarget::Bind() { |
| 232 ASSERT(cgen_ != NULL); |
| 233 ASSERT(!is_bound()); |
| 234 |
| 235 if (is_linked()) { |
| 236 // There were forward jumps. A mergable frame is created and all |
| 237 // the frames reaching the block via forward jumps are merged to it. |
| 238 ASSERT(reaching_frames_.length() == merge_labels_.length()); |
| 239 |
| 240 // A special case is that there was only one jump to the block so |
| 241 // far, no fall-through, and there cannot be another entry because |
| 242 // the block is forward only. In that case, simply use the single |
| 243 // frame. |
| 244 bool single_entry = (direction_ == FORWARD_ONLY) && |
| 245 !cgen_->has_valid_frame() && |
| 246 (reaching_frames_.length() == 1); |
| 247 if (single_entry) { |
| 248 // Pick up the only forward reaching frame and bind its merge |
| 249 // label. No merge code is emitted. |
| 250 cgen_->SetFrame(reaching_frames_[0]); |
| 251 __ bind(&merge_labels_[0]); |
| 252 } else { |
| 253 // Otherwise, choose a frame as the basis of the expected frame, |
| 254 // and make it mergable. If there is a current frame use it, |
| 255 // otherwise use the first in the list (there will be at least |
| 256 // one). |
| 257 int start_index = 0; |
| 258 if (cgen_->has_valid_frame()) { |
| 259 // Live non-frame registers are not allowed at the start of a |
| 260 // labeled basic block. |
| 261 ASSERT(cgen_->HasValidEntryRegisters()); |
| 262 } else { |
| 263 cgen_->SetFrame(reaching_frames_[start_index]); |
| 264 __ bind(&merge_labels_[start_index++]); |
| 265 } |
| 266 cgen_->frame()->MakeMergable(); |
| 267 expected_frame_ = new VirtualFrame(cgen_->frame()); |
| 268 |
| 269 for (int i = start_index; i < reaching_frames_.length(); i++) { |
| 270 cgen_->DeleteFrame(); |
| 271 __ jmp(&entry_label_); |
| 272 |
| 273 cgen_->SetFrame(reaching_frames_[i]); |
| 274 __ bind(&merge_labels_[i]); |
| 275 |
| 276 cgen_->frame()->MergeTo(expected_frame_); |
| 277 } |
| 278 |
| 279 __ bind(&entry_label_); |
| 76 } | 280 } |
| 281 |
| 282 // All but the last reaching virtual frame have been deleted, and |
| 283 // the last one is the current frame. |
| 284 reaching_frames_.Clear(); |
| 285 merge_labels_.Clear(); |
| 286 |
| 77 } else { | 287 } else { |
| 78 // No code needs to be emitted to merge to the expected frame at the | 288 // There were no forward jumps. If this jump target is not |
| 79 // actual function return. | 289 // bidirectional, there is no need to do anything. For |
| 80 if (!code_generator_->IsActualFunctionReturn(this)) { | 290 // bidirectional jump targets, the current frame is made mergable |
| 81 current_frame->MergeTo(expected_frame_); | 291 // and used for the expected frame. |
| 82 } | 292 if (direction_ == BIDIRECTIONAL) { |
| 83 code_generator_->delete_frame(); | 293 ASSERT(cgen_->HasValidEntryRegisters()); |
| 84 } | 294 cgen_->frame()->MakeMergable(); |
| 85 | 295 expected_frame_ = new VirtualFrame(cgen_->frame()); |
| 86 __ b(&label_); | 296 __ bind(&entry_label_); |
| 87 // Postcondition: there is no current frame but there is an expected frame | |
| 88 // at the label. | |
| 89 } | |
| 90 | |
| 91 | |
| 92 void JumpTarget::Branch(Condition cc, Hint ignored) { | |
| 93 // Precondition: there is a current frame. There may or may not be an | |
| 94 // expected frame at the label. | |
| 95 ASSERT(code_generator_ != NULL); | |
| 96 ASSERT(masm_ != NULL); | |
| 97 | |
| 98 VirtualFrame* current_frame = code_generator_->frame(); | |
| 99 ASSERT(current_frame != NULL); | |
| 100 | |
| 101 if (expected_frame_ == NULL) { | |
| 102 expected_frame_ = new VirtualFrame(current_frame); | |
| 103 // The frame at the actual function return will always have height zero. | |
| 104 if (code_generator_->IsActualFunctionReturn(this)) { | |
| 105 expected_frame_->Forget(expected_frame_->height()); | |
| 106 } | |
| 107 } else { | |
| 108 // No code needs to be emitted to merge to the expected frame at the | |
| 109 // actual function return. | |
| 110 if (!code_generator_->IsActualFunctionReturn(this)) { | |
| 111 current_frame->MergeTo(expected_frame_); | |
| 112 } | 297 } |
| 113 } | 298 } |
| 114 | 299 |
| 115 __ b(cc, &label_); | 300 is_linked_ = false; |
| 116 // Postcondition: there is both a current frame and an expected frame at | 301 is_bound_ = true; |
| 117 // the label and they match. | 302 } |
| 118 } | 303 |
| 119 | 304 |
| 120 | 305 void JumpTarget::Bind(Result* arg) { |
| 121 void JumpTarget::Call() { | 306 UNIMPLEMENTED(); |
| 122 // Precondition: there is a current frame, and there is no expected frame | 307 } |
| 123 // at the label. | 308 |
| 124 ASSERT(code_generator_ != NULL); | 309 |
| 125 ASSERT(masm_ != NULL); | 310 void JumpTarget::Bind(Result* arg0, Result* arg1) { |
| 126 ASSERT(!code_generator_->IsActualFunctionReturn(this)); | 311 UNIMPLEMENTED(); |
| 127 | 312 } |
| 128 VirtualFrame* current_frame = code_generator_->frame(); | 313 |
| 129 ASSERT(current_frame != NULL); | 314 |
| 130 ASSERT(expected_frame_ == NULL); | 315 void JumpTarget::Bind(Result* arg0, Result* arg1, Result* arg2) { |
| 131 | 316 UNIMPLEMENTED(); |
| 132 expected_frame_ = new VirtualFrame(current_frame); | 317 } |
| 133 // Adjust the expected frame's height to account for the return address | 318 |
| 134 // pushed by the call instruction. | 319 |
| 135 expected_frame_->Adjust(1); | 320 void JumpTarget::Bind(Result* arg0, Result* arg1, Result* arg2, Result* arg3) { |
| 136 | 321 UNIMPLEMENTED(); |
| 137 __ bl(&label_); | 322 } |
| 138 // Postcondition: there is both a current frame and an expected frame at | 323 |
| 139 // the label. The current frame is one shorter than the one at the label | 324 |
| 140 // (which contains the return address in memory). | 325 void JumpTarget::CopyTo(JumpTarget* destination) { |
| 141 } | 326 ASSERT(destination != NULL); |
| 142 | 327 destination->cgen_ = cgen_; |
| 143 | 328 destination->masm_ = masm_; |
| 144 void JumpTarget::Bind() { | 329 destination->direction_ = direction_; |
| 145 // Precondition: there is either a current frame or an expected frame at | 330 destination->reaching_frames_.Clear(); |
| 146 // the label (and possibly both). The label is unbound. | 331 destination->merge_labels_.Clear(); |
| 147 ASSERT(code_generator_ != NULL); | 332 ASSERT(reaching_frames_.length() == merge_labels_.length()); |
| 148 ASSERT(masm_ != NULL); | 333 for (int i = 0; i < reaching_frames_.length(); i++) { |
| 149 | 334 destination->reaching_frames_.Add(reaching_frames_[i]); |
| 150 VirtualFrame* current_frame = code_generator_->frame(); | 335 destination->merge_labels_.Add(merge_labels_[i]); |
| 151 ASSERT(current_frame != NULL || expected_frame_ != NULL); | |
| 152 ASSERT(!label_.is_bound()); | |
| 153 | |
| 154 if (expected_frame_ == NULL) { | |
| 155 expected_frame_ = new VirtualFrame(current_frame); | |
| 156 // The frame at the actual function return will always have height zero. | |
| 157 if (code_generator_->IsActualFunctionReturn(this)) { | |
| 158 expected_frame_->Forget(expected_frame_->height()); | |
| 159 } | |
| 160 } else if (current_frame == NULL) { | |
| 161 code_generator_->set_frame(new VirtualFrame(expected_frame_)); | |
| 162 } else { | |
| 163 // No code needs to be emitted to merge to the expected frame at the | |
| 164 // actual function return. | |
| 165 if (!code_generator_->IsActualFunctionReturn(this)) { | |
| 166 current_frame->MergeTo(expected_frame_); | |
| 167 } | |
| 168 } | 336 } |
| 169 | 337 destination->expected_frame_ = expected_frame_; |
| 170 __ bind(&label_); | 338 destination->entry_label_ = entry_label_; |
| 171 // Postcondition: there is both a current frame and an expected frame at | 339 destination->is_bound_ = is_bound_; |
| 172 // the label and they match. The label is bound. | 340 destination->is_linked_ = is_linked_; |
| 341 } |
| 342 |
| 343 |
| 344 void JumpTarget::AddReachingFrame(VirtualFrame* frame) { |
| 345 ASSERT(reaching_frames_.length() == merge_labels_.length()); |
| 346 Label fresh; |
| 347 merge_labels_.Add(fresh); |
| 348 reaching_frames_.Add(frame); |
| 173 } | 349 } |
| 174 | 350 |
| 175 | 351 |
| 176 // ------------------------------------------------------------------------- | 352 // ------------------------------------------------------------------------- |
| 177 // ShadowTarget implementation. | 353 // ShadowTarget implementation. |
| 178 | 354 |
| 179 ShadowTarget::ShadowTarget(JumpTarget* original) { | 355 ShadowTarget::ShadowTarget(JumpTarget* shadowed) { |
| 180 ASSERT(original != NULL); | 356 ASSERT(shadowed != NULL); |
| 181 original_target_ = original; | 357 other_target_ = shadowed; |
| 182 original_pos_ = original->label()->pos_; | 358 |
| 183 original_expected_frame_ = original->expected_frame(); | |
| 184 | |
| 185 // We do not call Unuse() on the orginal jump target, because we do not | |
| 186 // want to delete the expected frame. | |
| 187 original->label()->pos_ = 0; | |
| 188 original->set_expected_frame(NULL); | |
| 189 #ifdef DEBUG | 359 #ifdef DEBUG |
| 190 is_shadowing_ = true; | 360 is_shadowing_ = true; |
| 191 #endif | 361 #endif |
| 362 // While shadowing this shadow target saves the state of the original. |
| 363 shadowed->CopyTo(this); |
| 364 |
| 365 // Setting the code generator to null prevents the shadow target from |
| 366 // being used until shadowing stops. |
| 367 cgen_ = NULL; |
| 368 masm_ = NULL; |
| 369 |
| 370 // The original's state is reset. We do not Unuse it because that |
| 371 // would delete the expected frame and assert that the target is not |
| 372 // linked. |
| 373 shadowed->Reset(); |
| 192 } | 374 } |
| 193 | 375 |
| 194 | 376 |
| 195 void ShadowTarget::StopShadowing() { | 377 void ShadowTarget::StopShadowing() { |
| 196 ASSERT(is_shadowing_); | 378 ASSERT(is_shadowing_); |
| 197 ASSERT(is_unused()); | 379 |
| 198 | 380 // This target does not have a valid code generator yet. |
| 199 set_code_generator(original_target_->code_generator()); | 381 cgen_ = other_target_->code_generator(); |
| 200 label_.pos_ = original_target_->label()->pos_; | 382 ASSERT(cgen_ != NULL); |
| 201 expected_frame_ = original_target_->expected_frame(); | 383 masm_ = cgen_->masm(); |
| 202 | 384 |
| 203 original_target_->label()->pos_ = original_pos_; | 385 // The states of this target, which was shadowed, and the original |
| 204 original_target_->set_expected_frame(original_expected_frame_); | 386 // target, which was shadowing, are swapped. |
| 387 JumpTarget temp; |
| 388 other_target_->CopyTo(&temp); |
| 389 CopyTo(other_target_); |
| 390 temp.CopyTo(this); |
| 391 temp.Reset(); // So the destructor does not deallocate virtual frames. |
| 205 | 392 |
| 206 #ifdef DEBUG | 393 #ifdef DEBUG |
| 207 is_shadowing_ = false; | 394 is_shadowing_ = false; |
| 208 #endif | 395 #endif |
| 209 } | 396 } |
| 210 | 397 |
| 211 #undef __ | 398 #undef __ |
| 212 | 399 |
| 213 | 400 |
| 214 } } // namespace v8::internal | 401 } } // namespace v8::internal |
| OLD | NEW |