1 // Copyright 2011 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_LITHIUM_H_ 29 #define V8_LITHIUM_H_ 30 31 #include "hydrogen.h" 32 #include "safepoint-table.h" 33 34 namespace v8 { 35 namespace internal { 36 37 class LOperand: public ZoneObject { 38 public: 39 enum Kind { 40 INVALID, 41 UNALLOCATED, 42 CONSTANT_OPERAND, 43 STACK_SLOT, 44 DOUBLE_STACK_SLOT, 45 REGISTER, 46 DOUBLE_REGISTER, 47 ARGUMENT 48 }; 49 50 LOperand() : value_(KindField::encode(INVALID)) { } 51 52 Kind kind() const { return KindField::decode(value_); } 53 int index() const { return static_cast<int>(value_) >> kKindFieldWidth; } 54 bool IsConstantOperand() const { return kind() == CONSTANT_OPERAND; } 55 bool IsStackSlot() const { return kind() == STACK_SLOT; } 56 bool IsDoubleStackSlot() const { return kind() == DOUBLE_STACK_SLOT; } 57 bool IsRegister() const { return kind() == REGISTER; } 58 bool IsDoubleRegister() const { return kind() == DOUBLE_REGISTER; } 59 bool IsArgument() const { return kind() == ARGUMENT; } 60 bool IsUnallocated() const { return kind() == UNALLOCATED; } 61 bool Equals(LOperand* other) const { return value_ == other->value_; } 62 int VirtualRegister(); 63 64 void PrintTo(StringStream* stream); 65 void ConvertTo(Kind kind, int index) { 66 value_ = KindField::encode(kind); 67 value_ |= index << kKindFieldWidth; 68 ASSERT(this->index() == index); 69 } 70 71 protected: 72 static const int kKindFieldWidth = 3; 73 class KindField : public BitField<Kind, 0, kKindFieldWidth> { }; 74 75 LOperand(Kind kind, int index) { ConvertTo(kind, index); } 76 77 unsigned value_; 78 }; 79 80 81 class LUnallocated: public LOperand { 82 public: 83 enum Policy { 84 NONE, 85 ANY, 86 FIXED_REGISTER, 87 FIXED_DOUBLE_REGISTER, 88 FIXED_SLOT, 89 MUST_HAVE_REGISTER, 90 WRITABLE_REGISTER, 91 SAME_AS_FIRST_INPUT, 92 IGNORE 93 }; 94 95 // Lifetime of operand inside the instruction. 96 enum Lifetime { 97 // USED_AT_START operand is guaranteed to be live only at 98 // instruction start. Register allocator is free to assign the same register 99 // to some other operand used inside instruction (i.e. temporary or 100 // output). 101 USED_AT_START, 102 103 // USED_AT_END operand is treated as live until the end of 104 // instruction. This means that register allocator will not reuse it's 105 // register for any other operand inside instruction. 106 USED_AT_END 107 }; 108 109 explicit LUnallocated(Policy policy) : LOperand(UNALLOCATED, 0) { 110 Initialize(policy, 0, USED_AT_END); 111 } 112 113 LUnallocated(Policy policy, int fixed_index) : LOperand(UNALLOCATED, 0) { 114 Initialize(policy, fixed_index, USED_AT_END); 115 } 116 117 LUnallocated(Policy policy, Lifetime lifetime) : LOperand(UNALLOCATED, 0) { 118 Initialize(policy, 0, lifetime); 119 } 120 121 // The superclass has a KindField. Some policies have a signed fixed 122 // index in the upper bits. 123 static const int kPolicyWidth = 4; 124 static const int kLifetimeWidth = 1; 125 static const int kVirtualRegisterWidth = 17; 126 127 static const int kPolicyShift = kKindFieldWidth; 128 static const int kLifetimeShift = kPolicyShift + kPolicyWidth; 129 static const int kVirtualRegisterShift = kLifetimeShift + kLifetimeWidth; 130 static const int kFixedIndexShift = 131 kVirtualRegisterShift + kVirtualRegisterWidth; 132 133 class PolicyField : public BitField<Policy, kPolicyShift, kPolicyWidth> { }; 134 135 class LifetimeField 136 : public BitField<Lifetime, kLifetimeShift, kLifetimeWidth> { 137 }; 138 139 class VirtualRegisterField 140 : public BitField<unsigned, 141 kVirtualRegisterShift, 142 kVirtualRegisterWidth> { 143 }; 144 145 static const int kMaxVirtualRegisters = 1 << (kVirtualRegisterWidth + 1); 146 static const int kMaxFixedIndex = 63; 147 static const int kMinFixedIndex = -64; 148 149 bool HasIgnorePolicy() const { return policy() == IGNORE; } 150 bool HasNoPolicy() const { return policy() == NONE; } 151 bool HasAnyPolicy() const { 152 return policy() == ANY; 153 } 154 bool HasFixedPolicy() const { 155 return policy() == FIXED_REGISTER || 156 policy() == FIXED_DOUBLE_REGISTER || 157 policy() == FIXED_SLOT; 158 } 159 bool HasRegisterPolicy() const { 160 return policy() == WRITABLE_REGISTER || policy() == MUST_HAVE_REGISTER; 161 } 162 bool HasSameAsInputPolicy() const { 163 return policy() == SAME_AS_FIRST_INPUT; 164 } 165 Policy policy() const { return PolicyField::decode(value_); } 166 void set_policy(Policy policy) { 167 value_ &= ~PolicyField::mask(); 168 value_ |= PolicyField::encode(policy); 169 } 170 int fixed_index() const { 171 return static_cast<int>(value_) >> kFixedIndexShift; 172 } 173 174 unsigned virtual_register() const { 175 return VirtualRegisterField::decode(value_); 176 } 177 178 void set_virtual_register(unsigned id) { 179 value_ &= ~VirtualRegisterField::mask(); 180 value_ |= VirtualRegisterField::encode(id); 181 } 182 183 LUnallocated* CopyUnconstrained() { 184 LUnallocated* result = new LUnallocated(ANY); 185 result->set_virtual_register(virtual_register()); 186 return result; 187 } 188 189 static LUnallocated* cast(LOperand* op) { 190 ASSERT(op->IsUnallocated()); 191 return reinterpret_cast<LUnallocated*>(op); 192 } 193 194 bool IsUsedAtStart() { 195 return LifetimeField::decode(value_) == USED_AT_START; 196 } 197 198 private: 199 void Initialize(Policy policy, int fixed_index, Lifetime lifetime) { 200 value_ |= PolicyField::encode(policy); 201 value_ |= LifetimeField::encode(lifetime); 202 value_ |= fixed_index << kFixedIndexShift; 203 ASSERT(this->fixed_index() == fixed_index); 204 } 205 }; 206 207 208 class LMoveOperands BASE_EMBEDDED { 209 public: 210 LMoveOperands(LOperand* source, LOperand* destination) 211 : source_(source), destination_(destination) { 212 } 213 214 LOperand* source() const { return source_; } 215 void set_source(LOperand* operand) { source_ = operand; } 216 217 LOperand* destination() const { return destination_; } 218 void set_destination(LOperand* operand) { destination_ = operand; } 219 220 // The gap resolver marks moves as "in-progress" by clearing the 221 // destination (but not the source). 222 bool IsPending() const { 223 return destination_ == NULL && source_ != NULL; 224 } 225 226 // True if this move a move into the given destination operand. 227 bool Blocks(LOperand* operand) const { 228 return !IsEliminated() && source()->Equals(operand); 229 } 230 231 // A move is redundant if it's been eliminated, if its source and 232 // destination are the same, or if its destination is unneeded. 233 bool IsRedundant() const { 234 return IsEliminated() || source_->Equals(destination_) || IsIgnored(); 235 } 236 237 bool IsIgnored() const { 238 return destination_ != NULL && 239 destination_->IsUnallocated() && 240 LUnallocated::cast(destination_)->HasIgnorePolicy(); 241 } 242 243 // We clear both operands to indicate move that's been eliminated. 244 void Eliminate() { source_ = destination_ = NULL; } 245 bool IsEliminated() const { 246 ASSERT(source_ != NULL || destination_ == NULL); 247 return source_ == NULL; 248 } 249 250 private: 251 LOperand* source_; 252 LOperand* destination_; 253 }; 254 255 256 class LConstantOperand: public LOperand { 257 public: 258 static LConstantOperand* Create(int index) { 259 ASSERT(index >= 0); 260 if (index < kNumCachedOperands) return &cache[index]; 261 return new LConstantOperand(index); 262 } 263 264 static LConstantOperand* cast(LOperand* op) { 265 ASSERT(op->IsConstantOperand()); 266 return reinterpret_cast<LConstantOperand*>(op); 267 } 268 269 static void SetupCache(); 270 271 private: 272 static const int kNumCachedOperands = 128; 273 static LConstantOperand cache[]; 274 275 LConstantOperand() : LOperand() { } 276 explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { } 277 }; 278 279 280 class LArgument: public LOperand { 281 public: 282 explicit LArgument(int index) : LOperand(ARGUMENT, index) { } 283 284 static LArgument* cast(LOperand* op) { 285 ASSERT(op->IsArgument()); 286 return reinterpret_cast<LArgument*>(op); 287 } 288 }; 289 290 291 class LStackSlot: public LOperand { 292 public: 293 static LStackSlot* Create(int index) { 294 ASSERT(index >= 0); 295 if (index < kNumCachedOperands) return &cache[index]; 296 return new LStackSlot(index); 297 } 298 299 static LStackSlot* cast(LOperand* op) { 300 ASSERT(op->IsStackSlot()); 301 return reinterpret_cast<LStackSlot*>(op); 302 } 303 304 static void SetupCache(); 305 306 private: 307 static const int kNumCachedOperands = 128; 308 static LStackSlot cache[]; 309 310 LStackSlot() : LOperand() { } 311 explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { } 312 }; 313 314 315 class LDoubleStackSlot: public LOperand { 316 public: 317 static LDoubleStackSlot* Create(int index) { 318 ASSERT(index >= 0); 319 if (index < kNumCachedOperands) return &cache[index]; 320 return new LDoubleStackSlot(index); 321 } 322 323 static LDoubleStackSlot* cast(LOperand* op) { 324 ASSERT(op->IsStackSlot()); 325 return reinterpret_cast<LDoubleStackSlot*>(op); 326 } 327 328 static void SetupCache(); 329 330 private: 331 static const int kNumCachedOperands = 128; 332 static LDoubleStackSlot cache[]; 333 334 LDoubleStackSlot() : LOperand() { } 335 explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { } 336 }; 337 338 339 class LRegister: public LOperand { 340 public: 341 static LRegister* Create(int index) { 342 ASSERT(index >= 0); 343 if (index < kNumCachedOperands) return &cache[index]; 344 return new LRegister(index); 345 } 346 347 static LRegister* cast(LOperand* op) { 348 ASSERT(op->IsRegister()); 349 return reinterpret_cast<LRegister*>(op); 350 } 351 352 static void SetupCache(); 353 354 private: 355 static const int kNumCachedOperands = 16; 356 static LRegister cache[]; 357 358 LRegister() : LOperand() { } 359 explicit LRegister(int index) : LOperand(REGISTER, index) { } 360 }; 361 362 363 class LDoubleRegister: public LOperand { 364 public: 365 static LDoubleRegister* Create(int index) { 366 ASSERT(index >= 0); 367 if (index < kNumCachedOperands) return &cache[index]; 368 return new LDoubleRegister(index); 369 } 370 371 static LDoubleRegister* cast(LOperand* op) { 372 ASSERT(op->IsDoubleRegister()); 373 return reinterpret_cast<LDoubleRegister*>(op); 374 } 375 376 static void SetupCache(); 377 378 private: 379 static const int kNumCachedOperands = 16; 380 static LDoubleRegister cache[]; 381 382 LDoubleRegister() : LOperand() { } 383 explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { } 384 }; 385 386 387 class LParallelMove : public ZoneObject { 388 public: 389 LParallelMove() : move_operands_(4) { } 390 391 void AddMove(LOperand* from, LOperand* to) { 392 move_operands_.Add(LMoveOperands(from, to)); 393 } 394 395 bool IsRedundant() const; 396 397 const ZoneList<LMoveOperands>* move_operands() const { 398 return &move_operands_; 399 } 400 401 void PrintDataTo(StringStream* stream) const; 402 403 private: 404 ZoneList<LMoveOperands> move_operands_; 405 }; 406 407 408 class LPointerMap: public ZoneObject { 409 public: 410 explicit LPointerMap(int position) 411 : pointer_operands_(8), position_(position), lithium_position_(-1) { } 412 413 const ZoneList<LOperand*>* operands() const { return &pointer_operands_; } 414 int position() const { return position_; } 415 int lithium_position() const { return lithium_position_; } 416 417 void set_lithium_position(int pos) { 418 ASSERT(lithium_position_ == -1); 419 lithium_position_ = pos; 420 } 421 422 void RecordPointer(LOperand* op); 423 void PrintTo(StringStream* stream); 424 425 private: 426 ZoneList<LOperand*> pointer_operands_; 427 int position_; 428 int lithium_position_; 429 }; 430 431 432 class LEnvironment: public ZoneObject { 433 public: 434 LEnvironment(Handle<JSFunction> closure, 435 int ast_id, 436 int parameter_count, 437 int argument_count, 438 int value_count, 439 LEnvironment* outer) 440 : closure_(closure), 441 arguments_stack_height_(argument_count), 442 deoptimization_index_(Safepoint::kNoDeoptimizationIndex), 443 translation_index_(-1), 444 ast_id_(ast_id), 445 parameter_count_(parameter_count), 446 values_(value_count), 447 representations_(value_count), 448 spilled_registers_(NULL), 449 spilled_double_registers_(NULL), 450 outer_(outer) { 451 } 452 453 Handle<JSFunction> closure() const { return closure_; } 454 int arguments_stack_height() const { return arguments_stack_height_; } 455 int deoptimization_index() const { return deoptimization_index_; } 456 int translation_index() const { return translation_index_; } 457 int ast_id() const { return ast_id_; } 458 int parameter_count() const { return parameter_count_; } 459 LOperand** spilled_registers() const { return spilled_registers_; } 460 LOperand** spilled_double_registers() const { 461 return spilled_double_registers_; 462 } 463 const ZoneList<LOperand*>* values() const { return &values_; } 464 LEnvironment* outer() const { return outer_; } 465 466 void AddValue(LOperand* operand, Representation representation) { 467 values_.Add(operand); 468 representations_.Add(representation); 469 } 470 471 bool HasTaggedValueAt(int index) const { 472 return representations_[index].IsTagged(); 473 } 474 475 void Register(int deoptimization_index, int translation_index) { 476 ASSERT(!HasBeenRegistered()); 477 deoptimization_index_ = deoptimization_index; 478 translation_index_ = translation_index; 479 } 480 bool HasBeenRegistered() const { 481 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; 482 } 483 484 void SetSpilledRegisters(LOperand** registers, 485 LOperand** double_registers) { 486 spilled_registers_ = registers; 487 spilled_double_registers_ = double_registers; 488 } 489 490 void PrintTo(StringStream* stream); 491 492 private: 493 Handle<JSFunction> closure_; 494 int arguments_stack_height_; 495 int deoptimization_index_; 496 int translation_index_; 497 int ast_id_; 498 int parameter_count_; 499 ZoneList<LOperand*> values_; 500 ZoneList<Representation> representations_; 501 502 // Allocation index indexed arrays of spill slot operands for registers 503 // that are also in spill slots at an OSR entry. NULL for environments 504 // that do not correspond to an OSR entry. 505 LOperand** spilled_registers_; 506 LOperand** spilled_double_registers_; 507 508 LEnvironment* outer_; 509 510 friend class LCodegen; 511 }; 512 513 514 // Iterates over the non-null, non-constant operands in an environment. 515 class ShallowIterator BASE_EMBEDDED { 516 public: 517 explicit ShallowIterator(LEnvironment* env) 518 : env_(env), 519 limit_(env != NULL ? env->values()->length() : 0), 520 current_(0) { 521 current_ = AdvanceToNext(0); 522 } 523 524 inline bool HasNext() { 525 return env_ != NULL && current_ < limit_; 526 } 527 528 inline LOperand* Next() { 529 ASSERT(HasNext()); 530 return env_->values()->at(current_); 531 } 532 533 inline void Advance() { 534 current_ = AdvanceToNext(current_ + 1); 535 } 536 537 inline LEnvironment* env() { return env_; } 538 539 private: 540 inline bool ShouldSkip(LOperand* op) { 541 return op == NULL || op->IsConstantOperand() || op->IsArgument(); 542 } 543 544 inline int AdvanceToNext(int start) { 545 while (start < limit_ && ShouldSkip(env_->values()->at(start))) { 546 start++; 547 } 548 return start; 549 } 550 551 LEnvironment* env_; 552 int limit_; 553 int current_; 554 }; 555 556 557 // Iterator for non-null, non-constant operands incl. outer environments. 558 class DeepIterator BASE_EMBEDDED { 559 public: 560 explicit DeepIterator(LEnvironment* env) 561 : current_iterator_(env) { } 562 563 inline bool HasNext() { 564 if (current_iterator_.HasNext()) return true; 565 if (current_iterator_.env() == NULL) return false; 566 AdvanceToOuter(); 567 return current_iterator_.HasNext(); 568 } 569 570 inline LOperand* Next() { 571 ASSERT(current_iterator_.HasNext()); 572 return current_iterator_.Next(); 573 } 574 575 inline void Advance() { 576 if (current_iterator_.HasNext()) { 577 current_iterator_.Advance(); 578 } else { 579 AdvanceToOuter(); 580 } 581 } 582 583 private: 584 inline void AdvanceToOuter() { 585 current_iterator_ = ShallowIterator(current_iterator_.env()->outer()); 586 } 587 588 ShallowIterator current_iterator_; 589 }; 590 591 } } // namespace v8::internal 592 593 #endif // V8_LITHIUM_H_ 594