| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef V8_LITHIUM_H_ | |
| 6 #define V8_LITHIUM_H_ | |
| 7 | |
| 8 #include <set> | |
| 9 | |
| 10 #include "src/allocation.h" | |
| 11 #include "src/bailout-reason.h" | |
| 12 #include "src/hydrogen.h" | |
| 13 #include "src/safepoint-table.h" | |
| 14 #include "src/zone-allocator.h" | |
| 15 | |
| 16 namespace v8 { | |
| 17 namespace internal { | |
| 18 | |
| 19 #define LITHIUM_OPERAND_LIST(V) \ | |
| 20 V(ConstantOperand, CONSTANT_OPERAND, 128) \ | |
| 21 V(StackSlot, STACK_SLOT, 128) \ | |
| 22 V(DoubleStackSlot, DOUBLE_STACK_SLOT, 128) \ | |
| 23 V(Register, REGISTER, 16) \ | |
| 24 V(DoubleRegister, DOUBLE_REGISTER, 16) | |
| 25 | |
| 26 class LOperand : public ZoneObject { | |
| 27 public: | |
| 28 enum Kind { | |
| 29 INVALID, | |
| 30 UNALLOCATED, | |
| 31 CONSTANT_OPERAND, | |
| 32 STACK_SLOT, | |
| 33 DOUBLE_STACK_SLOT, | |
| 34 REGISTER, | |
| 35 DOUBLE_REGISTER | |
| 36 }; | |
| 37 | |
| 38 LOperand() : value_(KindField::encode(INVALID)) { } | |
| 39 | |
| 40 Kind kind() const { return KindField::decode(value_); } | |
| 41 int index() const { return static_cast<int>(value_) >> kKindFieldWidth; } | |
| 42 #define LITHIUM_OPERAND_PREDICATE(name, type, number) \ | |
| 43 bool Is##name() const { return kind() == type; } | |
| 44 LITHIUM_OPERAND_LIST(LITHIUM_OPERAND_PREDICATE) | |
| 45 LITHIUM_OPERAND_PREDICATE(Unallocated, UNALLOCATED, 0) | |
| 46 LITHIUM_OPERAND_PREDICATE(Ignored, INVALID, 0) | |
| 47 #undef LITHIUM_OPERAND_PREDICATE | |
| 48 bool Equals(LOperand* other) const { return value_ == other->value_; } | |
| 49 | |
| 50 void PrintTo(StringStream* stream); | |
| 51 void ConvertTo(Kind kind, int index) { | |
| 52 if (kind == REGISTER) DCHECK(index >= 0); | |
| 53 value_ = KindField::encode(kind); | |
| 54 value_ |= index << kKindFieldWidth; | |
| 55 DCHECK(this->index() == index); | |
| 56 } | |
| 57 | |
| 58 // Calls SetUpCache()/TearDownCache() for each subclass. | |
| 59 static void SetUpCaches(); | |
| 60 static void TearDownCaches(); | |
| 61 | |
| 62 protected: | |
| 63 static const int kKindFieldWidth = 3; | |
| 64 class KindField : public BitField<Kind, 0, kKindFieldWidth> { }; | |
| 65 | |
| 66 LOperand(Kind kind, int index) { ConvertTo(kind, index); } | |
| 67 | |
| 68 unsigned value_; | |
| 69 }; | |
| 70 | |
| 71 | |
| 72 class LUnallocated : public LOperand { | |
| 73 public: | |
| 74 enum BasicPolicy { | |
| 75 FIXED_SLOT, | |
| 76 EXTENDED_POLICY | |
| 77 }; | |
| 78 | |
| 79 enum ExtendedPolicy { | |
| 80 NONE, | |
| 81 ANY, | |
| 82 FIXED_REGISTER, | |
| 83 FIXED_DOUBLE_REGISTER, | |
| 84 MUST_HAVE_REGISTER, | |
| 85 MUST_HAVE_DOUBLE_REGISTER, | |
| 86 WRITABLE_REGISTER, | |
| 87 SAME_AS_FIRST_INPUT | |
| 88 }; | |
| 89 | |
| 90 // Lifetime of operand inside the instruction. | |
| 91 enum Lifetime { | |
| 92 // USED_AT_START operand is guaranteed to be live only at | |
| 93 // instruction start. Register allocator is free to assign the same register | |
| 94 // to some other operand used inside instruction (i.e. temporary or | |
| 95 // output). | |
| 96 USED_AT_START, | |
| 97 | |
| 98 // USED_AT_END operand is treated as live until the end of | |
| 99 // instruction. This means that register allocator will not reuse it's | |
| 100 // register for any other operand inside instruction. | |
| 101 USED_AT_END | |
| 102 }; | |
| 103 | |
| 104 explicit LUnallocated(ExtendedPolicy policy) : LOperand(UNALLOCATED, 0) { | |
| 105 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | |
| 106 value_ |= ExtendedPolicyField::encode(policy); | |
| 107 value_ |= LifetimeField::encode(USED_AT_END); | |
| 108 } | |
| 109 | |
| 110 LUnallocated(BasicPolicy policy, int index) : LOperand(UNALLOCATED, 0) { | |
| 111 DCHECK(policy == FIXED_SLOT); | |
| 112 value_ |= BasicPolicyField::encode(policy); | |
| 113 value_ |= index << FixedSlotIndexField::kShift; | |
| 114 DCHECK(this->fixed_slot_index() == index); | |
| 115 } | |
| 116 | |
| 117 LUnallocated(ExtendedPolicy policy, int index) : LOperand(UNALLOCATED, 0) { | |
| 118 DCHECK(policy == FIXED_REGISTER || policy == FIXED_DOUBLE_REGISTER); | |
| 119 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | |
| 120 value_ |= ExtendedPolicyField::encode(policy); | |
| 121 value_ |= LifetimeField::encode(USED_AT_END); | |
| 122 value_ |= FixedRegisterField::encode(index); | |
| 123 } | |
| 124 | |
| 125 LUnallocated(ExtendedPolicy policy, Lifetime lifetime) | |
| 126 : LOperand(UNALLOCATED, 0) { | |
| 127 value_ |= BasicPolicyField::encode(EXTENDED_POLICY); | |
| 128 value_ |= ExtendedPolicyField::encode(policy); | |
| 129 value_ |= LifetimeField::encode(lifetime); | |
| 130 } | |
| 131 | |
| 132 LUnallocated* CopyUnconstrained(Zone* zone) { | |
| 133 LUnallocated* result = new(zone) LUnallocated(ANY); | |
| 134 result->set_virtual_register(virtual_register()); | |
| 135 return result; | |
| 136 } | |
| 137 | |
| 138 static LUnallocated* cast(LOperand* op) { | |
| 139 DCHECK(op->IsUnallocated()); | |
| 140 return reinterpret_cast<LUnallocated*>(op); | |
| 141 } | |
| 142 | |
| 143 // The encoding used for LUnallocated operands depends on the policy that is | |
| 144 // stored within the operand. The FIXED_SLOT policy uses a compact encoding | |
| 145 // because it accommodates a larger pay-load. | |
| 146 // | |
| 147 // For FIXED_SLOT policy: | |
| 148 // +------------------------------------------+ | |
| 149 // | slot_index | vreg | 0 | 001 | | |
| 150 // +------------------------------------------+ | |
| 151 // | |
| 152 // For all other (extended) policies: | |
| 153 // +------------------------------------------+ | |
| 154 // | reg_index | L | PPP | vreg | 1 | 001 | L ... Lifetime | |
| 155 // +------------------------------------------+ P ... Policy | |
| 156 // | |
| 157 // The slot index is a signed value which requires us to decode it manually | |
| 158 // instead of using the BitField utility class. | |
| 159 | |
| 160 // The superclass has a KindField. | |
| 161 STATIC_ASSERT(kKindFieldWidth == 3); | |
| 162 | |
| 163 // BitFields for all unallocated operands. | |
| 164 class BasicPolicyField : public BitField<BasicPolicy, 3, 1> {}; | |
| 165 class VirtualRegisterField : public BitField<unsigned, 4, 18> {}; | |
| 166 | |
| 167 // BitFields specific to BasicPolicy::FIXED_SLOT. | |
| 168 class FixedSlotIndexField : public BitField<int, 22, 10> {}; | |
| 169 | |
| 170 // BitFields specific to BasicPolicy::EXTENDED_POLICY. | |
| 171 class ExtendedPolicyField : public BitField<ExtendedPolicy, 22, 3> {}; | |
| 172 class LifetimeField : public BitField<Lifetime, 25, 1> {}; | |
| 173 class FixedRegisterField : public BitField<int, 26, 6> {}; | |
| 174 | |
| 175 static const int kMaxVirtualRegisters = VirtualRegisterField::kMax + 1; | |
| 176 static const int kFixedSlotIndexWidth = FixedSlotIndexField::kSize; | |
| 177 static const int kMaxFixedSlotIndex = (1 << (kFixedSlotIndexWidth - 1)) - 1; | |
| 178 static const int kMinFixedSlotIndex = -(1 << (kFixedSlotIndexWidth - 1)); | |
| 179 | |
| 180 // Predicates for the operand policy. | |
| 181 bool HasAnyPolicy() const { | |
| 182 return basic_policy() == EXTENDED_POLICY && | |
| 183 extended_policy() == ANY; | |
| 184 } | |
| 185 bool HasFixedPolicy() const { | |
| 186 return basic_policy() == FIXED_SLOT || | |
| 187 extended_policy() == FIXED_REGISTER || | |
| 188 extended_policy() == FIXED_DOUBLE_REGISTER; | |
| 189 } | |
| 190 bool HasRegisterPolicy() const { | |
| 191 return basic_policy() == EXTENDED_POLICY && ( | |
| 192 extended_policy() == WRITABLE_REGISTER || | |
| 193 extended_policy() == MUST_HAVE_REGISTER); | |
| 194 } | |
| 195 bool HasDoubleRegisterPolicy() const { | |
| 196 return basic_policy() == EXTENDED_POLICY && | |
| 197 extended_policy() == MUST_HAVE_DOUBLE_REGISTER; | |
| 198 } | |
| 199 bool HasSameAsInputPolicy() const { | |
| 200 return basic_policy() == EXTENDED_POLICY && | |
| 201 extended_policy() == SAME_AS_FIRST_INPUT; | |
| 202 } | |
| 203 bool HasFixedSlotPolicy() const { | |
| 204 return basic_policy() == FIXED_SLOT; | |
| 205 } | |
| 206 bool HasFixedRegisterPolicy() const { | |
| 207 return basic_policy() == EXTENDED_POLICY && | |
| 208 extended_policy() == FIXED_REGISTER; | |
| 209 } | |
| 210 bool HasFixedDoubleRegisterPolicy() const { | |
| 211 return basic_policy() == EXTENDED_POLICY && | |
| 212 extended_policy() == FIXED_DOUBLE_REGISTER; | |
| 213 } | |
| 214 bool HasWritableRegisterPolicy() const { | |
| 215 return basic_policy() == EXTENDED_POLICY && | |
| 216 extended_policy() == WRITABLE_REGISTER; | |
| 217 } | |
| 218 | |
| 219 // [basic_policy]: Distinguish between FIXED_SLOT and all other policies. | |
| 220 BasicPolicy basic_policy() const { | |
| 221 return BasicPolicyField::decode(value_); | |
| 222 } | |
| 223 | |
| 224 // [extended_policy]: Only for non-FIXED_SLOT. The finer-grained policy. | |
| 225 ExtendedPolicy extended_policy() const { | |
| 226 DCHECK(basic_policy() == EXTENDED_POLICY); | |
| 227 return ExtendedPolicyField::decode(value_); | |
| 228 } | |
| 229 | |
| 230 // [fixed_slot_index]: Only for FIXED_SLOT. | |
| 231 int fixed_slot_index() const { | |
| 232 DCHECK(HasFixedSlotPolicy()); | |
| 233 return static_cast<int>(value_) >> FixedSlotIndexField::kShift; | |
| 234 } | |
| 235 | |
| 236 // [fixed_register_index]: Only for FIXED_REGISTER or FIXED_DOUBLE_REGISTER. | |
| 237 int fixed_register_index() const { | |
| 238 DCHECK(HasFixedRegisterPolicy() || HasFixedDoubleRegisterPolicy()); | |
| 239 return FixedRegisterField::decode(value_); | |
| 240 } | |
| 241 | |
| 242 // [virtual_register]: The virtual register ID for this operand. | |
| 243 int virtual_register() const { | |
| 244 return VirtualRegisterField::decode(value_); | |
| 245 } | |
| 246 void set_virtual_register(unsigned id) { | |
| 247 value_ = VirtualRegisterField::update(value_, id); | |
| 248 } | |
| 249 | |
| 250 // [lifetime]: Only for non-FIXED_SLOT. | |
| 251 bool IsUsedAtStart() { | |
| 252 DCHECK(basic_policy() == EXTENDED_POLICY); | |
| 253 return LifetimeField::decode(value_) == USED_AT_START; | |
| 254 } | |
| 255 | |
| 256 static bool TooManyParameters(int num_parameters) { | |
| 257 const int parameter_limit = -LUnallocated::kMinFixedSlotIndex; | |
| 258 return num_parameters + 1 > parameter_limit; | |
| 259 } | |
| 260 | |
| 261 static bool TooManyParametersOrStackSlots(int num_parameters, | |
| 262 int num_stack_slots) { | |
| 263 const int locals_limit = LUnallocated::kMaxFixedSlotIndex; | |
| 264 return num_parameters + 1 + num_stack_slots > locals_limit; | |
| 265 } | |
| 266 }; | |
| 267 | |
| 268 | |
| 269 class LMoveOperands final BASE_EMBEDDED { | |
| 270 public: | |
| 271 LMoveOperands(LOperand* source, LOperand* destination) | |
| 272 : source_(source), destination_(destination) { | |
| 273 } | |
| 274 | |
| 275 LOperand* source() const { return source_; } | |
| 276 void set_source(LOperand* operand) { source_ = operand; } | |
| 277 | |
| 278 LOperand* destination() const { return destination_; } | |
| 279 void set_destination(LOperand* operand) { destination_ = operand; } | |
| 280 | |
| 281 // The gap resolver marks moves as "in-progress" by clearing the | |
| 282 // destination (but not the source). | |
| 283 bool IsPending() const { | |
| 284 return destination_ == NULL && source_ != NULL; | |
| 285 } | |
| 286 | |
| 287 // True if this move a move into the given destination operand. | |
| 288 bool Blocks(LOperand* operand) const { | |
| 289 return !IsEliminated() && source()->Equals(operand); | |
| 290 } | |
| 291 | |
| 292 // A move is redundant if it's been eliminated, if its source and | |
| 293 // destination are the same, or if its destination is unneeded or constant. | |
| 294 bool IsRedundant() const { | |
| 295 return IsEliminated() || source_->Equals(destination_) || IsIgnored() || | |
| 296 (destination_ != NULL && destination_->IsConstantOperand()); | |
| 297 } | |
| 298 | |
| 299 bool IsIgnored() const { | |
| 300 return destination_ != NULL && destination_->IsIgnored(); | |
| 301 } | |
| 302 | |
| 303 // We clear both operands to indicate move that's been eliminated. | |
| 304 void Eliminate() { source_ = destination_ = NULL; } | |
| 305 bool IsEliminated() const { | |
| 306 DCHECK(source_ != NULL || destination_ == NULL); | |
| 307 return source_ == NULL; | |
| 308 } | |
| 309 | |
| 310 private: | |
| 311 LOperand* source_; | |
| 312 LOperand* destination_; | |
| 313 }; | |
| 314 | |
| 315 | |
| 316 template <LOperand::Kind kOperandKind, int kNumCachedOperands> | |
| 317 class LSubKindOperand final : public LOperand { | |
| 318 public: | |
| 319 static LSubKindOperand* Create(int index, Zone* zone) { | |
| 320 DCHECK(index >= 0); | |
| 321 if (index < kNumCachedOperands) return &cache[index]; | |
| 322 return new(zone) LSubKindOperand(index); | |
| 323 } | |
| 324 | |
| 325 static LSubKindOperand* cast(LOperand* op) { | |
| 326 DCHECK(op->kind() == kOperandKind); | |
| 327 return reinterpret_cast<LSubKindOperand*>(op); | |
| 328 } | |
| 329 | |
| 330 static void SetUpCache(); | |
| 331 static void TearDownCache(); | |
| 332 | |
| 333 private: | |
| 334 static LSubKindOperand* cache; | |
| 335 | |
| 336 LSubKindOperand() : LOperand() { } | |
| 337 explicit LSubKindOperand(int index) : LOperand(kOperandKind, index) { } | |
| 338 }; | |
| 339 | |
| 340 | |
| 341 #define LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS(name, type, number) \ | |
| 342 typedef LSubKindOperand<LOperand::type, number> L##name; | |
| 343 LITHIUM_OPERAND_LIST(LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS) | |
| 344 #undef LITHIUM_TYPEDEF_SUBKIND_OPERAND_CLASS | |
| 345 | |
| 346 | |
| 347 class LParallelMove final : public ZoneObject { | |
| 348 public: | |
| 349 explicit LParallelMove(Zone* zone) : move_operands_(4, zone) { } | |
| 350 | |
| 351 void AddMove(LOperand* from, LOperand* to, Zone* zone) { | |
| 352 move_operands_.Add(LMoveOperands(from, to), zone); | |
| 353 } | |
| 354 | |
| 355 bool IsRedundant() const; | |
| 356 | |
| 357 ZoneList<LMoveOperands>* move_operands() { return &move_operands_; } | |
| 358 | |
| 359 void PrintDataTo(StringStream* stream) const; | |
| 360 | |
| 361 private: | |
| 362 ZoneList<LMoveOperands> move_operands_; | |
| 363 }; | |
| 364 | |
| 365 | |
| 366 class LPointerMap final : public ZoneObject { | |
| 367 public: | |
| 368 explicit LPointerMap(Zone* zone) | |
| 369 : pointer_operands_(8, zone), | |
| 370 untagged_operands_(0, zone), | |
| 371 lithium_position_(-1) { } | |
| 372 | |
| 373 const ZoneList<LOperand*>* GetNormalizedOperands() { | |
| 374 for (int i = 0; i < untagged_operands_.length(); ++i) { | |
| 375 RemovePointer(untagged_operands_[i]); | |
| 376 } | |
| 377 untagged_operands_.Clear(); | |
| 378 return &pointer_operands_; | |
| 379 } | |
| 380 int lithium_position() const { return lithium_position_; } | |
| 381 | |
| 382 void set_lithium_position(int pos) { | |
| 383 DCHECK(lithium_position_ == -1); | |
| 384 lithium_position_ = pos; | |
| 385 } | |
| 386 | |
| 387 void RecordPointer(LOperand* op, Zone* zone); | |
| 388 void RemovePointer(LOperand* op); | |
| 389 void RecordUntagged(LOperand* op, Zone* zone); | |
| 390 void PrintTo(StringStream* stream); | |
| 391 | |
| 392 private: | |
| 393 ZoneList<LOperand*> pointer_operands_; | |
| 394 ZoneList<LOperand*> untagged_operands_; | |
| 395 int lithium_position_; | |
| 396 }; | |
| 397 | |
| 398 | |
| 399 class LEnvironment final : public ZoneObject { | |
| 400 public: | |
| 401 LEnvironment(Handle<JSFunction> closure, | |
| 402 FrameType frame_type, | |
| 403 BailoutId ast_id, | |
| 404 int parameter_count, | |
| 405 int argument_count, | |
| 406 int value_count, | |
| 407 LEnvironment* outer, | |
| 408 HEnterInlined* entry, | |
| 409 Zone* zone) | |
| 410 : closure_(closure), | |
| 411 frame_type_(frame_type), | |
| 412 arguments_stack_height_(argument_count), | |
| 413 deoptimization_index_(Safepoint::kNoDeoptimizationIndex), | |
| 414 translation_index_(-1), | |
| 415 ast_id_(ast_id), | |
| 416 translation_size_(value_count), | |
| 417 parameter_count_(parameter_count), | |
| 418 pc_offset_(-1), | |
| 419 values_(value_count, zone), | |
| 420 is_tagged_(value_count, zone), | |
| 421 is_uint32_(value_count, zone), | |
| 422 object_mapping_(0, zone), | |
| 423 outer_(outer), | |
| 424 entry_(entry), | |
| 425 zone_(zone), | |
| 426 has_been_used_(false) { } | |
| 427 | |
| 428 Handle<JSFunction> closure() const { return closure_; } | |
| 429 FrameType frame_type() const { return frame_type_; } | |
| 430 int arguments_stack_height() const { return arguments_stack_height_; } | |
| 431 int deoptimization_index() const { return deoptimization_index_; } | |
| 432 int translation_index() const { return translation_index_; } | |
| 433 BailoutId ast_id() const { return ast_id_; } | |
| 434 int translation_size() const { return translation_size_; } | |
| 435 int parameter_count() const { return parameter_count_; } | |
| 436 int pc_offset() const { return pc_offset_; } | |
| 437 const ZoneList<LOperand*>* values() const { return &values_; } | |
| 438 LEnvironment* outer() const { return outer_; } | |
| 439 HEnterInlined* entry() { return entry_; } | |
| 440 Zone* zone() const { return zone_; } | |
| 441 | |
| 442 bool has_been_used() const { return has_been_used_; } | |
| 443 void set_has_been_used() { has_been_used_ = true; } | |
| 444 | |
| 445 void AddValue(LOperand* operand, | |
| 446 Representation representation, | |
| 447 bool is_uint32) { | |
| 448 values_.Add(operand, zone()); | |
| 449 if (representation.IsSmiOrTagged()) { | |
| 450 DCHECK(!is_uint32); | |
| 451 is_tagged_.Add(values_.length() - 1, zone()); | |
| 452 } | |
| 453 | |
| 454 if (is_uint32) { | |
| 455 is_uint32_.Add(values_.length() - 1, zone()); | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 bool HasTaggedValueAt(int index) const { | |
| 460 return is_tagged_.Contains(index); | |
| 461 } | |
| 462 | |
| 463 bool HasUint32ValueAt(int index) const { | |
| 464 return is_uint32_.Contains(index); | |
| 465 } | |
| 466 | |
| 467 void AddNewObject(int length, bool is_arguments) { | |
| 468 uint32_t encoded = LengthOrDupeField::encode(length) | | |
| 469 IsArgumentsField::encode(is_arguments) | | |
| 470 IsDuplicateField::encode(false); | |
| 471 object_mapping_.Add(encoded, zone()); | |
| 472 } | |
| 473 | |
| 474 void AddDuplicateObject(int dupe_of) { | |
| 475 uint32_t encoded = LengthOrDupeField::encode(dupe_of) | | |
| 476 IsDuplicateField::encode(true); | |
| 477 object_mapping_.Add(encoded, zone()); | |
| 478 } | |
| 479 | |
| 480 int ObjectDuplicateOfAt(int index) { | |
| 481 DCHECK(ObjectIsDuplicateAt(index)); | |
| 482 return LengthOrDupeField::decode(object_mapping_[index]); | |
| 483 } | |
| 484 | |
| 485 int ObjectLengthAt(int index) { | |
| 486 DCHECK(!ObjectIsDuplicateAt(index)); | |
| 487 return LengthOrDupeField::decode(object_mapping_[index]); | |
| 488 } | |
| 489 | |
| 490 bool ObjectIsArgumentsAt(int index) { | |
| 491 DCHECK(!ObjectIsDuplicateAt(index)); | |
| 492 return IsArgumentsField::decode(object_mapping_[index]); | |
| 493 } | |
| 494 | |
| 495 bool ObjectIsDuplicateAt(int index) { | |
| 496 return IsDuplicateField::decode(object_mapping_[index]); | |
| 497 } | |
| 498 | |
| 499 void Register(int deoptimization_index, | |
| 500 int translation_index, | |
| 501 int pc_offset) { | |
| 502 DCHECK(!HasBeenRegistered()); | |
| 503 deoptimization_index_ = deoptimization_index; | |
| 504 translation_index_ = translation_index; | |
| 505 pc_offset_ = pc_offset; | |
| 506 } | |
| 507 bool HasBeenRegistered() const { | |
| 508 return deoptimization_index_ != Safepoint::kNoDeoptimizationIndex; | |
| 509 } | |
| 510 | |
| 511 void PrintTo(StringStream* stream); | |
| 512 | |
| 513 // Marker value indicating a de-materialized object. | |
| 514 static LOperand* materialization_marker() { return NULL; } | |
| 515 | |
| 516 // Encoding used for the object_mapping map below. | |
| 517 class LengthOrDupeField : public BitField<int, 0, 30> { }; | |
| 518 class IsArgumentsField : public BitField<bool, 30, 1> { }; | |
| 519 class IsDuplicateField : public BitField<bool, 31, 1> { }; | |
| 520 | |
| 521 private: | |
| 522 Handle<JSFunction> closure_; | |
| 523 FrameType frame_type_; | |
| 524 int arguments_stack_height_; | |
| 525 int deoptimization_index_; | |
| 526 int translation_index_; | |
| 527 BailoutId ast_id_; | |
| 528 int translation_size_; | |
| 529 int parameter_count_; | |
| 530 int pc_offset_; | |
| 531 | |
| 532 // Value array: [parameters] [locals] [expression stack] [de-materialized]. | |
| 533 // |>--------- translation_size ---------<| | |
| 534 ZoneList<LOperand*> values_; | |
| 535 GrowableBitVector is_tagged_; | |
| 536 GrowableBitVector is_uint32_; | |
| 537 | |
| 538 // Map with encoded information about materialization_marker operands. | |
| 539 ZoneList<uint32_t> object_mapping_; | |
| 540 | |
| 541 LEnvironment* outer_; | |
| 542 HEnterInlined* entry_; | |
| 543 Zone* zone_; | |
| 544 bool has_been_used_; | |
| 545 }; | |
| 546 | |
| 547 | |
| 548 // Iterates over the non-null, non-constant operands in an environment. | |
| 549 class ShallowIterator final BASE_EMBEDDED { | |
| 550 public: | |
| 551 explicit ShallowIterator(LEnvironment* env) | |
| 552 : env_(env), | |
| 553 limit_(env != NULL ? env->values()->length() : 0), | |
| 554 current_(0) { | |
| 555 SkipUninteresting(); | |
| 556 } | |
| 557 | |
| 558 bool Done() { return current_ >= limit_; } | |
| 559 | |
| 560 LOperand* Current() { | |
| 561 DCHECK(!Done()); | |
| 562 DCHECK(env_->values()->at(current_) != NULL); | |
| 563 return env_->values()->at(current_); | |
| 564 } | |
| 565 | |
| 566 void Advance() { | |
| 567 DCHECK(!Done()); | |
| 568 ++current_; | |
| 569 SkipUninteresting(); | |
| 570 } | |
| 571 | |
| 572 LEnvironment* env() { return env_; } | |
| 573 | |
| 574 private: | |
| 575 bool ShouldSkip(LOperand* op) { | |
| 576 return op == NULL || op->IsConstantOperand(); | |
| 577 } | |
| 578 | |
| 579 // Skip until something interesting, beginning with and including current_. | |
| 580 void SkipUninteresting() { | |
| 581 while (current_ < limit_ && ShouldSkip(env_->values()->at(current_))) { | |
| 582 ++current_; | |
| 583 } | |
| 584 } | |
| 585 | |
| 586 LEnvironment* env_; | |
| 587 int limit_; | |
| 588 int current_; | |
| 589 }; | |
| 590 | |
| 591 | |
| 592 // Iterator for non-null, non-constant operands incl. outer environments. | |
| 593 class DeepIterator final BASE_EMBEDDED { | |
| 594 public: | |
| 595 explicit DeepIterator(LEnvironment* env) | |
| 596 : current_iterator_(env) { | |
| 597 SkipUninteresting(); | |
| 598 } | |
| 599 | |
| 600 bool Done() { return current_iterator_.Done(); } | |
| 601 | |
| 602 LOperand* Current() { | |
| 603 DCHECK(!current_iterator_.Done()); | |
| 604 DCHECK(current_iterator_.Current() != NULL); | |
| 605 return current_iterator_.Current(); | |
| 606 } | |
| 607 | |
| 608 void Advance() { | |
| 609 current_iterator_.Advance(); | |
| 610 SkipUninteresting(); | |
| 611 } | |
| 612 | |
| 613 private: | |
| 614 void SkipUninteresting() { | |
| 615 while (current_iterator_.env() != NULL && current_iterator_.Done()) { | |
| 616 current_iterator_ = ShallowIterator(current_iterator_.env()->outer()); | |
| 617 } | |
| 618 } | |
| 619 | |
| 620 ShallowIterator current_iterator_; | |
| 621 }; | |
| 622 | |
| 623 | |
| 624 class LPlatformChunk; | |
| 625 class LGap; | |
| 626 class LLabel; | |
| 627 | |
| 628 // Superclass providing data and behavior common to all the | |
| 629 // arch-specific LPlatformChunk classes. | |
| 630 class LChunk : public ZoneObject { | |
| 631 public: | |
| 632 static LChunk* NewChunk(HGraph* graph); | |
| 633 | |
| 634 void AddInstruction(LInstruction* instruction, HBasicBlock* block); | |
| 635 LConstantOperand* DefineConstantOperand(HConstant* constant); | |
| 636 HConstant* LookupConstant(LConstantOperand* operand) const; | |
| 637 Representation LookupLiteralRepresentation(LConstantOperand* operand) const; | |
| 638 | |
| 639 int ParameterAt(int index); | |
| 640 int GetParameterStackSlot(int index) const; | |
| 641 int spill_slot_count() const { return spill_slot_count_; } | |
| 642 CompilationInfo* info() const { return info_; } | |
| 643 HGraph* graph() const { return graph_; } | |
| 644 Isolate* isolate() const { return graph_->isolate(); } | |
| 645 const ZoneList<LInstruction*>* instructions() const { return &instructions_; } | |
| 646 void AddGapMove(int index, LOperand* from, LOperand* to); | |
| 647 LGap* GetGapAt(int index) const; | |
| 648 bool IsGapAt(int index) const; | |
| 649 int NearestGapPos(int index) const; | |
| 650 void MarkEmptyBlocks(); | |
| 651 const ZoneList<LPointerMap*>* pointer_maps() const { return &pointer_maps_; } | |
| 652 LLabel* GetLabel(int block_id) const; | |
| 653 int LookupDestination(int block_id) const; | |
| 654 Label* GetAssemblyLabel(int block_id) const; | |
| 655 | |
| 656 const ZoneList<Handle<SharedFunctionInfo>>& inlined_functions() const { | |
| 657 return inlined_functions_; | |
| 658 } | |
| 659 | |
| 660 void AddInlinedFunction(Handle<SharedFunctionInfo> closure) { | |
| 661 inlined_functions_.Add(closure, zone()); | |
| 662 } | |
| 663 | |
| 664 void AddDeprecationDependency(Handle<Map> map) { | |
| 665 DCHECK(!map->is_deprecated()); | |
| 666 if (!map->CanBeDeprecated()) return; | |
| 667 DCHECK(!info_->IsStub()); | |
| 668 deprecation_dependencies_.Add(map, zone()); | |
| 669 } | |
| 670 | |
| 671 void AddStabilityDependency(Handle<Map> map) { | |
| 672 DCHECK(map->is_stable()); | |
| 673 if (!map->CanTransition()) return; | |
| 674 DCHECK(!info_->IsStub()); | |
| 675 stability_dependencies_.Add(map, zone()); | |
| 676 } | |
| 677 | |
| 678 Zone* zone() const { return info_->zone(); } | |
| 679 | |
| 680 Handle<Code> Codegen(); | |
| 681 | |
| 682 void set_allocated_double_registers(BitVector* allocated_registers); | |
| 683 BitVector* allocated_double_registers() { | |
| 684 return allocated_double_registers_; | |
| 685 } | |
| 686 | |
| 687 protected: | |
| 688 LChunk(CompilationInfo* info, HGraph* graph); | |
| 689 | |
| 690 int spill_slot_count_; | |
| 691 | |
| 692 private: | |
| 693 void RegisterWeakObjectsInOptimizedCode(Handle<Code> code) const; | |
| 694 void CommitDependencies(Handle<Code> code) const; | |
| 695 | |
| 696 CompilationInfo* info_; | |
| 697 HGraph* const graph_; | |
| 698 BitVector* allocated_double_registers_; | |
| 699 ZoneList<LInstruction*> instructions_; | |
| 700 ZoneList<LPointerMap*> pointer_maps_; | |
| 701 ZoneList<Handle<SharedFunctionInfo>> inlined_functions_; | |
| 702 ZoneList<Handle<Map>> deprecation_dependencies_; | |
| 703 ZoneList<Handle<Map>> stability_dependencies_; | |
| 704 }; | |
| 705 | |
| 706 | |
| 707 class LChunkBuilderBase BASE_EMBEDDED { | |
| 708 public: | |
| 709 explicit LChunkBuilderBase(CompilationInfo* info, HGraph* graph) | |
| 710 : argument_count_(0), | |
| 711 chunk_(NULL), | |
| 712 info_(info), | |
| 713 graph_(graph), | |
| 714 status_(UNUSED), | |
| 715 zone_(graph->zone()) {} | |
| 716 | |
| 717 virtual ~LChunkBuilderBase() { } | |
| 718 | |
| 719 void Abort(BailoutReason reason); | |
| 720 void Retry(BailoutReason reason); | |
| 721 | |
| 722 protected: | |
| 723 enum Status { UNUSED, BUILDING, DONE, ABORTED }; | |
| 724 | |
| 725 LPlatformChunk* chunk() const { return chunk_; } | |
| 726 CompilationInfo* info() const { return info_; } | |
| 727 HGraph* graph() const { return graph_; } | |
| 728 int argument_count() const { return argument_count_; } | |
| 729 Isolate* isolate() const { return graph_->isolate(); } | |
| 730 Heap* heap() const { return isolate()->heap(); } | |
| 731 | |
| 732 bool is_unused() const { return status_ == UNUSED; } | |
| 733 bool is_building() const { return status_ == BUILDING; } | |
| 734 bool is_done() const { return status_ == DONE; } | |
| 735 bool is_aborted() const { return status_ == ABORTED; } | |
| 736 | |
| 737 // An input operand in register, stack slot or a constant operand. | |
| 738 // Will not be moved to a register even if one is freely available. | |
| 739 virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0; | |
| 740 | |
| 741 LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env, | |
| 742 int* argument_index_accumulator, | |
| 743 ZoneList<HValue*>* objects_to_materialize); | |
| 744 void AddObjectToMaterialize(HValue* value, | |
| 745 ZoneList<HValue*>* objects_to_materialize, | |
| 746 LEnvironment* result); | |
| 747 | |
| 748 Zone* zone() const { return zone_; } | |
| 749 | |
| 750 int argument_count_; | |
| 751 LPlatformChunk* chunk_; | |
| 752 CompilationInfo* info_; | |
| 753 HGraph* const graph_; | |
| 754 Status status_; | |
| 755 | |
| 756 private: | |
| 757 Zone* zone_; | |
| 758 }; | |
| 759 | |
| 760 | |
| 761 int StackSlotOffset(int index); | |
| 762 | |
| 763 enum NumberUntagDMode { | |
| 764 NUMBER_CANDIDATE_IS_SMI, | |
| 765 NUMBER_CANDIDATE_IS_ANY_TAGGED | |
| 766 }; | |
| 767 | |
| 768 | |
| 769 class LPhase : public CompilationPhase { | |
| 770 public: | |
| 771 LPhase(const char* name, LChunk* chunk) | |
| 772 : CompilationPhase(name, chunk->info()), | |
| 773 chunk_(chunk) { } | |
| 774 ~LPhase(); | |
| 775 | |
| 776 private: | |
| 777 LChunk* chunk_; | |
| 778 | |
| 779 DISALLOW_COPY_AND_ASSIGN(LPhase); | |
| 780 }; | |
| 781 | |
| 782 | |
| 783 // A register-allocator view of a Lithium instruction. It contains the id of | |
| 784 // the output operand and a list of input operand uses. | |
| 785 | |
| 786 enum RegisterKind { | |
| 787 UNALLOCATED_REGISTERS, | |
| 788 GENERAL_REGISTERS, | |
| 789 DOUBLE_REGISTERS | |
| 790 }; | |
| 791 | |
| 792 // Iterator for non-null temp operands. | |
| 793 class TempIterator BASE_EMBEDDED { | |
| 794 public: | |
| 795 inline explicit TempIterator(LInstruction* instr); | |
| 796 inline bool Done(); | |
| 797 inline LOperand* Current(); | |
| 798 inline void Advance(); | |
| 799 | |
| 800 private: | |
| 801 inline void SkipUninteresting(); | |
| 802 LInstruction* instr_; | |
| 803 int limit_; | |
| 804 int current_; | |
| 805 }; | |
| 806 | |
| 807 | |
| 808 // Iterator for non-constant input operands. | |
| 809 class InputIterator BASE_EMBEDDED { | |
| 810 public: | |
| 811 inline explicit InputIterator(LInstruction* instr); | |
| 812 inline bool Done(); | |
| 813 inline LOperand* Current(); | |
| 814 inline void Advance(); | |
| 815 | |
| 816 private: | |
| 817 inline void SkipUninteresting(); | |
| 818 LInstruction* instr_; | |
| 819 int limit_; | |
| 820 int current_; | |
| 821 }; | |
| 822 | |
| 823 | |
| 824 class UseIterator BASE_EMBEDDED { | |
| 825 public: | |
| 826 inline explicit UseIterator(LInstruction* instr); | |
| 827 inline bool Done(); | |
| 828 inline LOperand* Current(); | |
| 829 inline void Advance(); | |
| 830 | |
| 831 private: | |
| 832 InputIterator input_iterator_; | |
| 833 DeepIterator env_iterator_; | |
| 834 }; | |
| 835 | |
| 836 class LInstruction; | |
| 837 class LCodeGen; | |
| 838 } // namespace internal | |
| 839 } // namespace v8 | |
| 840 | |
| 841 #endif // V8_LITHIUM_H_ | |
| OLD | NEW |