| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2010 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 "factory.h" |
| 31 #include "hydrogen.h" |
| 32 |
| 33 #if V8_TARGET_ARCH_IA32 |
| 34 #include "ia32/lithium-ia32.h" |
| 35 #elif V8_TARGET_ARCH_X64 |
| 36 #include "x64/lithium-x64.h" |
| 37 #elif V8_TARGET_ARCH_ARM |
| 38 #include "arm/lithium-arm.h" |
| 39 #else |
| 40 #error Unsupported target architecture. |
| 41 #endif |
| 42 |
| 43 namespace v8 { |
| 44 namespace internal { |
| 45 |
| 46 #define DEFINE_COMPILE(type) \ |
| 47 LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \ |
| 48 return builder->Do##type(this); \ |
| 49 } |
| 50 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) |
| 51 #undef DEFINE_COMPILE |
| 52 |
| 53 |
| 54 const char* Representation::Mnemonic() const { |
| 55 switch (kind_) { |
| 56 case kNone: return "v"; |
| 57 case kTagged: return "t"; |
| 58 case kDouble: return "d"; |
| 59 case kInteger32: return "i"; |
| 60 default: |
| 61 UNREACHABLE(); |
| 62 return NULL; |
| 63 } |
| 64 } |
| 65 |
| 66 |
| 67 static int32_t AddAssertNoOverflow(int32_t a, int32_t b) { |
| 68 ASSERT(static_cast<int64_t>(a + b) == (static_cast<int64_t>(a) + |
| 69 static_cast<int64_t>(b))); |
| 70 return a + b; |
| 71 } |
| 72 |
| 73 |
| 74 static int32_t SubAssertNoOverflow(int32_t a, int32_t b) { |
| 75 ASSERT(static_cast<int64_t>(a - b) == (static_cast<int64_t>(a) - |
| 76 static_cast<int64_t>(b))); |
| 77 return a - b; |
| 78 } |
| 79 |
| 80 |
| 81 static int32_t MulAssertNoOverflow(int32_t a, int32_t b) { |
| 82 ASSERT(static_cast<int64_t>(a * b) == (static_cast<int64_t>(a) * |
| 83 static_cast<int64_t>(b))); |
| 84 return a * b; |
| 85 } |
| 86 |
| 87 |
| 88 static int32_t AddWithoutOverflow(int32_t a, int32_t b) { |
| 89 if (b > 0) { |
| 90 if (a <= kMaxInt - b) return AddAssertNoOverflow(a, b); |
| 91 return kMaxInt; |
| 92 } else { |
| 93 if (a >= kMinInt - b) return AddAssertNoOverflow(a, b); |
| 94 return kMinInt; |
| 95 } |
| 96 } |
| 97 |
| 98 |
| 99 static int32_t SubWithoutOverflow(int32_t a, int32_t b) { |
| 100 if (b < 0) { |
| 101 if (a <= kMaxInt + b) return SubAssertNoOverflow(a, b); |
| 102 return kMaxInt; |
| 103 } else { |
| 104 if (a >= kMinInt + b) return SubAssertNoOverflow(a, b); |
| 105 return kMinInt; |
| 106 } |
| 107 } |
| 108 |
| 109 |
| 110 static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) { |
| 111 if (b == 0 || a == 0) return 0; |
| 112 if (a == 1) return b; |
| 113 if (b == 1) return a; |
| 114 |
| 115 int sign = 1; |
| 116 if ((a < 0 && b > 0) || (a > 0 && b < 0)) sign = -1; |
| 117 if (a < 0) a = -a; |
| 118 if (b < 0) b = -b; |
| 119 |
| 120 if (kMaxInt / b > a && a != kMinInt && b != kMinInt) { |
| 121 return MulAssertNoOverflow(a, b) * sign; |
| 122 } |
| 123 |
| 124 *overflow = true; |
| 125 if (sign == 1) { |
| 126 return kMaxInt; |
| 127 } else { |
| 128 return kMinInt; |
| 129 } |
| 130 } |
| 131 |
| 132 |
| 133 int32_t Range::Mask() const { |
| 134 if (lower_ == upper_) return lower_; |
| 135 if (lower_ >= 0) { |
| 136 int32_t res = 1; |
| 137 while (res < upper_) { |
| 138 res = (res << 1) | 1; |
| 139 } |
| 140 return res; |
| 141 } |
| 142 return 0xffffffff; |
| 143 } |
| 144 |
| 145 |
| 146 void Range::Add(int32_t value) { |
| 147 if (value == 0) return; |
| 148 lower_ = AddWithoutOverflow(lower_, value); |
| 149 upper_ = AddWithoutOverflow(upper_, value); |
| 150 Verify(); |
| 151 } |
| 152 |
| 153 |
| 154 // Returns whether the add may overflow. |
| 155 bool Range::AddAndCheckOverflow(Range* other) { |
| 156 int old_lower = lower_; |
| 157 int old_upper = upper_; |
| 158 lower_ = AddWithoutOverflow(lower_, other->lower()); |
| 159 upper_ = AddWithoutOverflow(upper_, other->upper()); |
| 160 bool r = (old_lower + other->lower() != lower_ || |
| 161 old_upper + other->upper() != upper_); |
| 162 KeepOrder(); |
| 163 Verify(); |
| 164 return r; |
| 165 } |
| 166 |
| 167 |
| 168 // Returns whether the sub may overflow. |
| 169 bool Range::SubAndCheckOverflow(Range* other) { |
| 170 int old_lower = lower_; |
| 171 int old_upper = upper_; |
| 172 lower_ = SubWithoutOverflow(lower_, other->lower()); |
| 173 upper_ = SubWithoutOverflow(upper_, other->upper()); |
| 174 bool r = (old_lower - other->lower() != lower_ || |
| 175 old_upper - other->upper() != upper_); |
| 176 KeepOrder(); |
| 177 Verify(); |
| 178 return r; |
| 179 } |
| 180 |
| 181 |
| 182 void Range::KeepOrder() { |
| 183 if (lower_ > upper_) { |
| 184 int32_t tmp = lower_; |
| 185 lower_ = upper_; |
| 186 upper_ = tmp; |
| 187 } |
| 188 } |
| 189 |
| 190 |
| 191 void Range::Verify() const { |
| 192 ASSERT(lower_ <= upper_); |
| 193 } |
| 194 |
| 195 |
| 196 // Returns whether the mul may overflow. |
| 197 bool Range::MulAndCheckOverflow(Range* other) { |
| 198 bool may_overflow = false; |
| 199 int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow); |
| 200 int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow); |
| 201 int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow); |
| 202 int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow); |
| 203 lower_ = Min(Min(v1, v2), Min(v3, v4)); |
| 204 upper_ = Max(Max(v1, v2), Max(v3, v4)); |
| 205 Verify(); |
| 206 return may_overflow; |
| 207 } |
| 208 |
| 209 |
| 210 const char* HType::ToString() { |
| 211 switch (type_) { |
| 212 case kTagged: return "tagged"; |
| 213 case kTaggedPrimitive: return "primitive"; |
| 214 case kTaggedNumber: return "number"; |
| 215 case kSmi: return "smi"; |
| 216 case kHeapNumber: return "heap-number"; |
| 217 case kString: return "string"; |
| 218 case kBoolean: return "boolean"; |
| 219 case kNonPrimitive: return "non-primitive"; |
| 220 case kJSArray: return "array"; |
| 221 case kJSObject: return "object"; |
| 222 case kUninitialized: return "uninitialized"; |
| 223 } |
| 224 UNREACHABLE(); |
| 225 return "Unreachable code"; |
| 226 } |
| 227 |
| 228 |
| 229 const char* HType::ToShortString() { |
| 230 switch (type_) { |
| 231 case kTagged: return "t"; |
| 232 case kTaggedPrimitive: return "p"; |
| 233 case kTaggedNumber: return "n"; |
| 234 case kSmi: return "m"; |
| 235 case kHeapNumber: return "h"; |
| 236 case kString: return "s"; |
| 237 case kBoolean: return "b"; |
| 238 case kNonPrimitive: return "r"; |
| 239 case kJSArray: return "a"; |
| 240 case kJSObject: return "o"; |
| 241 case kUninitialized: return "z"; |
| 242 } |
| 243 UNREACHABLE(); |
| 244 return "Unreachable code"; |
| 245 } |
| 246 |
| 247 |
| 248 HType HType::TypeFromValue(Handle<Object> value) { |
| 249 HType result = HType::Tagged(); |
| 250 if (value->IsSmi()) { |
| 251 result = HType::Smi(); |
| 252 } else if (value->IsHeapNumber()) { |
| 253 result = HType::HeapNumber(); |
| 254 } else if (value->IsString()) { |
| 255 result = HType::String(); |
| 256 } else if (value->IsBoolean()) { |
| 257 result = HType::Boolean(); |
| 258 } else if (value->IsJSObject()) { |
| 259 result = HType::JSObject(); |
| 260 } else if (value->IsJSArray()) { |
| 261 result = HType::JSArray(); |
| 262 } |
| 263 return result; |
| 264 } |
| 265 |
| 266 |
| 267 int HValue::LookupOperandIndex(int occurrence_index, HValue* op) const { |
| 268 for (int i = 0; i < OperandCount(); ++i) { |
| 269 if (OperandAt(i) == op) { |
| 270 if (occurrence_index == 0) return i; |
| 271 --occurrence_index; |
| 272 } |
| 273 } |
| 274 return -1; |
| 275 } |
| 276 |
| 277 |
| 278 bool HValue::IsDefinedAfter(HBasicBlock* other) const { |
| 279 return block()->block_id() > other->block_id(); |
| 280 } |
| 281 |
| 282 |
| 283 bool HValue::UsesMultipleTimes(HValue* op) const { |
| 284 bool seen = false; |
| 285 for (int i = 0; i < OperandCount(); ++i) { |
| 286 if (OperandAt(i) == op) { |
| 287 if (seen) return true; |
| 288 seen = true; |
| 289 } |
| 290 } |
| 291 return false; |
| 292 } |
| 293 |
| 294 |
| 295 bool HValue::Equals(HValue* other) const { |
| 296 if (other->opcode() != opcode()) return false; |
| 297 if (!other->representation().Equals(representation())) return false; |
| 298 if (!other->type_.Equals(type_)) return false; |
| 299 if (OperandCount() != other->OperandCount()) return false; |
| 300 for (int i = 0; i < OperandCount(); ++i) { |
| 301 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false; |
| 302 } |
| 303 bool result = DataEquals(other); |
| 304 ASSERT(!result || Hashcode() == other->Hashcode()); |
| 305 return result; |
| 306 } |
| 307 |
| 308 |
| 309 intptr_t HValue::Hashcode() const { |
| 310 intptr_t result = opcode(); |
| 311 int count = OperandCount(); |
| 312 for (int i = 0; i < count; ++i) { |
| 313 result = result * 19 + OperandAt(i)->id() + (result >> 7); |
| 314 } |
| 315 return result; |
| 316 } |
| 317 |
| 318 |
| 319 void HValue::SetOperandAt(int index, HValue* value) { |
| 320 ASSERT(value == NULL || !value->representation().IsNone()); |
| 321 RegisterUse(index, value); |
| 322 InternalSetOperandAt(index, value); |
| 323 } |
| 324 |
| 325 |
| 326 void HValue::ReplaceAndDelete(HValue* other) { |
| 327 ReplaceValue(other); |
| 328 Delete(); |
| 329 } |
| 330 |
| 331 |
| 332 void HValue::ReplaceValue(HValue* other) { |
| 333 ZoneList<HValue*> start_uses(2); |
| 334 for (int i = 0; i < uses_.length(); ++i) { |
| 335 HValue* use = uses_.at(i); |
| 336 if (!use->block()->IsStartBlock()) { |
| 337 InternalReplaceAtUse(use, other); |
| 338 other->uses_.Add(use); |
| 339 } else { |
| 340 start_uses.Add(use); |
| 341 } |
| 342 } |
| 343 uses_.Clear(); |
| 344 uses_.AddAll(start_uses); |
| 345 } |
| 346 |
| 347 |
| 348 void HValue::ClearOperands() { |
| 349 for (int i = 0; i < OperandCount(); ++i) { |
| 350 SetOperandAt(i, NULL); |
| 351 } |
| 352 } |
| 353 |
| 354 |
| 355 void HValue::Delete() { |
| 356 ASSERT(HasNoUses()); |
| 357 ClearOperands(); |
| 358 DeleteFromGraph(); |
| 359 } |
| 360 |
| 361 |
| 362 void HValue::ReplaceAtUse(HValue* use, HValue* other) { |
| 363 for (int i = 0; i < use->OperandCount(); ++i) { |
| 364 if (use->OperandAt(i) == this) { |
| 365 use->SetOperandAt(i, other); |
| 366 } |
| 367 } |
| 368 } |
| 369 |
| 370 |
| 371 void HValue::ReplaceFirstAtUse(HValue* use, HValue* other, Representation r) { |
| 372 for (int i = 0; i < use->OperandCount(); ++i) { |
| 373 if (use->RequiredInputRepresentation(i).Equals(r) && |
| 374 use->OperandAt(i) == this) { |
| 375 use->SetOperandAt(i, other); |
| 376 return; |
| 377 } |
| 378 } |
| 379 } |
| 380 |
| 381 |
| 382 void HValue::InternalReplaceAtUse(HValue* use, HValue* other) { |
| 383 for (int i = 0; i < use->OperandCount(); ++i) { |
| 384 if (use->OperandAt(i) == this) { |
| 385 // Call internal method that does not update use lists. The caller is |
| 386 // responsible for doing so. |
| 387 use->InternalSetOperandAt(i, other); |
| 388 } |
| 389 } |
| 390 } |
| 391 |
| 392 |
| 393 void HValue::SetBlock(HBasicBlock* block) { |
| 394 ASSERT(block_ == NULL || block == NULL); |
| 395 block_ = block; |
| 396 if (id_ == kNoNumber && block != NULL) { |
| 397 id_ = block->graph()->GetNextValueID(this); |
| 398 } |
| 399 } |
| 400 |
| 401 |
| 402 void HValue::PrintTypeTo(HType type, StringStream* stream) { |
| 403 stream->Add(type.ToShortString()); |
| 404 } |
| 405 |
| 406 |
| 407 void HValue::PrintNameTo(StringStream* stream) { |
| 408 stream->Add("%s%d", representation_.Mnemonic(), id()); |
| 409 } |
| 410 |
| 411 |
| 412 bool HValue::UpdateInferredType() { |
| 413 HType type = CalculateInferredType(); |
| 414 bool result = (!type.Equals(type_)); |
| 415 type_ = type; |
| 416 return result; |
| 417 } |
| 418 |
| 419 |
| 420 void HValue::RegisterUse(int index, HValue* new_value) { |
| 421 HValue* old_value = OperandAt(index); |
| 422 if (old_value == new_value) return; |
| 423 if (old_value != NULL) { |
| 424 ASSERT(old_value->uses_.Contains(this)); |
| 425 old_value->uses_.RemoveElement(this); |
| 426 } |
| 427 if (new_value != NULL) { |
| 428 new_value->uses_.Add(this); |
| 429 } |
| 430 } |
| 431 |
| 432 |
| 433 void HValue::AddNewRange(Range* r) { |
| 434 if (!HasRange()) ComputeInitialRange(); |
| 435 if (!HasRange()) range_ = new Range(); |
| 436 ASSERT(HasRange()); |
| 437 r->StackUpon(range_); |
| 438 range_ = r; |
| 439 } |
| 440 |
| 441 |
| 442 void HValue::RemoveLastAddedRange() { |
| 443 ASSERT(HasRange()); |
| 444 ASSERT(range_->next() != NULL); |
| 445 range_ = range_->next(); |
| 446 } |
| 447 |
| 448 |
| 449 void HValue::ComputeInitialRange() { |
| 450 ASSERT(!HasRange()); |
| 451 range_ = InferRange(); |
| 452 ASSERT(HasRange()); |
| 453 } |
| 454 |
| 455 |
| 456 void HInstruction::PrintTo(StringStream* stream) const { |
| 457 stream->Add("%s", Mnemonic()); |
| 458 if (HasSideEffects()) stream->Add("*"); |
| 459 stream->Add(" "); |
| 460 PrintDataTo(stream); |
| 461 |
| 462 if (range() != NULL) { |
| 463 stream->Add(" range[%d,%d,m0=%d]", |
| 464 range()->lower(), |
| 465 range()->upper(), |
| 466 static_cast<int>(range()->CanBeMinusZero())); |
| 467 } |
| 468 |
| 469 int changes_flags = (flags() & HValue::ChangesFlagsMask()); |
| 470 if (changes_flags != 0) { |
| 471 stream->Add(" changes[0x%x]", changes_flags); |
| 472 } |
| 473 |
| 474 if (representation().IsTagged() && !type().Equals(HType::Tagged())) { |
| 475 stream->Add(" type[%s]", type().ToString()); |
| 476 } |
| 477 } |
| 478 |
| 479 |
| 480 void HInstruction::Unlink() { |
| 481 ASSERT(IsLinked()); |
| 482 ASSERT(!IsControlInstruction()); // Must never move control instructions. |
| 483 clear_block(); |
| 484 if (previous_ != NULL) previous_->next_ = next_; |
| 485 if (next_ != NULL) next_->previous_ = previous_; |
| 486 } |
| 487 |
| 488 |
| 489 void HInstruction::InsertBefore(HInstruction* next) { |
| 490 ASSERT(!IsLinked()); |
| 491 ASSERT(!next->IsBlockEntry()); |
| 492 ASSERT(!IsControlInstruction()); |
| 493 ASSERT(!next->block()->IsStartBlock()); |
| 494 ASSERT(next->previous_ != NULL); |
| 495 HInstruction* prev = next->previous(); |
| 496 prev->next_ = this; |
| 497 next->previous_ = this; |
| 498 next_ = next; |
| 499 previous_ = prev; |
| 500 SetBlock(next->block()); |
| 501 } |
| 502 |
| 503 |
| 504 void HInstruction::InsertAfter(HInstruction* previous) { |
| 505 ASSERT(!IsLinked()); |
| 506 ASSERT(!previous->IsControlInstruction()); |
| 507 ASSERT(!IsControlInstruction() || previous->next_ == NULL); |
| 508 HBasicBlock* block = previous->block(); |
| 509 // Never insert anything except constants into the start block after finishing |
| 510 // it. |
| 511 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) { |
| 512 ASSERT(block->end()->SecondSuccessor() == NULL); |
| 513 InsertAfter(block->end()->FirstSuccessor()->first()); |
| 514 return; |
| 515 } |
| 516 |
| 517 // If we're inserting after an instruction with side-effects that is |
| 518 // followed by a simulate instruction, we need to insert after the |
| 519 // simulate instruction instead. |
| 520 HInstruction* next = previous->next_; |
| 521 if (previous->HasSideEffects() && next != NULL) { |
| 522 ASSERT(next->IsSimulate()); |
| 523 previous = next; |
| 524 next = previous->next_; |
| 525 } |
| 526 |
| 527 previous_ = previous; |
| 528 next_ = next; |
| 529 SetBlock(block); |
| 530 previous->next_ = this; |
| 531 if (next != NULL) next->previous_ = this; |
| 532 } |
| 533 |
| 534 |
| 535 #ifdef DEBUG |
| 536 void HInstruction::Verify() const { |
| 537 // Verify that input operands are defined before use. |
| 538 HBasicBlock* cur_block = block(); |
| 539 for (int i = 0; i < OperandCount(); ++i) { |
| 540 HValue* other_operand = OperandAt(i); |
| 541 HBasicBlock* other_block = other_operand->block(); |
| 542 if (cur_block == other_block) { |
| 543 if (!other_operand->IsPhi()) { |
| 544 HInstruction* cur = cur_block->first(); |
| 545 while (cur != NULL) { |
| 546 ASSERT(cur != this); // We should reach other_operand before! |
| 547 if (cur == other_operand) break; |
| 548 cur = cur->next(); |
| 549 } |
| 550 // Must reach other operand in the same block! |
| 551 ASSERT(cur == other_operand); |
| 552 } |
| 553 } else { |
| 554 ASSERT(other_block->Dominates(cur_block)); |
| 555 } |
| 556 } |
| 557 |
| 558 // Verify that instructions that may have side-effects are followed |
| 559 // by a simulate instruction. |
| 560 if (HasSideEffects() && !IsOsrEntry()) { |
| 561 ASSERT(next()->IsSimulate()); |
| 562 } |
| 563 } |
| 564 #endif |
| 565 |
| 566 |
| 567 HCall::HCall(int count) : arguments_(ZONE->NewArray<HValue*>(count), count) { |
| 568 for (int i = 0; i < count; ++i) arguments_[i] = NULL; |
| 569 set_representation(Representation::Tagged()); |
| 570 SetFlagMask(AllSideEffects()); |
| 571 } |
| 572 |
| 573 |
| 574 void HCall::PrintDataTo(StringStream* stream) const { |
| 575 stream->Add("("); |
| 576 for (int i = 0; i < arguments_.length(); ++i) { |
| 577 if (i != 0) stream->Add(", "); |
| 578 arguments_.at(i)->PrintNameTo(stream); |
| 579 } |
| 580 stream->Add(")"); |
| 581 } |
| 582 |
| 583 |
| 584 void HClassOfTest::PrintDataTo(StringStream* stream) const { |
| 585 stream->Add("class_of_test("); |
| 586 value()->PrintTo(stream); |
| 587 stream->Add(", \"%o\")", *class_name()); |
| 588 } |
| 589 |
| 590 |
| 591 void HAccessArgumentsAt::PrintDataTo(StringStream* stream) const { |
| 592 arguments()->PrintNameTo(stream); |
| 593 stream->Add("["); |
| 594 index()->PrintNameTo(stream); |
| 595 stream->Add("], length "); |
| 596 length()->PrintNameTo(stream); |
| 597 } |
| 598 |
| 599 |
| 600 void HCall::SetArgumentAt(int index, HPushArgument* push_argument) { |
| 601 push_argument->set_argument_index(index); |
| 602 SetOperandAt(index, push_argument); |
| 603 } |
| 604 |
| 605 |
| 606 void HCallConstantFunction::PrintDataTo(StringStream* stream) const { |
| 607 if (IsApplyFunction()) { |
| 608 stream->Add("SPECIAL function: apply"); |
| 609 } else { |
| 610 stream->Add("%s", *(function()->shared()->DebugName()->ToCString())); |
| 611 } |
| 612 HCall::PrintDataTo(stream); |
| 613 } |
| 614 |
| 615 |
| 616 void HBranch::PrintDataTo(StringStream* stream) const { |
| 617 int first_id = FirstSuccessor()->block_id(); |
| 618 int second_id = SecondSuccessor()->block_id(); |
| 619 stream->Add("on "); |
| 620 value()->PrintNameTo(stream); |
| 621 stream->Add(" (B%d, B%d)", first_id, second_id); |
| 622 } |
| 623 |
| 624 |
| 625 void HGoto::PrintDataTo(StringStream* stream) const { |
| 626 stream->Add("B%d", FirstSuccessor()->block_id()); |
| 627 } |
| 628 |
| 629 |
| 630 void HReturn::PrintDataTo(StringStream* stream) const { |
| 631 value()->PrintNameTo(stream); |
| 632 } |
| 633 |
| 634 |
| 635 void HThrow::PrintDataTo(StringStream* stream) const { |
| 636 value()->PrintNameTo(stream); |
| 637 } |
| 638 |
| 639 |
| 640 const char* HUnaryMathOperation::OpName() const { |
| 641 switch (op()) { |
| 642 case kMathFloor: return "floor"; |
| 643 case kMathRound: return "round"; |
| 644 case kMathCeil: return "ceil"; |
| 645 case kMathAbs: return "abs"; |
| 646 case kMathLog: return "log"; |
| 647 case kMathSin: return "sin"; |
| 648 case kMathCos: return "cos"; |
| 649 case kMathTan: return "tan"; |
| 650 case kMathASin: return "asin"; |
| 651 case kMathACos: return "acos"; |
| 652 case kMathATan: return "atan"; |
| 653 case kMathExp: return "exp"; |
| 654 case kMathSqrt: return "sqrt"; |
| 655 default: break; |
| 656 } |
| 657 return "(unknown operation)"; |
| 658 } |
| 659 |
| 660 |
| 661 void HUnaryMathOperation::PrintDataTo(StringStream* stream) const { |
| 662 const char* name = OpName(); |
| 663 stream->Add("%s ", name); |
| 664 value()->PrintNameTo(stream); |
| 665 } |
| 666 |
| 667 |
| 668 void HUnaryOperation::PrintDataTo(StringStream* stream) const { |
| 669 value()->PrintNameTo(stream); |
| 670 } |
| 671 |
| 672 |
| 673 void HHasInstanceType::PrintDataTo(StringStream* stream) const { |
| 674 value()->PrintNameTo(stream); |
| 675 switch (from_) { |
| 676 case FIRST_JS_OBJECT_TYPE: |
| 677 if (to_ == LAST_TYPE) stream->Add(" spec_object"); |
| 678 break; |
| 679 case JS_REGEXP_TYPE: |
| 680 if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp"); |
| 681 break; |
| 682 case JS_ARRAY_TYPE: |
| 683 if (to_ == JS_ARRAY_TYPE) stream->Add(" array"); |
| 684 break; |
| 685 case JS_FUNCTION_TYPE: |
| 686 if (to_ == JS_FUNCTION_TYPE) stream->Add(" function"); |
| 687 break; |
| 688 default: |
| 689 break; |
| 690 } |
| 691 } |
| 692 |
| 693 |
| 694 void HTypeofIs::PrintDataTo(StringStream* stream) const { |
| 695 value()->PrintNameTo(stream); |
| 696 stream->Add(" == "); |
| 697 stream->Add(type_literal_->ToAsciiVector()); |
| 698 } |
| 699 |
| 700 |
| 701 void HPushArgument::PrintDataTo(StringStream* stream) const { |
| 702 HUnaryOperation::PrintDataTo(stream); |
| 703 if (argument_index() != -1) { |
| 704 stream->Add(" [%d]", argument_index_); |
| 705 } |
| 706 } |
| 707 |
| 708 |
| 709 void HChange::PrintDataTo(StringStream* stream) const { |
| 710 HUnaryOperation::PrintDataTo(stream); |
| 711 stream->Add(" %s to %s", from_.Mnemonic(), to_.Mnemonic()); |
| 712 |
| 713 if (CanTruncateToInt32()) stream->Add(" truncating-int32"); |
| 714 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); |
| 715 } |
| 716 |
| 717 |
| 718 HCheckInstanceType* HCheckInstanceType::NewIsJSObjectOrJSFunction( |
| 719 HValue* value) { |
| 720 STATIC_ASSERT((LAST_JS_OBJECT_TYPE + 1) == JS_FUNCTION_TYPE); |
| 721 return new HCheckInstanceType(value, FIRST_JS_OBJECT_TYPE, JS_FUNCTION_TYPE); |
| 722 } |
| 723 |
| 724 |
| 725 void HCheckMap::PrintDataTo(StringStream* stream) const { |
| 726 value()->PrintNameTo(stream); |
| 727 stream->Add(" %p", *map()); |
| 728 } |
| 729 |
| 730 |
| 731 void HCheckFunction::PrintDataTo(StringStream* stream) const { |
| 732 value()->PrintNameTo(stream); |
| 733 stream->Add(" %p", *target()); |
| 734 } |
| 735 |
| 736 |
| 737 void HCallKeyed::PrintDataTo(StringStream* stream) const { |
| 738 stream->Add("["); |
| 739 key()->PrintNameTo(stream); |
| 740 stream->Add("]("); |
| 741 for (int i = 1; i < arguments_.length(); ++i) { |
| 742 if (i != 1) stream->Add(", "); |
| 743 arguments_.at(i)->PrintNameTo(stream); |
| 744 } |
| 745 stream->Add(")"); |
| 746 } |
| 747 |
| 748 |
| 749 void HCallNamed::PrintDataTo(StringStream* stream) const { |
| 750 SmartPointer<char> name_string = name()->ToCString(); |
| 751 stream->Add("%s ", *name_string); |
| 752 HCall::PrintDataTo(stream); |
| 753 } |
| 754 |
| 755 |
| 756 void HCallGlobal::PrintDataTo(StringStream* stream) const { |
| 757 SmartPointer<char> name_string = name()->ToCString(); |
| 758 stream->Add("%s ", *name_string); |
| 759 HCall::PrintDataTo(stream); |
| 760 } |
| 761 |
| 762 |
| 763 void HCallRuntime::PrintDataTo(StringStream* stream) const { |
| 764 SmartPointer<char> name_string = name()->ToCString(); |
| 765 stream->Add("%s ", *name_string); |
| 766 HCall::PrintDataTo(stream); |
| 767 } |
| 768 |
| 769 void HCallStub::PrintDataTo(StringStream* stream) const { |
| 770 stream->Add("%s(%d)", |
| 771 CodeStub::MajorName(major_key_, false), |
| 772 argument_count_); |
| 773 } |
| 774 |
| 775 |
| 776 Range* HValue::InferRange() { |
| 777 if (representation().IsTagged()) { |
| 778 // Tagged values are always in int32 range when converted to integer, |
| 779 // but they can contain -0. |
| 780 Range* result = new Range(); |
| 781 result->set_can_be_minus_zero(true); |
| 782 return result; |
| 783 } else if (representation().IsNone()) { |
| 784 return NULL; |
| 785 } else { |
| 786 return new Range(); |
| 787 } |
| 788 } |
| 789 |
| 790 |
| 791 Range* HConstant::InferRange() { |
| 792 if (has_int32_value_) { |
| 793 Range* result = new Range(int32_value_, int32_value_); |
| 794 result->set_can_be_minus_zero(false); |
| 795 return result; |
| 796 } |
| 797 return HInstruction::InferRange(); |
| 798 } |
| 799 |
| 800 |
| 801 Range* HPhi::InferRange() { |
| 802 if (representation().IsInteger32()) { |
| 803 if (block()->IsLoopHeader()) { |
| 804 Range* range = new Range(kMinInt, kMaxInt); |
| 805 return range; |
| 806 } else { |
| 807 Range* range = OperandAt(0)->range()->Copy(); |
| 808 for (int i = 1; i < OperandCount(); ++i) { |
| 809 range->Union(OperandAt(i)->range()); |
| 810 } |
| 811 return range; |
| 812 } |
| 813 } else { |
| 814 return HValue::InferRange(); |
| 815 } |
| 816 } |
| 817 |
| 818 |
| 819 Range* HAdd::InferRange() { |
| 820 if (representation().IsInteger32()) { |
| 821 Range* a = left()->range(); |
| 822 Range* b = right()->range(); |
| 823 Range* res = a->Copy(); |
| 824 if (!res->AddAndCheckOverflow(b)) { |
| 825 ClearFlag(kCanOverflow); |
| 826 } |
| 827 bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero(); |
| 828 res->set_can_be_minus_zero(m0); |
| 829 return res; |
| 830 } else { |
| 831 return HArithmeticBinaryOperation::InferRange(); |
| 832 } |
| 833 } |
| 834 |
| 835 |
| 836 Range* HSub::InferRange() { |
| 837 if (representation().IsInteger32()) { |
| 838 Range* a = left()->range(); |
| 839 Range* b = right()->range(); |
| 840 Range* res = a->Copy(); |
| 841 if (!res->SubAndCheckOverflow(b)) { |
| 842 ClearFlag(kCanOverflow); |
| 843 } |
| 844 res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero()); |
| 845 return res; |
| 846 } else { |
| 847 return HArithmeticBinaryOperation::InferRange(); |
| 848 } |
| 849 } |
| 850 |
| 851 |
| 852 Range* HMul::InferRange() { |
| 853 if (representation().IsInteger32()) { |
| 854 Range* a = left()->range(); |
| 855 Range* b = right()->range(); |
| 856 Range* res = a->Copy(); |
| 857 if (!res->MulAndCheckOverflow(b)) { |
| 858 ClearFlag(kCanOverflow); |
| 859 } |
| 860 bool m0 = (a->CanBeZero() && b->CanBeNegative()) || |
| 861 (a->CanBeNegative() && b->CanBeZero()); |
| 862 res->set_can_be_minus_zero(m0); |
| 863 return res; |
| 864 } else { |
| 865 return HArithmeticBinaryOperation::InferRange(); |
| 866 } |
| 867 } |
| 868 |
| 869 |
| 870 Range* HDiv::InferRange() { |
| 871 if (representation().IsInteger32()) { |
| 872 Range* result = new Range(); |
| 873 if (left()->range()->CanBeMinusZero()) { |
| 874 result->set_can_be_minus_zero(true); |
| 875 } |
| 876 |
| 877 if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) { |
| 878 result->set_can_be_minus_zero(true); |
| 879 } |
| 880 |
| 881 if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) { |
| 882 SetFlag(HValue::kCanOverflow); |
| 883 } |
| 884 |
| 885 if (!right()->range()->CanBeZero()) { |
| 886 ClearFlag(HValue::kCanBeDivByZero); |
| 887 } |
| 888 return result; |
| 889 } else { |
| 890 return HArithmeticBinaryOperation::InferRange(); |
| 891 } |
| 892 } |
| 893 |
| 894 |
| 895 Range* HMod::InferRange() { |
| 896 if (representation().IsInteger32()) { |
| 897 Range* a = left()->range(); |
| 898 Range* result = new Range(); |
| 899 if (a->CanBeMinusZero() || a->CanBeNegative()) { |
| 900 result->set_can_be_minus_zero(true); |
| 901 } |
| 902 if (!right()->range()->CanBeZero()) { |
| 903 ClearFlag(HValue::kCanBeDivByZero); |
| 904 } |
| 905 return result; |
| 906 } else { |
| 907 return HArithmeticBinaryOperation::InferRange(); |
| 908 } |
| 909 } |
| 910 |
| 911 |
| 912 void HPhi::PrintTo(StringStream* stream) const { |
| 913 stream->Add("["); |
| 914 for (int i = 0; i < OperandCount(); ++i) { |
| 915 HValue* value = OperandAt(i); |
| 916 stream->Add(" "); |
| 917 value->PrintNameTo(stream); |
| 918 stream->Add(" "); |
| 919 } |
| 920 stream->Add(" uses%d_%di_%dd_%dt]", |
| 921 uses()->length(), |
| 922 int32_non_phi_uses() + int32_indirect_uses(), |
| 923 double_non_phi_uses() + double_indirect_uses(), |
| 924 tagged_non_phi_uses() + tagged_indirect_uses()); |
| 925 } |
| 926 |
| 927 |
| 928 void HPhi::AddInput(HValue* value) { |
| 929 inputs_.Add(NULL); |
| 930 SetOperandAt(OperandCount() - 1, value); |
| 931 // Mark phis that may have 'arguments' directly or indirectly as an operand. |
| 932 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) { |
| 933 SetFlag(kIsArguments); |
| 934 } |
| 935 } |
| 936 |
| 937 |
| 938 bool HPhi::HasReceiverOperand() { |
| 939 for (int i = 0; i < OperandCount(); i++) { |
| 940 if (OperandAt(i)->IsParameter() && |
| 941 HParameter::cast(OperandAt(i))->index() == 0) { |
| 942 return true; |
| 943 } |
| 944 } |
| 945 return false; |
| 946 } |
| 947 |
| 948 |
| 949 HValue* HPhi::GetRedundantReplacement() const { |
| 950 HValue* candidate = NULL; |
| 951 int count = OperandCount(); |
| 952 int position = 0; |
| 953 while (position < count && candidate == NULL) { |
| 954 HValue* current = OperandAt(position++); |
| 955 if (current != this) candidate = current; |
| 956 } |
| 957 while (position < count) { |
| 958 HValue* current = OperandAt(position++); |
| 959 if (current != this && current != candidate) return NULL; |
| 960 } |
| 961 ASSERT(candidate != this); |
| 962 return candidate; |
| 963 } |
| 964 |
| 965 |
| 966 void HPhi::DeleteFromGraph() { |
| 967 ASSERT(block() != NULL); |
| 968 block()->RemovePhi(this); |
| 969 ASSERT(block() == NULL); |
| 970 } |
| 971 |
| 972 |
| 973 void HPhi::InitRealUses(int phi_id) { |
| 974 // Initialize real uses. |
| 975 phi_id_ = phi_id; |
| 976 for (int j = 0; j < uses()->length(); j++) { |
| 977 HValue* use = uses()->at(j); |
| 978 if (!use->IsPhi()) { |
| 979 int index = use->LookupOperandIndex(0, this); |
| 980 Representation req_rep = use->RequiredInputRepresentation(index); |
| 981 non_phi_uses_[req_rep.kind()]++; |
| 982 } |
| 983 } |
| 984 } |
| 985 |
| 986 |
| 987 void HPhi::AddNonPhiUsesFrom(HPhi* other) { |
| 988 for (int i = 0; i < Representation::kNumRepresentations; i++) { |
| 989 indirect_uses_[i] += other->non_phi_uses_[i]; |
| 990 } |
| 991 } |
| 992 |
| 993 |
| 994 void HPhi::AddIndirectUsesTo(int* dest) { |
| 995 for (int i = 0; i < Representation::kNumRepresentations; i++) { |
| 996 dest[i] += indirect_uses_[i]; |
| 997 } |
| 998 } |
| 999 |
| 1000 |
| 1001 void HSimulate::PrintDataTo(StringStream* stream) const { |
| 1002 stream->Add("id=%d ", ast_id()); |
| 1003 if (pop_count_ > 0) stream->Add("pop %d", pop_count_); |
| 1004 if (values_.length() > 0) { |
| 1005 if (pop_count_ > 0) stream->Add(" /"); |
| 1006 for (int i = 0; i < values_.length(); ++i) { |
| 1007 if (!HasAssignedIndexAt(i)) { |
| 1008 stream->Add(" push "); |
| 1009 } else { |
| 1010 stream->Add(" var[%d] = ", GetAssignedIndexAt(i)); |
| 1011 } |
| 1012 values_[i]->PrintNameTo(stream); |
| 1013 } |
| 1014 } |
| 1015 } |
| 1016 |
| 1017 |
| 1018 void HEnterInlined::PrintDataTo(StringStream* stream) const { |
| 1019 SmartPointer<char> name = function()->debug_name()->ToCString(); |
| 1020 stream->Add("%s, id=%d", *name, function()->id()); |
| 1021 } |
| 1022 |
| 1023 |
| 1024 HConstant::HConstant(Handle<Object> handle, Representation r) |
| 1025 : handle_(handle), |
| 1026 constant_type_(HType::TypeFromValue(handle)), |
| 1027 has_int32_value_(false), |
| 1028 int32_value_(0), |
| 1029 has_double_value_(false), |
| 1030 double_value_(0) { |
| 1031 set_representation(r); |
| 1032 SetFlag(kUseGVN); |
| 1033 if (handle_->IsNumber()) { |
| 1034 double n = handle_->Number(); |
| 1035 has_int32_value_ = static_cast<double>(static_cast<int32_t>(n)) == n; |
| 1036 if (has_int32_value_) int32_value_ = static_cast<int32_t>(n); |
| 1037 double_value_ = n; |
| 1038 has_double_value_ = true; |
| 1039 } |
| 1040 } |
| 1041 |
| 1042 |
| 1043 HConstant* HConstant::CopyToRepresentation(Representation r) const { |
| 1044 if (r.IsInteger32() && !has_int32_value_) return NULL; |
| 1045 if (r.IsDouble() && !has_double_value_) return NULL; |
| 1046 return new HConstant(handle_, r); |
| 1047 } |
| 1048 |
| 1049 |
| 1050 HConstant* HConstant::CopyToTruncatedInt32() const { |
| 1051 if (!has_double_value_) return NULL; |
| 1052 int32_t truncated = NumberToInt32(*handle_); |
| 1053 return new HConstant(FACTORY->NewNumberFromInt(truncated), |
| 1054 Representation::Integer32()); |
| 1055 } |
| 1056 |
| 1057 |
| 1058 void HConstant::PrintDataTo(StringStream* stream) const { |
| 1059 handle()->ShortPrint(stream); |
| 1060 } |
| 1061 |
| 1062 |
| 1063 bool HArrayLiteral::IsCopyOnWrite() const { |
| 1064 return constant_elements()->map() == HEAP->fixed_cow_array_map(); |
| 1065 } |
| 1066 |
| 1067 |
| 1068 void HBinaryOperation::PrintDataTo(StringStream* stream) const { |
| 1069 left()->PrintNameTo(stream); |
| 1070 stream->Add(" "); |
| 1071 right()->PrintNameTo(stream); |
| 1072 if (CheckFlag(kCanOverflow)) stream->Add(" !"); |
| 1073 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?"); |
| 1074 } |
| 1075 |
| 1076 |
| 1077 Range* HBitAnd::InferRange() { |
| 1078 Range* a = left()->range(); |
| 1079 Range* b = right()->range(); |
| 1080 int32_t a_mask = 0xffffffff; |
| 1081 int32_t b_mask = 0xffffffff; |
| 1082 if (a != NULL) a_mask = a->Mask(); |
| 1083 if (b != NULL) b_mask = b->Mask(); |
| 1084 int32_t result_mask = a_mask & b_mask; |
| 1085 if (result_mask >= 0) { |
| 1086 return new Range(0, result_mask); |
| 1087 } else { |
| 1088 return HBinaryOperation::InferRange(); |
| 1089 } |
| 1090 } |
| 1091 |
| 1092 |
| 1093 Range* HBitOr::InferRange() { |
| 1094 Range* a = left()->range(); |
| 1095 Range* b = right()->range(); |
| 1096 int32_t a_mask = 0xffffffff; |
| 1097 int32_t b_mask = 0xffffffff; |
| 1098 if (a != NULL) a_mask = a->Mask(); |
| 1099 if (b != NULL) b_mask = b->Mask(); |
| 1100 int32_t result_mask = a_mask | b_mask; |
| 1101 if (result_mask >= 0) { |
| 1102 return new Range(0, result_mask); |
| 1103 } else { |
| 1104 return HBinaryOperation::InferRange(); |
| 1105 } |
| 1106 } |
| 1107 |
| 1108 |
| 1109 Range* HSar::InferRange() { |
| 1110 if (right()->IsConstant()) { |
| 1111 HConstant* c = HConstant::cast(right()); |
| 1112 if (c->HasInteger32Value()) { |
| 1113 int32_t val = c->Integer32Value(); |
| 1114 Range* result = NULL; |
| 1115 Range* left_range = left()->range(); |
| 1116 if (left_range == NULL) { |
| 1117 result = new Range(); |
| 1118 } else { |
| 1119 result = left_range->Copy(); |
| 1120 } |
| 1121 result->Sar(val); |
| 1122 return result; |
| 1123 } |
| 1124 } |
| 1125 |
| 1126 return HBinaryOperation::InferRange(); |
| 1127 } |
| 1128 |
| 1129 |
| 1130 Range* HShl::InferRange() { |
| 1131 if (right()->IsConstant()) { |
| 1132 HConstant* c = HConstant::cast(right()); |
| 1133 if (c->HasInteger32Value()) { |
| 1134 int32_t val = c->Integer32Value(); |
| 1135 Range* result = NULL; |
| 1136 Range* left_range = left()->range(); |
| 1137 if (left_range == NULL) { |
| 1138 result = new Range(); |
| 1139 } else { |
| 1140 result = left_range->Copy(); |
| 1141 } |
| 1142 result->Shl(val); |
| 1143 return result; |
| 1144 } |
| 1145 } |
| 1146 |
| 1147 return HBinaryOperation::InferRange(); |
| 1148 } |
| 1149 |
| 1150 |
| 1151 |
| 1152 void HCompare::PrintDataTo(StringStream* stream) const { |
| 1153 stream->Add(Token::Name(token())); |
| 1154 stream->Add(" "); |
| 1155 HBinaryOperation::PrintDataTo(stream); |
| 1156 } |
| 1157 |
| 1158 |
| 1159 void HCompare::SetInputRepresentation(Representation r) { |
| 1160 input_representation_ = r; |
| 1161 if (r.IsTagged()) { |
| 1162 SetFlagMask(AllSideEffects()); |
| 1163 ClearFlag(kUseGVN); |
| 1164 } else { |
| 1165 ClearFlagMask(AllSideEffects()); |
| 1166 SetFlag(kUseGVN); |
| 1167 } |
| 1168 } |
| 1169 |
| 1170 |
| 1171 void HParameter::PrintDataTo(StringStream* stream) const { |
| 1172 stream->Add("%u", index()); |
| 1173 } |
| 1174 |
| 1175 |
| 1176 void HLoadNamedField::PrintDataTo(StringStream* stream) const { |
| 1177 object()->PrintNameTo(stream); |
| 1178 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : ""); |
| 1179 } |
| 1180 |
| 1181 |
| 1182 void HLoadKeyed::PrintDataTo(StringStream* stream) const { |
| 1183 object()->PrintNameTo(stream); |
| 1184 stream->Add("["); |
| 1185 key()->PrintNameTo(stream); |
| 1186 stream->Add("]"); |
| 1187 } |
| 1188 |
| 1189 |
| 1190 void HStoreNamed::PrintDataTo(StringStream* stream) const { |
| 1191 object()->PrintNameTo(stream); |
| 1192 stream->Add("."); |
| 1193 ASSERT(name()->IsString()); |
| 1194 stream->Add(*String::cast(*name())->ToCString()); |
| 1195 stream->Add(" = "); |
| 1196 value()->PrintNameTo(stream); |
| 1197 } |
| 1198 |
| 1199 |
| 1200 void HStoreNamedField::PrintDataTo(StringStream* stream) const { |
| 1201 HStoreNamed::PrintDataTo(stream); |
| 1202 if (!transition().is_null()) { |
| 1203 stream->Add(" (transition map %p)", *transition()); |
| 1204 } |
| 1205 } |
| 1206 |
| 1207 |
| 1208 void HStoreKeyed::PrintDataTo(StringStream* stream) const { |
| 1209 object()->PrintNameTo(stream); |
| 1210 stream->Add("["); |
| 1211 key()->PrintNameTo(stream); |
| 1212 stream->Add("] = "); |
| 1213 value()->PrintNameTo(stream); |
| 1214 } |
| 1215 |
| 1216 |
| 1217 void HLoadGlobal::PrintDataTo(StringStream* stream) const { |
| 1218 stream->Add("[%p]", *cell()); |
| 1219 if (check_hole_value()) stream->Add(" (deleteable/read-only)"); |
| 1220 } |
| 1221 |
| 1222 |
| 1223 void HStoreGlobal::PrintDataTo(StringStream* stream) const { |
| 1224 stream->Add("[%p] = ", *cell()); |
| 1225 value()->PrintNameTo(stream); |
| 1226 } |
| 1227 |
| 1228 |
| 1229 // Implementation of type inference and type conversions. Calculates |
| 1230 // the inferred type of this instruction based on the input operands. |
| 1231 |
| 1232 HType HValue::CalculateInferredType() const { |
| 1233 return type_; |
| 1234 } |
| 1235 |
| 1236 |
| 1237 HType HCheckMap::CalculateInferredType() const { |
| 1238 return value()->type(); |
| 1239 } |
| 1240 |
| 1241 |
| 1242 HType HCheckFunction::CalculateInferredType() const { |
| 1243 return value()->type(); |
| 1244 } |
| 1245 |
| 1246 |
| 1247 HType HCheckNonSmi::CalculateInferredType() const { |
| 1248 // TODO(kasperl): Is there any way to signal that this isn't a smi? |
| 1249 return HType::Tagged(); |
| 1250 } |
| 1251 |
| 1252 |
| 1253 HType HCheckSmi::CalculateInferredType() const { |
| 1254 return HType::Smi(); |
| 1255 } |
| 1256 |
| 1257 |
| 1258 HType HPhi::CalculateInferredType() const { |
| 1259 HType result = HType::Uninitialized(); |
| 1260 for (int i = 0; i < OperandCount(); ++i) { |
| 1261 HType current = OperandAt(i)->type(); |
| 1262 result = result.Combine(current); |
| 1263 } |
| 1264 return result; |
| 1265 } |
| 1266 |
| 1267 |
| 1268 HType HConstant::CalculateInferredType() const { |
| 1269 return constant_type_; |
| 1270 } |
| 1271 |
| 1272 |
| 1273 HType HCompare::CalculateInferredType() const { |
| 1274 return HType::Boolean(); |
| 1275 } |
| 1276 |
| 1277 |
| 1278 HType HCompareJSObjectEq::CalculateInferredType() const { |
| 1279 return HType::Boolean(); |
| 1280 } |
| 1281 |
| 1282 |
| 1283 HType HUnaryPredicate::CalculateInferredType() const { |
| 1284 return HType::Boolean(); |
| 1285 } |
| 1286 |
| 1287 |
| 1288 HType HArithmeticBinaryOperation::CalculateInferredType() const { |
| 1289 return HType::TaggedNumber(); |
| 1290 } |
| 1291 |
| 1292 |
| 1293 HType HAdd::CalculateInferredType() const { |
| 1294 return HType::Tagged(); |
| 1295 } |
| 1296 |
| 1297 |
| 1298 HType HBitAnd::CalculateInferredType() const { |
| 1299 return HType::TaggedNumber(); |
| 1300 } |
| 1301 |
| 1302 |
| 1303 HType HBitXor::CalculateInferredType() const { |
| 1304 return HType::TaggedNumber(); |
| 1305 } |
| 1306 |
| 1307 |
| 1308 HType HBitOr::CalculateInferredType() const { |
| 1309 return HType::TaggedNumber(); |
| 1310 } |
| 1311 |
| 1312 |
| 1313 HType HBitNot::CalculateInferredType() const { |
| 1314 return HType::TaggedNumber(); |
| 1315 } |
| 1316 |
| 1317 |
| 1318 HType HUnaryMathOperation::CalculateInferredType() const { |
| 1319 return HType::TaggedNumber(); |
| 1320 } |
| 1321 |
| 1322 |
| 1323 HType HShl::CalculateInferredType() const { |
| 1324 return HType::TaggedNumber(); |
| 1325 } |
| 1326 |
| 1327 |
| 1328 HType HShr::CalculateInferredType() const { |
| 1329 return HType::TaggedNumber(); |
| 1330 } |
| 1331 |
| 1332 |
| 1333 HType HSar::CalculateInferredType() const { |
| 1334 return HType::TaggedNumber(); |
| 1335 } |
| 1336 |
| 1337 |
| 1338 HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero( |
| 1339 BitVector* visited) { |
| 1340 visited->Add(id()); |
| 1341 if (representation().IsInteger32() && |
| 1342 !value()->representation().IsInteger32()) { |
| 1343 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { |
| 1344 SetFlag(kBailoutOnMinusZero); |
| 1345 } |
| 1346 } |
| 1347 if (RequiredInputRepresentation(0).IsInteger32() && |
| 1348 representation().IsInteger32()) { |
| 1349 return value(); |
| 1350 } |
| 1351 return NULL; |
| 1352 } |
| 1353 |
| 1354 |
| 1355 |
| 1356 HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
| 1357 visited->Add(id()); |
| 1358 if (from().IsInteger32()) return NULL; |
| 1359 if (CanTruncateToInt32()) return NULL; |
| 1360 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) { |
| 1361 SetFlag(kBailoutOnMinusZero); |
| 1362 } |
| 1363 ASSERT(!from().IsInteger32() || !to().IsInteger32()); |
| 1364 return NULL; |
| 1365 } |
| 1366 |
| 1367 |
| 1368 HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
| 1369 visited->Add(id()); |
| 1370 if (range() == NULL || range()->CanBeMinusZero()) { |
| 1371 SetFlag(kBailoutOnMinusZero); |
| 1372 return left(); |
| 1373 } |
| 1374 return NULL; |
| 1375 } |
| 1376 |
| 1377 |
| 1378 HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
| 1379 visited->Add(id()); |
| 1380 if (range() == NULL || range()->CanBeMinusZero()) { |
| 1381 SetFlag(kBailoutOnMinusZero); |
| 1382 } |
| 1383 return NULL; |
| 1384 } |
| 1385 |
| 1386 |
| 1387 HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
| 1388 visited->Add(id()); |
| 1389 if (range() == NULL || range()->CanBeMinusZero()) { |
| 1390 SetFlag(kBailoutOnMinusZero); |
| 1391 } |
| 1392 return NULL; |
| 1393 } |
| 1394 |
| 1395 |
| 1396 HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
| 1397 visited->Add(id()); |
| 1398 // Propagate to the left argument. If the left argument cannot be -0, then |
| 1399 // the result of the add operation cannot be either. |
| 1400 if (range() == NULL || range()->CanBeMinusZero()) { |
| 1401 return left(); |
| 1402 } |
| 1403 return NULL; |
| 1404 } |
| 1405 |
| 1406 |
| 1407 HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) { |
| 1408 visited->Add(id()); |
| 1409 // Propagate to the left argument. If the left argument cannot be -0, then |
| 1410 // the result of the sub operation cannot be either. |
| 1411 if (range() == NULL || range()->CanBeMinusZero()) { |
| 1412 return left(); |
| 1413 } |
| 1414 return NULL; |
| 1415 } |
| 1416 |
| 1417 |
| 1418 // Node-specific verification code is only included in debug mode. |
| 1419 #ifdef DEBUG |
| 1420 |
| 1421 void HPhi::Verify() const { |
| 1422 ASSERT(OperandCount() == block()->predecessors()->length()); |
| 1423 for (int i = 0; i < OperandCount(); ++i) { |
| 1424 HValue* value = OperandAt(i); |
| 1425 HBasicBlock* defining_block = value->block(); |
| 1426 HBasicBlock* predecessor_block = block()->predecessors()->at(i); |
| 1427 ASSERT(defining_block == predecessor_block || |
| 1428 defining_block->Dominates(predecessor_block)); |
| 1429 } |
| 1430 } |
| 1431 |
| 1432 |
| 1433 void HSimulate::Verify() const { |
| 1434 HInstruction::Verify(); |
| 1435 ASSERT(HasAstId()); |
| 1436 } |
| 1437 |
| 1438 |
| 1439 void HBoundsCheck::Verify() const { |
| 1440 HInstruction::Verify(); |
| 1441 ASSERT(HasNoUses()); |
| 1442 } |
| 1443 |
| 1444 |
| 1445 void HCheckSmi::Verify() const { |
| 1446 HInstruction::Verify(); |
| 1447 ASSERT(HasNoUses()); |
| 1448 } |
| 1449 |
| 1450 |
| 1451 void HCheckNonSmi::Verify() const { |
| 1452 HInstruction::Verify(); |
| 1453 ASSERT(HasNoUses()); |
| 1454 } |
| 1455 |
| 1456 |
| 1457 void HCheckInstanceType::Verify() const { |
| 1458 HInstruction::Verify(); |
| 1459 ASSERT(HasNoUses()); |
| 1460 } |
| 1461 |
| 1462 |
| 1463 void HCheckMap::Verify() const { |
| 1464 HInstruction::Verify(); |
| 1465 ASSERT(HasNoUses()); |
| 1466 } |
| 1467 |
| 1468 |
| 1469 void HCheckFunction::Verify() const { |
| 1470 HInstruction::Verify(); |
| 1471 ASSERT(HasNoUses()); |
| 1472 } |
| 1473 |
| 1474 |
| 1475 void HCheckPrototypeMaps::Verify() const { |
| 1476 HInstruction::Verify(); |
| 1477 ASSERT(HasNoUses()); |
| 1478 } |
| 1479 |
| 1480 #endif |
| 1481 |
| 1482 } } // namespace v8::internal |
| OLD | NEW |