blob: 4b54c216c8dd9d554f05a7128436b0cd30c4fbb9 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 the V8 project authors. All rights reserved.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002// 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
ulan@chromium.org2e04b582013-02-21 14:06:02 +000030#include "double.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000031#include "factory.h"
32#include "hydrogen.h"
33
34#if V8_TARGET_ARCH_IA32
35#include "ia32/lithium-ia32.h"
36#elif V8_TARGET_ARCH_X64
37#include "x64/lithium-x64.h"
38#elif V8_TARGET_ARCH_ARM
39#include "arm/lithium-arm.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000040#elif V8_TARGET_ARCH_MIPS
41#include "mips/lithium-mips.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#else
43#error Unsupported target architecture.
44#endif
45
46namespace v8 {
47namespace internal {
48
49#define DEFINE_COMPILE(type) \
50 LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \
51 return builder->Do##type(this); \
52 }
53HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
54#undef DEFINE_COMPILE
55
56
57const char* Representation::Mnemonic() const {
58 switch (kind_) {
59 case kNone: return "v";
60 case kTagged: return "t";
61 case kDouble: return "d";
62 case kInteger32: return "i";
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000063 case kExternal: return "x";
karlklose@chromium.org83a47282011-05-11 11:54:09 +000064 default:
kasperl@chromium.orga5551262010-12-07 12:49:48 +000065 UNREACHABLE();
66 return NULL;
67 }
68}
69
70
danno@chromium.orgfa458e42012-02-01 10:48:36 +000071int HValue::LoopWeight() const {
72 const int w = FLAG_loop_weight;
73 static const int weights[] = { 1, w, w*w, w*w*w, w*w*w*w };
74 return weights[Min(block()->LoopNestingDepth(),
75 static_cast<int>(ARRAY_SIZE(weights)-1))];
76}
77
78
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000079Isolate* HValue::isolate() const {
80 ASSERT(block() != NULL);
81 return block()->graph()->isolate();
82}
83
84
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000085void HValue::AssumeRepresentation(Representation r) {
86 if (CheckFlag(kFlexibleRepresentation)) {
87 ChangeRepresentation(r);
88 // The representation of the value is dictated by type feedback and
89 // will not be changed later.
90 ClearFlag(kFlexibleRepresentation);
91 }
92}
93
94
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000095void HValue::InferRepresentation(HInferRepresentation* h_infer) {
96 ASSERT(CheckFlag(kFlexibleRepresentation));
97 Representation new_rep = RepresentationFromInputs();
98 UpdateRepresentation(new_rep, h_infer, "inputs");
99 new_rep = RepresentationFromUses();
100 UpdateRepresentation(new_rep, h_infer, "uses");
101}
102
103
104Representation HValue::RepresentationFromUses() {
105 if (HasNoUses()) return Representation::None();
106
107 // Array of use counts for each representation.
108 int use_count[Representation::kNumRepresentations] = { 0 };
109
110 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
111 HValue* use = it.value();
112 Representation rep = use->observed_input_representation(it.index());
113 if (rep.IsNone()) continue;
114 if (FLAG_trace_representation) {
115 PrintF("#%d %s is used by #%d %s as %s%s\n",
116 id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(),
117 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : ""));
118 }
119 use_count[rep.kind()] += use->LoopWeight();
120 }
121 if (IsPhi()) HPhi::cast(this)->AddIndirectUsesTo(&use_count[0]);
122 int tagged_count = use_count[Representation::kTagged];
123 int double_count = use_count[Representation::kDouble];
124 int int32_count = use_count[Representation::kInteger32];
125
126 if (tagged_count > 0) return Representation::Tagged();
127 if (double_count > 0) return Representation::Double();
128 if (int32_count > 0) return Representation::Integer32();
129
130 return Representation::None();
131}
132
133
134void HValue::UpdateRepresentation(Representation new_rep,
135 HInferRepresentation* h_infer,
136 const char* reason) {
137 Representation r = representation();
138 if (new_rep.is_more_general_than(r)) {
139 // When an HConstant is marked "not convertible to integer", then
140 // never try to represent it as an integer.
141 if (new_rep.IsInteger32() && !IsConvertibleToInteger()) {
142 new_rep = Representation::Tagged();
143 if (FLAG_trace_representation) {
144 PrintF("Changing #%d %s representation %s -> %s because it's NCTI"
145 " (%s want i)\n",
146 id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
147 }
148 } else {
149 if (FLAG_trace_representation) {
150 PrintF("Changing #%d %s representation %s -> %s based on %s\n",
151 id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason);
152 }
153 }
154 ChangeRepresentation(new_rep);
155 AddDependantsToWorklist(h_infer);
156 }
157}
158
159
160void HValue::AddDependantsToWorklist(HInferRepresentation* h_infer) {
161 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
162 h_infer->AddToWorklist(it.value());
163 }
164 for (int i = 0; i < OperandCount(); ++i) {
165 h_infer->AddToWorklist(OperandAt(i));
166 }
167}
168
169
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000170static int32_t ConvertAndSetOverflow(int64_t result, bool* overflow) {
171 if (result > kMaxInt) {
172 *overflow = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000173 return kMaxInt;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000174 }
175 if (result < kMinInt) {
176 *overflow = true;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000177 return kMinInt;
178 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000179 return static_cast<int32_t>(result);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000180}
181
182
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000183static int32_t AddWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
184 int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b);
185 return ConvertAndSetOverflow(result, overflow);
186}
187
188
189static int32_t SubWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
190 int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b);
191 return ConvertAndSetOverflow(result, overflow);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000192}
193
194
195static int32_t MulWithoutOverflow(int32_t a, int32_t b, bool* overflow) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000196 int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b);
197 return ConvertAndSetOverflow(result, overflow);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000198}
199
200
201int32_t Range::Mask() const {
202 if (lower_ == upper_) return lower_;
203 if (lower_ >= 0) {
204 int32_t res = 1;
205 while (res < upper_) {
206 res = (res << 1) | 1;
207 }
208 return res;
209 }
210 return 0xffffffff;
211}
212
213
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000214void Range::AddConstant(int32_t value) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000215 if (value == 0) return;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000216 bool may_overflow = false; // Overflow is ignored here.
217 lower_ = AddWithoutOverflow(lower_, value, &may_overflow);
218 upper_ = AddWithoutOverflow(upper_, value, &may_overflow);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000219#ifdef DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000220 Verify();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000221#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000222}
223
224
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000225void Range::Intersect(Range* other) {
226 upper_ = Min(upper_, other->upper_);
227 lower_ = Max(lower_, other->lower_);
228 bool b = CanBeMinusZero() && other->CanBeMinusZero();
229 set_can_be_minus_zero(b);
230}
231
232
233void Range::Union(Range* other) {
234 upper_ = Max(upper_, other->upper_);
235 lower_ = Min(lower_, other->lower_);
236 bool b = CanBeMinusZero() || other->CanBeMinusZero();
237 set_can_be_minus_zero(b);
238}
239
240
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000241void Range::CombinedMax(Range* other) {
242 upper_ = Max(upper_, other->upper_);
243 lower_ = Max(lower_, other->lower_);
244 set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero());
245}
246
247
248void Range::CombinedMin(Range* other) {
249 upper_ = Min(upper_, other->upper_);
250 lower_ = Min(lower_, other->lower_);
251 set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero());
252}
253
254
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000255void Range::Sar(int32_t value) {
256 int32_t bits = value & 0x1F;
257 lower_ = lower_ >> bits;
258 upper_ = upper_ >> bits;
259 set_can_be_minus_zero(false);
260}
261
262
263void Range::Shl(int32_t value) {
264 int32_t bits = value & 0x1F;
265 int old_lower = lower_;
266 int old_upper = upper_;
267 lower_ = lower_ << bits;
268 upper_ = upper_ << bits;
269 if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) {
270 upper_ = kMaxInt;
271 lower_ = kMinInt;
272 }
273 set_can_be_minus_zero(false);
274}
275
276
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000277bool Range::AddAndCheckOverflow(Range* other) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000278 bool may_overflow = false;
279 lower_ = AddWithoutOverflow(lower_, other->lower(), &may_overflow);
280 upper_ = AddWithoutOverflow(upper_, other->upper(), &may_overflow);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000281 KeepOrder();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000282#ifdef DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000283 Verify();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000284#endif
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000285 return may_overflow;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000286}
287
288
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000289bool Range::SubAndCheckOverflow(Range* other) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000290 bool may_overflow = false;
291 lower_ = SubWithoutOverflow(lower_, other->upper(), &may_overflow);
292 upper_ = SubWithoutOverflow(upper_, other->lower(), &may_overflow);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000293 KeepOrder();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000294#ifdef DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000295 Verify();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000296#endif
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000297 return may_overflow;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000298}
299
300
301void Range::KeepOrder() {
302 if (lower_ > upper_) {
303 int32_t tmp = lower_;
304 lower_ = upper_;
305 upper_ = tmp;
306 }
307}
308
309
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000310#ifdef DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000311void Range::Verify() const {
312 ASSERT(lower_ <= upper_);
313}
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000314#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000315
316
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317bool Range::MulAndCheckOverflow(Range* other) {
318 bool may_overflow = false;
319 int v1 = MulWithoutOverflow(lower_, other->lower(), &may_overflow);
320 int v2 = MulWithoutOverflow(lower_, other->upper(), &may_overflow);
321 int v3 = MulWithoutOverflow(upper_, other->lower(), &may_overflow);
322 int v4 = MulWithoutOverflow(upper_, other->upper(), &may_overflow);
323 lower_ = Min(Min(v1, v2), Min(v3, v4));
324 upper_ = Max(Max(v1, v2), Max(v3, v4));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000325#ifdef DEBUG
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000326 Verify();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000327#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000328 return may_overflow;
329}
330
331
332const char* HType::ToString() {
333 switch (type_) {
334 case kTagged: return "tagged";
335 case kTaggedPrimitive: return "primitive";
336 case kTaggedNumber: return "number";
337 case kSmi: return "smi";
338 case kHeapNumber: return "heap-number";
339 case kString: return "string";
340 case kBoolean: return "boolean";
341 case kNonPrimitive: return "non-primitive";
342 case kJSArray: return "array";
343 case kJSObject: return "object";
344 case kUninitialized: return "uninitialized";
345 }
346 UNREACHABLE();
347 return "Unreachable code";
348}
349
350
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000351HType HType::TypeFromValue(Isolate* isolate, Handle<Object> value) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000352 // Handle dereferencing is safe here: an object's type as checked below
353 // never changes.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000354 AllowHandleDereference allow_handle_deref(isolate);
yangguo@chromium.org003650e2013-01-24 16:31:08 +0000355
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000356 HType result = HType::Tagged();
357 if (value->IsSmi()) {
358 result = HType::Smi();
359 } else if (value->IsHeapNumber()) {
360 result = HType::HeapNumber();
361 } else if (value->IsString()) {
362 result = HType::String();
363 } else if (value->IsBoolean()) {
364 result = HType::Boolean();
365 } else if (value->IsJSObject()) {
366 result = HType::JSObject();
367 } else if (value->IsJSArray()) {
368 result = HType::JSArray();
369 }
370 return result;
371}
372
373
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000374bool HValue::Dominates(HValue* dominator, HValue* dominated) {
375 if (dominator->block() != dominated->block()) {
376 // If they are in different blocks we can use the dominance relation
377 // between the blocks.
378 return dominator->block()->Dominates(dominated->block());
379 } else {
380 // Otherwise we must see which instruction comes first, considering
381 // that phis always precede regular instructions.
382 if (dominator->IsInstruction()) {
383 if (dominated->IsInstruction()) {
384 for (HInstruction* next = HInstruction::cast(dominator)->next();
385 next != NULL;
386 next = next->next()) {
387 if (next == dominated) return true;
388 }
389 return false;
390 } else if (dominated->IsPhi()) {
391 return false;
392 } else {
393 UNREACHABLE();
394 }
395 } else if (dominator->IsPhi()) {
396 if (dominated->IsInstruction()) {
397 return true;
398 } else {
399 // We cannot compare which phi comes first.
400 UNREACHABLE();
401 }
402 } else {
403 UNREACHABLE();
404 }
405 return false;
406 }
407}
408
409
410bool HValue::TestDominanceUsingProcessedFlag(HValue* dominator,
411 HValue* dominated) {
412 if (dominator->block() != dominated->block()) {
413 return dominator->block()->Dominates(dominated->block());
414 } else {
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000415 // If both arguments are in the same block we check if dominator is a phi
416 // or if dominated has not already been processed: in either case we know
417 // that dominator precedes dominated.
418 return dominator->IsPhi() || !dominated->CheckFlag(kIDefsProcessingDone);
danno@chromium.org94b0d6f2013-02-04 13:33:20 +0000419 }
420}
421
422
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000423bool HValue::IsDefinedAfter(HBasicBlock* other) const {
424 return block()->block_id() > other->block_id();
425}
426
427
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000428HUseListNode* HUseListNode::tail() {
429 // Skip and remove dead items in the use list.
430 while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) {
431 tail_ = tail_->tail_;
432 }
433 return tail_;
434}
435
436
ulan@chromium.org812308e2012-02-29 15:58:45 +0000437bool HValue::CheckUsesForFlag(Flag f) {
438 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000439 if (it.value()->IsSimulate()) continue;
ulan@chromium.org812308e2012-02-29 15:58:45 +0000440 if (!it.value()->CheckFlag(f)) return false;
441 }
442 return true;
443}
444
445
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000446HUseIterator::HUseIterator(HUseListNode* head) : next_(head) {
447 Advance();
448}
449
450
451void HUseIterator::Advance() {
452 current_ = next_;
453 if (current_ != NULL) {
454 next_ = current_->tail();
455 value_ = current_->value();
456 index_ = current_->index();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000457 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000458}
459
460
461int HValue::UseCount() const {
462 int count = 0;
463 for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count;
464 return count;
465}
466
467
468HUseListNode* HValue::RemoveUse(HValue* value, int index) {
469 HUseListNode* previous = NULL;
470 HUseListNode* current = use_list_;
471 while (current != NULL) {
472 if (current->value() == value && current->index() == index) {
473 if (previous == NULL) {
474 use_list_ = current->tail();
475 } else {
476 previous->set_tail(current->tail());
477 }
478 break;
479 }
480
481 previous = current;
482 current = current->tail();
483 }
484
485#ifdef DEBUG
486 // Do not reuse use list nodes in debug mode, zap them.
487 if (current != NULL) {
488 HUseListNode* temp =
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000489 new(block()->zone())
490 HUseListNode(current->value(), current->index(), NULL);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000491 current->Zap();
492 current = temp;
493 }
494#endif
495 return current;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000496}
497
498
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000499bool HValue::Equals(HValue* other) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000500 if (other->opcode() != opcode()) return false;
501 if (!other->representation().Equals(representation())) return false;
502 if (!other->type_.Equals(type_)) return false;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000503 if (other->flags() != flags()) return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000504 if (OperandCount() != other->OperandCount()) return false;
505 for (int i = 0; i < OperandCount(); ++i) {
506 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false;
507 }
508 bool result = DataEquals(other);
509 ASSERT(!result || Hashcode() == other->Hashcode());
510 return result;
511}
512
513
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000514intptr_t HValue::Hashcode() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000515 intptr_t result = opcode();
516 int count = OperandCount();
517 for (int i = 0; i < count; ++i) {
518 result = result * 19 + OperandAt(i)->id() + (result >> 7);
519 }
520 return result;
521}
522
523
ricow@chromium.orgdcebac02011-04-20 09:44:50 +0000524const char* HValue::Mnemonic() const {
525 switch (opcode()) {
526#define MAKE_CASE(type) case k##type: return #type;
527 HYDROGEN_CONCRETE_INSTRUCTION_LIST(MAKE_CASE)
528#undef MAKE_CASE
529 case kPhi: return "Phi";
530 default: return "";
531 }
532}
533
534
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000535bool HValue::IsInteger32Constant() {
536 return IsConstant() && HConstant::cast(this)->HasInteger32Value();
537}
538
539
540int32_t HValue::GetInteger32Constant() {
541 return HConstant::cast(this)->Integer32Value();
542}
543
544
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000545void HValue::SetOperandAt(int index, HValue* value) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000546 RegisterUse(index, value);
547 InternalSetOperandAt(index, value);
548}
549
550
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000551void HValue::DeleteAndReplaceWith(HValue* other) {
552 // We replace all uses first, so Delete can assert that there are none.
553 if (other != NULL) ReplaceAllUsesWith(other);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000554 ASSERT(HasNoUses());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000555 Kill();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000556 DeleteFromGraph();
557}
558
559
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000560void HValue::ReplaceAllUsesWith(HValue* other) {
561 while (use_list_ != NULL) {
562 HUseListNode* list_node = use_list_;
563 HValue* value = list_node->value();
564 ASSERT(!value->block()->IsStartBlock());
565 value->InternalSetOperandAt(list_node->index(), other);
566 use_list_ = list_node->tail();
567 list_node->set_tail(other->use_list_);
568 other->use_list_ = list_node;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000569 }
570}
571
572
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000573void HValue::Kill() {
574 // Instead of going through the entire use list of each operand, we only
575 // check the first item in each use list and rely on the tail() method to
576 // skip dead items, removing them lazily next time we traverse the list.
577 SetFlag(kIsDead);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000578 for (int i = 0; i < OperandCount(); ++i) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000579 HValue* operand = OperandAt(i);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000580 if (operand == NULL) continue;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000581 HUseListNode* first = operand->use_list_;
582 if (first != NULL && first->value() == this && first->index() == i) {
583 operand->use_list_ = first->tail();
584 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000585 }
586}
587
588
589void HValue::SetBlock(HBasicBlock* block) {
590 ASSERT(block_ == NULL || block == NULL);
591 block_ = block;
592 if (id_ == kNoNumber && block != NULL) {
593 id_ = block->graph()->GetNextValueID(this);
594 }
595}
596
597
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000598void HValue::PrintTypeTo(StringStream* stream) {
599 if (!representation().IsTagged() || type().Equals(HType::Tagged())) return;
600 stream->Add(" type[%s]", type().ToString());
601}
602
603
604void HValue::PrintRangeTo(StringStream* stream) {
605 if (range() == NULL || range()->IsMostGeneric()) return;
606 stream->Add(" range[%d,%d,m0=%d]",
607 range()->lower(),
608 range()->upper(),
609 static_cast<int>(range()->CanBeMinusZero()));
610}
611
612
613void HValue::PrintChangesTo(StringStream* stream) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000614 GVNFlagSet changes_flags = ChangesFlags();
615 if (changes_flags.IsEmpty()) return;
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000616 stream->Add(" changes[");
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000617 if (changes_flags == AllSideEffectsFlagSet()) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000618 stream->Add("*");
619 } else {
620 bool add_comma = false;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000621#define PRINT_DO(type) \
622 if (changes_flags.Contains(kChanges##type)) { \
623 if (add_comma) stream->Add(","); \
624 add_comma = true; \
625 stream->Add(#type); \
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000626 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000627 GVN_TRACKED_FLAG_LIST(PRINT_DO);
628 GVN_UNTRACKED_FLAG_LIST(PRINT_DO);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000629#undef PRINT_DO
630 }
631 stream->Add("]");
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000632}
633
634
635void HValue::PrintNameTo(StringStream* stream) {
636 stream->Add("%s%d", representation_.Mnemonic(), id());
637}
638
639
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000640bool HValue::HasMonomorphicJSObjectType() {
641 return !GetMonomorphicJSObjectMap().is_null();
642}
643
644
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000645bool HValue::UpdateInferredType() {
646 HType type = CalculateInferredType();
647 bool result = (!type.Equals(type_));
648 type_ = type;
649 return result;
650}
651
652
653void HValue::RegisterUse(int index, HValue* new_value) {
654 HValue* old_value = OperandAt(index);
655 if (old_value == new_value) return;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000656
657 HUseListNode* removed = NULL;
658 if (old_value != NULL) {
659 removed = old_value->RemoveUse(this, index);
660 }
661
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000662 if (new_value != NULL) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000663 if (removed == NULL) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000664 new_value->use_list_ = new(new_value->block()->zone()) HUseListNode(
665 this, index, new_value->use_list_);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +0000666 } else {
667 removed->set_tail(new_value->use_list_);
668 new_value->use_list_ = removed;
669 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670 }
671}
672
673
ulan@chromium.org812308e2012-02-29 15:58:45 +0000674void HValue::AddNewRange(Range* r, Zone* zone) {
675 if (!HasRange()) ComputeInitialRange(zone);
676 if (!HasRange()) range_ = new(zone) Range();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000677 ASSERT(HasRange());
678 r->StackUpon(range_);
679 range_ = r;
680}
681
682
683void HValue::RemoveLastAddedRange() {
684 ASSERT(HasRange());
685 ASSERT(range_->next() != NULL);
686 range_ = range_->next();
687}
688
689
ulan@chromium.org812308e2012-02-29 15:58:45 +0000690void HValue::ComputeInitialRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000691 ASSERT(!HasRange());
ulan@chromium.org812308e2012-02-29 15:58:45 +0000692 range_ = InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000693 ASSERT(HasRange());
694}
695
696
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000697void HInstruction::PrintTo(StringStream* stream) {
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000698 PrintMnemonicTo(stream);
699 PrintDataTo(stream);
700 PrintRangeTo(stream);
701 PrintChangesTo(stream);
702 PrintTypeTo(stream);
703}
704
705
706void HInstruction::PrintMnemonicTo(StringStream* stream) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000707 stream->Add("%s ", Mnemonic());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000708}
709
710
711void HInstruction::Unlink() {
712 ASSERT(IsLinked());
713 ASSERT(!IsControlInstruction()); // Must never move control instructions.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000714 ASSERT(!IsBlockEntry()); // Doesn't make sense to delete these.
715 ASSERT(previous_ != NULL);
716 previous_->next_ = next_;
717 if (next_ == NULL) {
718 ASSERT(block()->last() == this);
719 block()->set_last(previous_);
720 } else {
721 next_->previous_ = previous_;
722 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000723 clear_block();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000724}
725
726
727void HInstruction::InsertBefore(HInstruction* next) {
728 ASSERT(!IsLinked());
729 ASSERT(!next->IsBlockEntry());
730 ASSERT(!IsControlInstruction());
731 ASSERT(!next->block()->IsStartBlock());
732 ASSERT(next->previous_ != NULL);
733 HInstruction* prev = next->previous();
734 prev->next_ = this;
735 next->previous_ = this;
736 next_ = next;
737 previous_ = prev;
738 SetBlock(next->block());
739}
740
741
742void HInstruction::InsertAfter(HInstruction* previous) {
743 ASSERT(!IsLinked());
744 ASSERT(!previous->IsControlInstruction());
745 ASSERT(!IsControlInstruction() || previous->next_ == NULL);
746 HBasicBlock* block = previous->block();
747 // Never insert anything except constants into the start block after finishing
748 // it.
749 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) {
750 ASSERT(block->end()->SecondSuccessor() == NULL);
751 InsertAfter(block->end()->FirstSuccessor()->first());
752 return;
753 }
754
755 // If we're inserting after an instruction with side-effects that is
756 // followed by a simulate instruction, we need to insert after the
757 // simulate instruction instead.
758 HInstruction* next = previous->next_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000759 if (previous->HasObservableSideEffects() && next != NULL) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000760 ASSERT(next->IsSimulate());
761 previous = next;
762 next = previous->next_;
763 }
764
765 previous_ = previous;
766 next_ = next;
767 SetBlock(block);
768 previous->next_ = this;
769 if (next != NULL) next->previous_ = this;
jkummerow@chromium.org28faa982012-04-13 09:58:30 +0000770 if (block->last() == previous) {
771 block->set_last(this);
772 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000773}
774
775
776#ifdef DEBUG
ager@chromium.org378b34e2011-01-28 08:04:38 +0000777void HInstruction::Verify() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000778 // Verify that input operands are defined before use.
779 HBasicBlock* cur_block = block();
780 for (int i = 0; i < OperandCount(); ++i) {
781 HValue* other_operand = OperandAt(i);
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +0000782 if (other_operand == NULL) continue;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000783 HBasicBlock* other_block = other_operand->block();
784 if (cur_block == other_block) {
785 if (!other_operand->IsPhi()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000786 HInstruction* cur = this->previous();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000787 while (cur != NULL) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000788 if (cur == other_operand) break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000789 cur = cur->previous();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000790 }
791 // Must reach other operand in the same block!
792 ASSERT(cur == other_operand);
793 }
794 } else {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000795 // If the following assert fires, you may have forgotten an
796 // AddInstruction.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000797 ASSERT(other_block->Dominates(cur_block));
798 }
799 }
800
801 // Verify that instructions that may have side-effects are followed
802 // by a simulate instruction.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000803 if (HasObservableSideEffects() && !IsOsrEntry()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000804 ASSERT(next()->IsSimulate());
805 }
ager@chromium.org378b34e2011-01-28 08:04:38 +0000806
807 // Verify that instructions that can be eliminated by GVN have overridden
808 // HValue::DataEquals. The default implementation is UNREACHABLE. We
809 // don't actually care whether DataEquals returns true or false here.
810 if (CheckFlag(kUseGVN)) DataEquals(this);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000811
812 // Verify that all uses are in the graph.
813 for (HUseIterator use = uses(); !use.Done(); use.Advance()) {
814 if (use.value()->IsInstruction()) {
815 ASSERT(HInstruction::cast(use.value())->IsLinked());
816 }
817 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000818}
819#endif
820
821
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000822HNumericConstraint* HNumericConstraint::AddToGraph(
823 HValue* constrained_value,
824 NumericRelation relation,
825 HValue* related_value,
826 HInstruction* insertion_point) {
827 if (insertion_point == NULL) {
828 if (constrained_value->IsInstruction()) {
829 insertion_point = HInstruction::cast(constrained_value);
830 } else if (constrained_value->IsPhi()) {
831 insertion_point = constrained_value->block()->first();
832 } else {
833 UNREACHABLE();
834 }
835 }
836 HNumericConstraint* result =
837 new(insertion_point->block()->zone()) HNumericConstraint(
838 constrained_value, relation, related_value);
839 result->InsertAfter(insertion_point);
840 return result;
841}
842
843
844void HNumericConstraint::PrintDataTo(StringStream* stream) {
845 stream->Add("(");
846 constrained_value()->PrintNameTo(stream);
847 stream->Add(" %s ", relation().Mnemonic());
848 related_value()->PrintNameTo(stream);
849 stream->Add(")");
850}
851
852
ulan@chromium.org2e04b582013-02-21 14:06:02 +0000853HInductionVariableAnnotation* HInductionVariableAnnotation::AddToGraph(
854 HPhi* phi,
855 NumericRelation relation,
856 int operand_index) {
857 HInductionVariableAnnotation* result =
858 new(phi->block()->zone()) HInductionVariableAnnotation(phi, relation,
859 operand_index);
860 result->InsertAfter(phi->block()->first());
861 return result;
862}
863
864
865void HInductionVariableAnnotation::PrintDataTo(StringStream* stream) {
866 stream->Add("(");
867 RedefinedOperand()->PrintNameTo(stream);
868 stream->Add(" %s ", relation().Mnemonic());
869 induction_base()->PrintNameTo(stream);
870 stream->Add(")");
871}
872
873
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000874void HDummyUse::PrintDataTo(StringStream* stream) {
875 value()->PrintNameTo(stream);
876}
877
878
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000879void HUnaryCall::PrintDataTo(StringStream* stream) {
880 value()->PrintNameTo(stream);
881 stream->Add(" ");
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000882 stream->Add("#%d", argument_count());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000883}
884
885
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000886void HBinaryCall::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000887 first()->PrintNameTo(stream);
888 stream->Add(" ");
889 second()->PrintNameTo(stream);
890 stream->Add(" ");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000891 stream->Add("#%d", argument_count());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000892}
893
894
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000895void HBoundsCheck::AddInformativeDefinitions() {
896 // TODO(mmassi): Executing this code during AddInformativeDefinitions
897 // is a hack. Move it to some other HPhase.
898 if (index()->IsRelationTrue(NumericRelation::Ge(),
899 block()->graph()->GetConstant0()) &&
900 index()->IsRelationTrue(NumericRelation::Lt(), length())) {
901 set_skip_check(true);
902 }
903}
904
905
906bool HBoundsCheck::IsRelationTrueInternal(NumericRelation relation,
907 HValue* related_value) {
908 if (related_value == length()) {
909 // A HBoundsCheck is smaller than the length it compared against.
910 return NumericRelation::Lt().Implies(relation);
911 } else if (related_value == block()->graph()->GetConstant0()) {
912 // A HBoundsCheck is greater than or equal to zero.
913 return NumericRelation::Ge().Implies(relation);
914 } else {
915 return false;
916 }
917}
918
919
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000920void HBoundsCheck::PrintDataTo(StringStream* stream) {
921 index()->PrintNameTo(stream);
922 stream->Add(" ");
923 length()->PrintNameTo(stream);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000924 if (skip_check()) {
925 stream->Add(" [DISABLED]");
926 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000927}
928
ricow@chromium.orgddd545c2011-08-24 12:02:41 +0000929
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000930void HBoundsCheck::InferRepresentation(HInferRepresentation* h_infer) {
931 ASSERT(CheckFlag(kFlexibleRepresentation));
932 Representation r;
933 if (key_mode_ == DONT_ALLOW_SMI_KEY ||
934 !length()->representation().IsTagged()) {
935 r = Representation::Integer32();
936 } else if (index()->representation().IsTagged() ||
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000937 (index()->ActualValue()->IsConstant() &&
938 HConstant::cast(index()->ActualValue())->HasSmiValue())) {
mstarzinger@chromium.org068ea0a2013-01-30 09:39:44 +0000939 // If the index is tagged, or a constant that holds a Smi, allow the length
940 // to be tagged, since it is usually already tagged from loading it out of
941 // the length field of a JSArray. This allows for direct comparison without
942 // untagging.
943 r = Representation::Tagged();
944 } else {
945 r = Representation::Integer32();
946 }
947 UpdateRepresentation(r, h_infer, "boundscheck");
948}
949
950
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000951void HCallConstantFunction::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000952 if (IsApplyFunction()) {
953 stream->Add("optimized apply ");
954 } else {
955 stream->Add("%o ", function()->shared()->DebugName());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000956 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000957 stream->Add("#%d", argument_count());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000958}
959
960
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000961void HCallNamed::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000962 stream->Add("%o ", *name());
963 HUnaryCall::PrintDataTo(stream);
964}
965
966
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000967void HCallGlobal::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000968 stream->Add("%o ", *name());
969 HUnaryCall::PrintDataTo(stream);
970}
971
972
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000973void HCallKnownGlobal::PrintDataTo(StringStream* stream) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000974 stream->Add("%o ", target()->shared()->DebugName());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000975 stream->Add("#%d", argument_count());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000976}
977
978
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000979void HCallRuntime::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000980 stream->Add("%o ", *name());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000981 stream->Add("#%d", argument_count());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000982}
983
984
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000985void HClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000986 stream->Add("class_of_test(");
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000987 value()->PrintNameTo(stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000988 stream->Add(", \"%o\")", *class_name());
989}
990
991
yangguo@chromium.org39110192013-01-16 09:55:08 +0000992void HWrapReceiver::PrintDataTo(StringStream* stream) {
993 receiver()->PrintNameTo(stream);
994 stream->Add(" ");
995 function()->PrintNameTo(stream);
996}
997
998
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000999void HAccessArgumentsAt::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001000 arguments()->PrintNameTo(stream);
1001 stream->Add("[");
1002 index()->PrintNameTo(stream);
1003 stream->Add("], length ");
1004 length()->PrintNameTo(stream);
1005}
1006
1007
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001008void HControlInstruction::PrintDataTo(StringStream* stream) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001009 stream->Add(" goto (");
1010 bool first_block = true;
1011 for (HSuccessorIterator it(this); !it.Done(); it.Advance()) {
1012 stream->Add(first_block ? "B%d" : ", B%d", it.Current()->block_id());
1013 first_block = false;
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001014 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001015 stream->Add(")");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001016}
1017
1018
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001019void HUnaryControlInstruction::PrintDataTo(StringStream* stream) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001020 value()->PrintNameTo(stream);
1021 HControlInstruction::PrintDataTo(stream);
1022}
1023
1024
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001025void HIsNilAndBranch::PrintDataTo(StringStream* stream) {
1026 value()->PrintNameTo(stream);
1027 stream->Add(kind() == kStrictEquality ? " === " : " == ");
1028 stream->Add(nil() == kNullValue ? "null" : "undefined");
1029 HControlInstruction::PrintDataTo(stream);
1030}
1031
1032
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001033void HReturn::PrintDataTo(StringStream* stream) {
1034 value()->PrintNameTo(stream);
1035}
1036
1037
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001038Representation HBranch::observed_input_representation(int index) {
1039 static const ToBooleanStub::Types tagged_types(
1040 ToBooleanStub::UNDEFINED |
1041 ToBooleanStub::NULL_TYPE |
1042 ToBooleanStub::SPEC_OBJECT |
1043 ToBooleanStub::STRING);
1044 if (expected_input_types_.ContainsAnyOf(tagged_types)) {
1045 return Representation::Tagged();
1046 } else if (expected_input_types_.Contains(ToBooleanStub::HEAP_NUMBER)) {
1047 return Representation::Double();
1048 } else if (expected_input_types_.Contains(ToBooleanStub::SMI)) {
1049 return Representation::Integer32();
1050 } else {
1051 return Representation::None();
1052 }
1053}
1054
1055
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001056void HCompareMap::PrintDataTo(StringStream* stream) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00001057 value()->PrintNameTo(stream);
1058 stream->Add(" (%p)", *map());
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00001059 HControlInstruction::PrintDataTo(stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001060}
1061
1062
1063const char* HUnaryMathOperation::OpName() const {
1064 switch (op()) {
1065 case kMathFloor: return "floor";
1066 case kMathRound: return "round";
1067 case kMathCeil: return "ceil";
1068 case kMathAbs: return "abs";
1069 case kMathLog: return "log";
1070 case kMathSin: return "sin";
1071 case kMathCos: return "cos";
1072 case kMathTan: return "tan";
1073 case kMathASin: return "asin";
1074 case kMathACos: return "acos";
1075 case kMathATan: return "atan";
1076 case kMathExp: return "exp";
1077 case kMathSqrt: return "sqrt";
1078 default: break;
1079 }
1080 return "(unknown operation)";
1081}
1082
1083
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001084void HUnaryMathOperation::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001085 const char* name = OpName();
1086 stream->Add("%s ", name);
1087 value()->PrintNameTo(stream);
1088}
1089
1090
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001091void HUnaryOperation::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001092 value()->PrintNameTo(stream);
1093}
1094
1095
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001096void HHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001097 value()->PrintNameTo(stream);
1098 switch (from_) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001099 case FIRST_JS_RECEIVER_TYPE:
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001100 if (to_ == LAST_TYPE) stream->Add(" spec_object");
1101 break;
1102 case JS_REGEXP_TYPE:
1103 if (to_ == JS_REGEXP_TYPE) stream->Add(" reg_exp");
1104 break;
1105 case JS_ARRAY_TYPE:
1106 if (to_ == JS_ARRAY_TYPE) stream->Add(" array");
1107 break;
1108 case JS_FUNCTION_TYPE:
1109 if (to_ == JS_FUNCTION_TYPE) stream->Add(" function");
1110 break;
1111 default:
1112 break;
1113 }
1114}
1115
1116
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001117void HTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001118 value()->PrintNameTo(stream);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001119 stream->Add(" == %o", *type_literal_);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001120 HControlInstruction::PrintDataTo(stream);
1121}
1122
1123
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001124void HCheckMapValue::PrintDataTo(StringStream* stream) {
1125 value()->PrintNameTo(stream);
1126 stream->Add(" ");
1127 map()->PrintNameTo(stream);
1128}
1129
1130
1131void HForInPrepareMap::PrintDataTo(StringStream* stream) {
1132 enumerable()->PrintNameTo(stream);
1133}
1134
1135
1136void HForInCacheArray::PrintDataTo(StringStream* stream) {
1137 enumerable()->PrintNameTo(stream);
1138 stream->Add(" ");
1139 map()->PrintNameTo(stream);
1140 stream->Add("[%d]", idx_);
1141}
1142
1143
1144void HLoadFieldByIndex::PrintDataTo(StringStream* stream) {
1145 object()->PrintNameTo(stream);
1146 stream->Add(" ");
1147 index()->PrintNameTo(stream);
1148}
1149
1150
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001151HValue* HBitwise::Canonicalize() {
1152 if (!representation().IsInteger32()) return this;
1153 // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x.
1154 int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0;
1155 if (left()->IsConstant() &&
1156 HConstant::cast(left())->HasInteger32Value() &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001157 HConstant::cast(left())->Integer32Value() == nop_constant &&
1158 !right()->CheckFlag(kUint32)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001159 return right();
1160 }
1161 if (right()->IsConstant() &&
1162 HConstant::cast(right())->HasInteger32Value() &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001163 HConstant::cast(right())->Integer32Value() == nop_constant &&
1164 !left()->CheckFlag(kUint32)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001165 return left();
1166 }
1167 return this;
1168}
1169
1170
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00001171HValue* HBitNot::Canonicalize() {
1172 // Optimize ~~x, a common pattern used for ToInt32(x).
1173 if (value()->IsBitNot()) {
1174 HValue* result = HBitNot::cast(value())->value();
1175 ASSERT(result->representation().IsInteger32());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001176 if (!result->CheckFlag(kUint32)) {
1177 return result;
1178 }
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00001179 }
1180 return this;
1181}
1182
1183
ulan@chromium.org812308e2012-02-29 15:58:45 +00001184HValue* HAdd::Canonicalize() {
1185 if (!representation().IsInteger32()) return this;
1186 if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow);
1187 return this;
1188}
1189
1190
1191HValue* HSub::Canonicalize() {
1192 if (!representation().IsInteger32()) return this;
1193 if (CheckUsesForFlag(kTruncatingToInt32)) ClearFlag(kCanOverflow);
1194 return this;
1195}
1196
1197
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001198HValue* HChange::Canonicalize() {
1199 return (from().Equals(to())) ? value() : this;
1200}
1201
1202
yangguo@chromium.org154ff992012-03-13 08:09:54 +00001203HValue* HWrapReceiver::Canonicalize() {
1204 if (HasNoUses()) return NULL;
1205 if (receiver()->type().IsJSObject()) {
1206 return receiver();
1207 }
1208 return this;
1209}
1210
1211
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001212void HTypeof::PrintDataTo(StringStream* stream) {
1213 value()->PrintNameTo(stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001214}
1215
1216
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001217void HForceRepresentation::PrintDataTo(StringStream* stream) {
1218 stream->Add("%s ", representation().Mnemonic());
1219 value()->PrintNameTo(stream);
1220}
1221
1222
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001223void HChange::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001224 HUnaryOperation::PrintDataTo(stream);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001225 stream->Add(" %s to %s", from().Mnemonic(), to().Mnemonic());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001226
1227 if (CanTruncateToInt32()) stream->Add(" truncating-int32");
1228 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001229 if (CheckFlag(kDeoptimizeOnUndefined)) stream->Add(" deopt-on-undefined");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001230}
1231
1232
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001233void HJSArrayLength::PrintDataTo(StringStream* stream) {
1234 value()->PrintNameTo(stream);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001235 if (HasTypeCheck()) {
1236 stream->Add(" ");
1237 typecheck()->PrintNameTo(stream);
1238 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001239}
1240
1241
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001242HValue* HUnaryMathOperation::Canonicalize() {
1243 if (op() == kMathFloor) {
1244 // If the input is integer32 then we replace the floor instruction
1245 // with its input. This happens before the representation changes are
1246 // introduced.
1247 if (value()->representation().IsInteger32()) return value();
1248
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00001249#if defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_IA32) || \
1250 defined(V8_TARGET_ARCH_X64)
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001251 if (value()->IsDiv() && (value()->UseCount() == 1)) {
1252 // TODO(2038): Implement this optimization for non ARM architectures.
1253 HDiv* hdiv = HDiv::cast(value());
1254 HValue* left = hdiv->left();
1255 HValue* right = hdiv->right();
1256 // Try to simplify left and right values of the division.
1257 HValue* new_left =
1258 LChunkBuilder::SimplifiedDividendForMathFloorOfDiv(left);
1259 HValue* new_right =
1260 LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(right);
1261
1262 // Return if left or right are not optimizable.
1263 if ((new_left == NULL) || (new_right == NULL)) return this;
1264
1265 // Insert the new values in the graph.
1266 if (new_left->IsInstruction() &&
1267 !HInstruction::cast(new_left)->IsLinked()) {
1268 HInstruction::cast(new_left)->InsertBefore(this);
1269 }
1270 if (new_right->IsInstruction() &&
1271 !HInstruction::cast(new_right)->IsLinked()) {
1272 HInstruction::cast(new_right)->InsertBefore(this);
1273 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001274 HMathFloorOfDiv* instr = new(block()->zone()) HMathFloorOfDiv(context(),
yangguo@chromium.orgefdb9d72012-04-26 08:21:05 +00001275 new_left,
1276 new_right);
1277 // Replace this HMathFloor instruction by the new HMathFloorOfDiv.
1278 instr->InsertBefore(this);
1279 ReplaceAllUsesWith(instr);
1280 Kill();
1281 // We know the division had no other uses than this HMathFloor. Delete it.
1282 // Also delete the arguments of the division if they are not used any
1283 // more.
1284 hdiv->DeleteAndReplaceWith(NULL);
1285 ASSERT(left->IsChange() || left->IsConstant());
1286 ASSERT(right->IsChange() || right->IsConstant());
1287 if (left->HasNoUses()) left->DeleteAndReplaceWith(NULL);
1288 if (right->HasNoUses()) right->DeleteAndReplaceWith(NULL);
1289
1290 // Return NULL to remove this instruction from the graph.
1291 return NULL;
1292 }
1293#endif // V8_TARGET_ARCH_ARM
1294 }
1295 return this;
1296}
1297
1298
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001299HValue* HCheckInstanceType::Canonicalize() {
1300 if (check_ == IS_STRING &&
1301 !value()->type().IsUninitialized() &&
1302 value()->type().IsString()) {
1303 return NULL;
1304 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001305
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001306 if (check_ == IS_INTERNALIZED_STRING && value()->IsConstant()) {
1307 // Dereferencing is safe here:
1308 // an internalized string cannot become non-internalized.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001309 AllowHandleDereference allow_handle_deref(isolate());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001310 if (HConstant::cast(value())->handle()->IsInternalizedString()) return NULL;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001311 }
1312 return this;
1313}
1314
1315
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001316void HCheckInstanceType::GetCheckInterval(InstanceType* first,
1317 InstanceType* last) {
1318 ASSERT(is_interval_check());
1319 switch (check_) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001320 case IS_SPEC_OBJECT:
1321 *first = FIRST_SPEC_OBJECT_TYPE;
1322 *last = LAST_SPEC_OBJECT_TYPE;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001323 return;
1324 case IS_JS_ARRAY:
1325 *first = *last = JS_ARRAY_TYPE;
1326 return;
1327 default:
1328 UNREACHABLE();
1329 }
1330}
1331
1332
1333void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
1334 ASSERT(!is_interval_check());
1335 switch (check_) {
1336 case IS_STRING:
1337 *mask = kIsNotStringMask;
1338 *tag = kStringTag;
1339 return;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001340 case IS_INTERNALIZED_STRING:
1341 *mask = kIsInternalizedMask;
1342 *tag = kInternalizedTag;
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001343 return;
1344 default:
1345 UNREACHABLE();
1346 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001347}
1348
1349
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001350void HCheckMaps::SetSideEffectDominator(GVNFlag side_effect,
1351 HValue* dominator) {
1352 ASSERT(side_effect == kChangesMaps);
1353 // TODO(mstarzinger): For now we specialize on HStoreNamedField, but once
1354 // type information is rich enough we should generalize this to any HType
1355 // for which the map is known.
1356 if (HasNoUses() && dominator->IsStoreNamedField()) {
1357 HStoreNamedField* store = HStoreNamedField::cast(dominator);
1358 Handle<Map> map = store->transition();
1359 if (map.is_null() || store->object() != value()) return;
1360 for (int i = 0; i < map_set()->length(); i++) {
1361 if (map.is_identical_to(map_set()->at(i))) {
1362 DeleteAndReplaceWith(NULL);
1363 return;
1364 }
1365 }
1366 }
1367}
1368
1369
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001370void HLoadElements::PrintDataTo(StringStream* stream) {
1371 value()->PrintNameTo(stream);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001372 if (HasTypeCheck()) {
1373 stream->Add(" ");
1374 typecheck()->PrintNameTo(stream);
1375 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001376}
1377
1378
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001379void HCheckMaps::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001380 value()->PrintNameTo(stream);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001381 stream->Add(" [%p", *map_set()->first());
1382 for (int i = 1; i < map_set()->length(); ++i) {
1383 stream->Add(",%p", *map_set()->at(i));
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001384 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001385 stream->Add("]");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001386}
1387
1388
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001389void HCheckFunction::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001390 value()->PrintNameTo(stream);
1391 stream->Add(" %p", *target());
1392}
1393
1394
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395const char* HCheckInstanceType::GetCheckName() {
1396 switch (check_) {
1397 case IS_SPEC_OBJECT: return "object";
1398 case IS_JS_ARRAY: return "array";
1399 case IS_STRING: return "string";
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001400 case IS_INTERNALIZED_STRING: return "internalized_string";
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 }
1402 UNREACHABLE();
1403 return "";
1404}
1405
1406void HCheckInstanceType::PrintDataTo(StringStream* stream) {
1407 stream->Add("%s ", GetCheckName());
1408 HUnaryOperation::PrintDataTo(stream);
1409}
1410
1411
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001412void HCheckPrototypeMaps::PrintDataTo(StringStream* stream) {
mvstanton@chromium.org6bec0092013-01-23 13:46:53 +00001413 stream->Add("[receiver_prototype=%p,holder=%p]",
1414 *prototypes_.first(), *prototypes_.last());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001415}
1416
1417
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001418void HCallStub::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001419 stream->Add("%s ",
1420 CodeStub::MajorName(major_key_, false));
1421 HUnaryCall::PrintDataTo(stream);
1422}
1423
1424
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001425void HInstanceOf::PrintDataTo(StringStream* stream) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001426 left()->PrintNameTo(stream);
1427 stream->Add(" ");
1428 right()->PrintNameTo(stream);
1429 stream->Add(" ");
1430 context()->PrintNameTo(stream);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001431}
1432
1433
ulan@chromium.org812308e2012-02-29 15:58:45 +00001434Range* HValue::InferRange(Zone* zone) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001435 // Untagged integer32 cannot be -0, all other representations can.
ulan@chromium.org812308e2012-02-29 15:58:45 +00001436 Range* result = new(zone) Range();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001437 result->set_can_be_minus_zero(!representation().IsInteger32());
1438 return result;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001439}
1440
1441
ulan@chromium.org812308e2012-02-29 15:58:45 +00001442Range* HChange::InferRange(Zone* zone) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001443 Range* input_range = value()->range();
1444 if (from().IsInteger32() &&
1445 to().IsTagged() &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001446 !value()->CheckFlag(HInstruction::kUint32) &&
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001447 input_range != NULL && input_range->IsInSmiRange()) {
1448 set_type(HType::Smi());
1449 }
1450 Range* result = (input_range != NULL)
ulan@chromium.org812308e2012-02-29 15:58:45 +00001451 ? input_range->Copy(zone)
1452 : HValue::InferRange(zone);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001453 if (to().IsInteger32()) result->set_can_be_minus_zero(false);
1454 return result;
1455}
1456
1457
ulan@chromium.org812308e2012-02-29 15:58:45 +00001458Range* HConstant::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001459 if (has_int32_value_) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001460 Range* result = new(zone) Range(int32_value_, int32_value_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001461 result->set_can_be_minus_zero(false);
1462 return result;
1463 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00001464 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001465}
1466
1467
ulan@chromium.org812308e2012-02-29 15:58:45 +00001468Range* HPhi::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001469 if (representation().IsInteger32()) {
1470 if (block()->IsLoopHeader()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001471 Range* range = new(zone) Range(kMinInt, kMaxInt);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001472 return range;
1473 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001474 Range* range = OperandAt(0)->range()->Copy(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001475 for (int i = 1; i < OperandCount(); ++i) {
1476 range->Union(OperandAt(i)->range());
1477 }
1478 return range;
1479 }
1480 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001481 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001482 }
1483}
1484
1485
ulan@chromium.org812308e2012-02-29 15:58:45 +00001486Range* HAdd::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001487 if (representation().IsInteger32()) {
1488 Range* a = left()->range();
1489 Range* b = right()->range();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001490 Range* res = a->Copy(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001491 if (!res->AddAndCheckOverflow(b)) {
1492 ClearFlag(kCanOverflow);
1493 }
1494 bool m0 = a->CanBeMinusZero() && b->CanBeMinusZero();
1495 res->set_can_be_minus_zero(m0);
1496 return res;
1497 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001498 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001499 }
1500}
1501
1502
ulan@chromium.org812308e2012-02-29 15:58:45 +00001503Range* HSub::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001504 if (representation().IsInteger32()) {
1505 Range* a = left()->range();
1506 Range* b = right()->range();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001507 Range* res = a->Copy(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001508 if (!res->SubAndCheckOverflow(b)) {
1509 ClearFlag(kCanOverflow);
1510 }
1511 res->set_can_be_minus_zero(a->CanBeMinusZero() && b->CanBeZero());
1512 return res;
1513 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001514 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001515 }
1516}
1517
1518
ulan@chromium.org812308e2012-02-29 15:58:45 +00001519Range* HMul::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001520 if (representation().IsInteger32()) {
1521 Range* a = left()->range();
1522 Range* b = right()->range();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001523 Range* res = a->Copy(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001524 if (!res->MulAndCheckOverflow(b)) {
1525 ClearFlag(kCanOverflow);
1526 }
1527 bool m0 = (a->CanBeZero() && b->CanBeNegative()) ||
1528 (a->CanBeNegative() && b->CanBeZero());
1529 res->set_can_be_minus_zero(m0);
1530 return res;
1531 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001532 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001533 }
1534}
1535
1536
ulan@chromium.org812308e2012-02-29 15:58:45 +00001537Range* HDiv::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001538 if (representation().IsInteger32()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001539 Range* result = new(zone) Range();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001540 if (left()->range()->CanBeMinusZero()) {
1541 result->set_can_be_minus_zero(true);
1542 }
1543
1544 if (left()->range()->CanBeZero() && right()->range()->CanBeNegative()) {
1545 result->set_can_be_minus_zero(true);
1546 }
1547
1548 if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) {
1549 SetFlag(HValue::kCanOverflow);
1550 }
1551
1552 if (!right()->range()->CanBeZero()) {
1553 ClearFlag(HValue::kCanBeDivByZero);
1554 }
1555 return result;
1556 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001557 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001558 }
1559}
1560
1561
ulan@chromium.org812308e2012-02-29 15:58:45 +00001562Range* HMod::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001563 if (representation().IsInteger32()) {
1564 Range* a = left()->range();
ulan@chromium.org812308e2012-02-29 15:58:45 +00001565 Range* result = new(zone) Range();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001566 if (a->CanBeMinusZero() || a->CanBeNegative()) {
1567 result->set_can_be_minus_zero(true);
1568 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001569
1570 if (right()->range()->Includes(-1) && left()->range()->Includes(kMinInt)) {
1571 SetFlag(HValue::kCanOverflow);
1572 }
1573
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001574 if (!right()->range()->CanBeZero()) {
1575 ClearFlag(HValue::kCanBeDivByZero);
1576 }
1577 return result;
1578 } else {
ulan@chromium.org812308e2012-02-29 15:58:45 +00001579 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001580 }
1581}
1582
1583
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001584void HPhi::AddInformativeDefinitions() {
1585 if (OperandCount() == 2) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00001586 // If one of the operands is an OSR block give up (this cannot be an
1587 // induction variable).
1588 if (OperandAt(0)->block()->is_osr_entry() ||
1589 OperandAt(1)->block()->is_osr_entry()) return;
1590
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001591 for (int operand_index = 0; operand_index < 2; operand_index++) {
1592 int other_operand_index = (operand_index + 1) % 2;
1593
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001594 static NumericRelation relations[] = {
1595 NumericRelation::Ge(),
1596 NumericRelation::Le()
1597 };
1598
1599 // Check if this phi is an induction variable. If, e.g., we know that
1600 // its first input is greater than the phi itself, then that must be
1601 // the back edge, and the phi is always greater than its second input.
1602 for (int relation_index = 0; relation_index < 2; relation_index++) {
1603 if (OperandAt(operand_index)->IsRelationTrue(relations[relation_index],
1604 this)) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00001605 HInductionVariableAnnotation::AddToGraph(this,
1606 relations[relation_index],
1607 other_operand_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001608 }
1609 }
1610 }
1611 }
1612}
1613
1614
ulan@chromium.org2e04b582013-02-21 14:06:02 +00001615bool HPhi::IsRelationTrueInternal(NumericRelation relation, HValue* other) {
1616 if (CheckFlag(kNumericConstraintEvaluationInProgress)) return false;
1617
1618 SetFlag(kNumericConstraintEvaluationInProgress);
1619 bool result = true;
1620 for (int i = 0; i < OperandCount(); i++) {
1621 // Skip OSR entry blocks
1622 if (OperandAt(i)->block()->is_osr_entry()) continue;
1623
1624 if (!OperandAt(i)->IsRelationTrue(relation, other)) {
1625 result = false;
1626 break;
1627 }
1628 }
1629 ClearFlag(kNumericConstraintEvaluationInProgress);
1630
1631 return result;
1632}
1633
1634
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001635Range* HMathMinMax::InferRange(Zone* zone) {
1636 if (representation().IsInteger32()) {
1637 Range* a = left()->range();
1638 Range* b = right()->range();
1639 Range* res = a->Copy(zone);
1640 if (operation_ == kMathMax) {
1641 res->CombinedMax(b);
1642 } else {
1643 ASSERT(operation_ == kMathMin);
1644 res->CombinedMin(b);
1645 }
1646 return res;
1647 } else {
1648 return HValue::InferRange(zone);
1649 }
1650}
1651
1652
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001653void HPhi::PrintTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001654 stream->Add("[");
1655 for (int i = 0; i < OperandCount(); ++i) {
1656 HValue* value = OperandAt(i);
1657 stream->Add(" ");
1658 value->PrintNameTo(stream);
1659 stream->Add(" ");
1660 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001661 stream->Add(" uses%d_%di_%dd_%dt",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001662 UseCount(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001663 int32_non_phi_uses() + int32_indirect_uses(),
1664 double_non_phi_uses() + double_indirect_uses(),
1665 tagged_non_phi_uses() + tagged_indirect_uses());
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001666 stream->Add("%s%s]",
1667 is_live() ? "_live" : "",
1668 IsConvertibleToInteger() ? "" : "_ncti");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001669}
1670
1671
1672void HPhi::AddInput(HValue* value) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001673 inputs_.Add(NULL, value->block()->zone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001674 SetOperandAt(OperandCount() - 1, value);
1675 // Mark phis that may have 'arguments' directly or indirectly as an operand.
1676 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) {
1677 SetFlag(kIsArguments);
1678 }
1679}
1680
1681
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001682bool HPhi::HasRealUses() {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001683 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1684 if (!it.value()->IsPhi()) return true;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001685 }
1686 return false;
1687}
1688
1689
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001690HValue* HPhi::GetRedundantReplacement() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001691 HValue* candidate = NULL;
1692 int count = OperandCount();
1693 int position = 0;
1694 while (position < count && candidate == NULL) {
1695 HValue* current = OperandAt(position++);
1696 if (current != this) candidate = current;
1697 }
1698 while (position < count) {
1699 HValue* current = OperandAt(position++);
1700 if (current != this && current != candidate) return NULL;
1701 }
1702 ASSERT(candidate != this);
1703 return candidate;
1704}
1705
1706
1707void HPhi::DeleteFromGraph() {
1708 ASSERT(block() != NULL);
1709 block()->RemovePhi(this);
1710 ASSERT(block() == NULL);
1711}
1712
1713
1714void HPhi::InitRealUses(int phi_id) {
1715 // Initialize real uses.
1716 phi_id_ = phi_id;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001717 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
1718 HValue* value = it.value();
1719 if (!value->IsPhi()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001720 Representation rep = value->observed_input_representation(it.index());
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001721 non_phi_uses_[rep.kind()] += value->LoopWeight();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001722 if (FLAG_trace_representation) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001723 PrintF("#%d Phi is used by real #%d %s as %s\n",
1724 id(), value->id(), value->Mnemonic(), rep.Mnemonic());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001725 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001726 }
1727 }
1728}
1729
1730
1731void HPhi::AddNonPhiUsesFrom(HPhi* other) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001732 if (FLAG_trace_representation) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001733 PrintF("adding to #%d Phi uses of #%d Phi: i%d d%d t%d\n",
1734 id(), other->id(),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001735 other->non_phi_uses_[Representation::kInteger32],
1736 other->non_phi_uses_[Representation::kDouble],
1737 other->non_phi_uses_[Representation::kTagged]);
1738 }
1739
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001740 for (int i = 0; i < Representation::kNumRepresentations; i++) {
1741 indirect_uses_[i] += other->non_phi_uses_[i];
1742 }
1743}
1744
1745
1746void HPhi::AddIndirectUsesTo(int* dest) {
1747 for (int i = 0; i < Representation::kNumRepresentations; i++) {
1748 dest[i] += indirect_uses_[i];
1749 }
1750}
1751
1752
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001753void HSimulate::MergeInto(HSimulate* other) {
1754 for (int i = 0; i < values_.length(); ++i) {
1755 HValue* value = values_[i];
1756 if (HasAssignedIndexAt(i)) {
1757 other->AddAssignedValue(GetAssignedIndexAt(i), value);
1758 } else {
1759 if (other->pop_count_ > 0) {
1760 other->pop_count_--;
1761 } else {
1762 other->AddPushedValue(value);
1763 }
1764 }
1765 }
1766 other->pop_count_ += pop_count();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001767}
1768
1769
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001770void HSimulate::PrintDataTo(StringStream* stream) {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001771 stream->Add("id=%d", ast_id().ToInt());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001772 if (pop_count_ > 0) stream->Add(" pop %d", pop_count_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001773 if (values_.length() > 0) {
1774 if (pop_count_ > 0) stream->Add(" /");
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001775 for (int i = values_.length() - 1; i >= 0; --i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001776 if (i > 0) stream->Add(",");
1777 if (HasAssignedIndexAt(i)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001778 stream->Add(" var[%d] = ", GetAssignedIndexAt(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001779 } else {
1780 stream->Add(" push ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001781 }
1782 values_[i]->PrintNameTo(stream);
1783 }
1784 }
1785}
1786
1787
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00001788void HDeoptimize::PrintDataTo(StringStream* stream) {
1789 if (OperandCount() == 0) return;
1790 OperandAt(0)->PrintNameTo(stream);
1791 for (int i = 1; i < OperandCount(); ++i) {
1792 stream->Add(" ");
1793 OperandAt(i)->PrintNameTo(stream);
1794 }
1795}
1796
1797
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001798void HEnterInlined::PrintDataTo(StringStream* stream) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001799 SmartArrayPointer<char> name = function()->debug_name()->ToCString();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001800 stream->Add("%s, id=%d", *name, function()->id().ToInt());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001801}
1802
1803
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001804static bool IsInteger32(double value) {
1805 double roundtrip_value = static_cast<double>(static_cast<int32_t>(value));
1806 return BitCast<int64_t>(roundtrip_value) == BitCast<int64_t>(value);
1807}
1808
1809
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001810HConstant::HConstant(Handle<Object> handle, Representation r)
1811 : handle_(handle),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001812 has_int32_value_(false),
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001813 has_double_value_(false) {
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001814 // Dereferencing here is safe: the value of a number object does not change.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001815 AllowHandleDereference allow_handle_deref(Isolate::Current());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001816 if (handle_->IsNumber()) {
1817 double n = handle_->Number();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001818 has_int32_value_ = IsInteger32(n);
1819 int32_value_ = DoubleToInt32(n);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001820 double_value_ = n;
1821 has_double_value_ = true;
1822 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001823 if (r.IsNone()) {
1824 if (has_int32_value_) {
1825 r = Representation::Integer32();
1826 } else if (has_double_value_) {
1827 r = Representation::Double();
1828 } else {
1829 r = Representation::Tagged();
1830 }
1831 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001832 Initialize(r);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001833}
1834
1835
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001836HConstant::HConstant(int32_t integer_value, Representation r)
1837 : has_int32_value_(true),
1838 has_double_value_(true),
1839 int32_value_(integer_value),
1840 double_value_(FastI2D(integer_value)) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001841 Initialize(r);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001842}
1843
1844
1845HConstant::HConstant(double double_value, Representation r)
1846 : has_int32_value_(IsInteger32(double_value)),
1847 has_double_value_(true),
1848 int32_value_(DoubleToInt32(double_value)),
1849 double_value_(double_value) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001850 Initialize(r);
1851}
1852
1853
1854void HConstant::Initialize(Representation r) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001855 set_representation(r);
1856 SetFlag(kUseGVN);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001857 if (representation().IsInteger32()) {
1858 ClearGVNFlag(kDependsOnOsrEntries);
1859 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001860}
1861
1862
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001863HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001864 if (r.IsInteger32() && !has_int32_value_) return NULL;
1865 if (r.IsDouble() && !has_double_value_) return NULL;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001866 if (handle_.is_null()) {
1867 ASSERT(has_int32_value_ || has_double_value_);
1868 if (has_int32_value_) return new(zone) HConstant(int32_value_, r);
1869 return new(zone) HConstant(double_value_, r);
1870 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001871 return new(zone) HConstant(handle_, r);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001872}
1873
1874
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001875HConstant* HConstant::CopyToTruncatedInt32(Zone* zone) const {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001876 if (has_int32_value_) {
1877 if (handle_.is_null()) {
1878 return new(zone) HConstant(int32_value_, Representation::Integer32());
1879 } else {
1880 // Re-use the existing Handle if possible.
1881 return new(zone) HConstant(handle_, Representation::Integer32());
1882 }
1883 } else if (has_double_value_) {
1884 return new(zone) HConstant(DoubleToInt32(double_value_),
1885 Representation::Integer32());
1886 } else {
1887 return NULL;
1888 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001889}
1890
1891
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001892bool HConstant::ToBoolean() {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001893 // Converts the constant's boolean value according to
1894 // ECMAScript section 9.2 ToBoolean conversion.
1895 if (HasInteger32Value()) return Integer32Value() != 0;
1896 if (HasDoubleValue()) {
1897 double v = DoubleValue();
1898 return v != 0 && !isnan(v);
1899 }
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001900 // Dereferencing is safe: singletons do not change and strings are
1901 // immutable.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001902 AllowHandleDereference allow_handle_deref(isolate());
yangguo@chromium.org003650e2013-01-24 16:31:08 +00001903 if (handle_->IsTrue()) return true;
1904 if (handle_->IsFalse()) return false;
1905 if (handle_->IsUndefined()) return false;
1906 if (handle_->IsNull()) return false;
1907 if (handle_->IsString() && String::cast(*handle_)->length() == 0) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001908 return false;
1909 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001910 return true;
1911}
1912
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001913void HConstant::PrintDataTo(StringStream* stream) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001914 if (has_int32_value_) {
1915 stream->Add("%d ", int32_value_);
1916 } else if (has_double_value_) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001917 stream->Add("%f ", FmtElm(double_value_));
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001918 } else {
1919 handle()->ShortPrint(stream);
1920 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001921}
1922
1923
1924bool HArrayLiteral::IsCopyOnWrite() const {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001925 if (!boilerplate_object_->IsJSObject()) return false;
1926 return Handle<JSObject>::cast(boilerplate_object_)->elements()->map() ==
1927 HEAP->fixed_cow_array_map();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001928}
1929
1930
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001931void HBinaryOperation::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001932 left()->PrintNameTo(stream);
1933 stream->Add(" ");
1934 right()->PrintNameTo(stream);
1935 if (CheckFlag(kCanOverflow)) stream->Add(" !");
1936 if (CheckFlag(kBailoutOnMinusZero)) stream->Add(" -0?");
1937}
1938
1939
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001940void HBinaryOperation::InferRepresentation(HInferRepresentation* h_infer) {
1941 ASSERT(CheckFlag(kFlexibleRepresentation));
1942 Representation new_rep = RepresentationFromInputs();
1943 UpdateRepresentation(new_rep, h_infer, "inputs");
1944 // When the operation has information about its own output type, don't look
1945 // at uses.
1946 if (!observed_output_representation_.IsNone()) return;
1947 new_rep = RepresentationFromUses();
1948 UpdateRepresentation(new_rep, h_infer, "uses");
1949}
1950
1951
1952Representation HBinaryOperation::RepresentationFromInputs() {
1953 // Determine the worst case of observed input representations and
1954 // the currently assumed output representation.
1955 Representation rep = representation();
1956 if (observed_output_representation_.is_more_general_than(rep)) {
1957 rep = observed_output_representation_;
1958 }
1959 for (int i = 1; i <= 2; ++i) {
1960 Representation input_rep = observed_input_representation(i);
1961 if (input_rep.is_more_general_than(rep)) rep = input_rep;
1962 }
1963 // If any of the actual input representation is more general than what we
1964 // have so far but not Tagged, use that representation instead.
1965 Representation left_rep = left()->representation();
1966 Representation right_rep = right()->representation();
1967
1968 if (left_rep.is_more_general_than(rep) &&
1969 left()->CheckFlag(kFlexibleRepresentation)) {
1970 rep = left_rep;
1971 }
1972 if (right_rep.is_more_general_than(rep) &&
1973 right()->CheckFlag(kFlexibleRepresentation)) {
1974 rep = right_rep;
1975 }
1976 return rep;
1977}
1978
1979
1980void HBinaryOperation::AssumeRepresentation(Representation r) {
1981 set_observed_input_representation(r, r);
1982 HValue::AssumeRepresentation(r);
1983}
1984
1985
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001986void HMathMinMax::InferRepresentation(HInferRepresentation* h_infer) {
1987 ASSERT(CheckFlag(kFlexibleRepresentation));
1988 Representation new_rep = RepresentationFromInputs();
1989 UpdateRepresentation(new_rep, h_infer, "inputs");
1990 // Do not care about uses.
1991}
1992
1993
ulan@chromium.org812308e2012-02-29 15:58:45 +00001994Range* HBitwise::InferRange(Zone* zone) {
1995 if (op() == Token::BIT_XOR) return HValue::InferRange(zone);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001996 const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001997 int32_t left_mask = (left()->range() != NULL)
1998 ? left()->range()->Mask()
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001999 : kDefaultMask;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002000 int32_t right_mask = (right()->range() != NULL)
2001 ? right()->range()->Mask()
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00002002 : kDefaultMask;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002003 int32_t result_mask = (op() == Token::BIT_AND)
2004 ? left_mask & right_mask
2005 : left_mask | right_mask;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002006 return (result_mask >= 0)
ulan@chromium.org812308e2012-02-29 15:58:45 +00002007 ? new(zone) Range(0, result_mask)
2008 : HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002009}
2010
2011
ulan@chromium.org812308e2012-02-29 15:58:45 +00002012Range* HSar::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002013 if (right()->IsConstant()) {
2014 HConstant* c = HConstant::cast(right());
2015 if (c->HasInteger32Value()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002016 Range* result = (left()->range() != NULL)
ulan@chromium.org812308e2012-02-29 15:58:45 +00002017 ? left()->range()->Copy(zone)
2018 : new(zone) Range();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002019 result->Sar(c->Integer32Value());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002020 result->set_can_be_minus_zero(false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002021 return result;
2022 }
2023 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00002024 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002025}
2026
2027
ulan@chromium.org812308e2012-02-29 15:58:45 +00002028Range* HShr::InferRange(Zone* zone) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002029 if (right()->IsConstant()) {
2030 HConstant* c = HConstant::cast(right());
2031 if (c->HasInteger32Value()) {
2032 int shift_count = c->Integer32Value() & 0x1f;
2033 if (left()->range()->CanBeNegative()) {
2034 // Only compute bounds if the result always fits into an int32.
2035 return (shift_count >= 1)
ulan@chromium.org812308e2012-02-29 15:58:45 +00002036 ? new(zone) Range(0,
2037 static_cast<uint32_t>(0xffffffff) >> shift_count)
2038 : new(zone) Range();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002039 } else {
2040 // For positive inputs we can use the >> operator.
2041 Range* result = (left()->range() != NULL)
ulan@chromium.org812308e2012-02-29 15:58:45 +00002042 ? left()->range()->Copy(zone)
2043 : new(zone) Range();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002044 result->Sar(c->Integer32Value());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002045 result->set_can_be_minus_zero(false);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002046 return result;
2047 }
2048 }
2049 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00002050 return HValue::InferRange(zone);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002051}
2052
2053
ulan@chromium.org812308e2012-02-29 15:58:45 +00002054Range* HShl::InferRange(Zone* zone) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002055 if (right()->IsConstant()) {
2056 HConstant* c = HConstant::cast(right());
2057 if (c->HasInteger32Value()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002058 Range* result = (left()->range() != NULL)
ulan@chromium.org812308e2012-02-29 15:58:45 +00002059 ? left()->range()->Copy(zone)
2060 : new(zone) Range();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002061 result->Shl(c->Integer32Value());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002062 result->set_can_be_minus_zero(false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002063 return result;
2064 }
2065 }
ulan@chromium.org812308e2012-02-29 15:58:45 +00002066 return HValue::InferRange(zone);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002067}
2068
2069
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002070Range* HLoadKeyed::InferRange(Zone* zone) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002071 switch (elements_kind()) {
2072 case EXTERNAL_PIXEL_ELEMENTS:
ulan@chromium.org812308e2012-02-29 15:58:45 +00002073 return new(zone) Range(0, 255);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002074 case EXTERNAL_BYTE_ELEMENTS:
ulan@chromium.org812308e2012-02-29 15:58:45 +00002075 return new(zone) Range(-128, 127);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002076 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
ulan@chromium.org812308e2012-02-29 15:58:45 +00002077 return new(zone) Range(0, 255);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002078 case EXTERNAL_SHORT_ELEMENTS:
ulan@chromium.org812308e2012-02-29 15:58:45 +00002079 return new(zone) Range(-32768, 32767);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002080 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
ulan@chromium.org812308e2012-02-29 15:58:45 +00002081 return new(zone) Range(0, 65535);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002082 default:
ulan@chromium.org812308e2012-02-29 15:58:45 +00002083 return HValue::InferRange(zone);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002084 }
2085}
2086
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002087
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002088void HCompareGeneric::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002089 stream->Add(Token::Name(token()));
2090 stream->Add(" ");
2091 HBinaryOperation::PrintDataTo(stream);
2092}
2093
2094
erikcorry0ad885c2011-11-21 13:51:57 +00002095void HStringCompareAndBranch::PrintDataTo(StringStream* stream) {
2096 stream->Add(Token::Name(token()));
2097 stream->Add(" ");
2098 HControlInstruction::PrintDataTo(stream);
2099}
2100
2101
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002102void HCompareIDAndBranch::AddInformativeDefinitions() {
2103 NumericRelation r = NumericRelation::FromToken(token());
2104 if (r.IsNone()) return;
2105
2106 HNumericConstraint::AddToGraph(left(), r, right(), SuccessorAt(0)->first());
2107 HNumericConstraint::AddToGraph(
2108 left(), r.Negated(), right(), SuccessorAt(1)->first());
2109}
2110
2111
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002112void HCompareIDAndBranch::PrintDataTo(StringStream* stream) {
2113 stream->Add(Token::Name(token()));
2114 stream->Add(" ");
2115 left()->PrintNameTo(stream);
2116 stream->Add(" ");
2117 right()->PrintNameTo(stream);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002118 HControlInstruction::PrintDataTo(stream);
2119}
2120
2121
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002122void HCompareObjectEqAndBranch::PrintDataTo(StringStream* stream) {
2123 left()->PrintNameTo(stream);
2124 stream->Add(" ");
2125 right()->PrintNameTo(stream);
2126 HControlInstruction::PrintDataTo(stream);
2127}
2128
2129
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002130void HGoto::PrintDataTo(StringStream* stream) {
2131 stream->Add("B%d", SuccessorAt(0)->block_id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002132}
2133
2134
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002135void HCompareIDAndBranch::InferRepresentation(HInferRepresentation* h_infer) {
2136 Representation rep = Representation::None();
2137 Representation left_rep = left()->representation();
2138 Representation right_rep = right()->representation();
2139 bool observed_integers =
2140 observed_input_representation(0).IsInteger32() &&
2141 observed_input_representation(1).IsInteger32();
2142 bool inputs_are_not_doubles =
2143 !left_rep.IsDouble() && !right_rep.IsDouble();
2144 if (observed_integers && inputs_are_not_doubles) {
2145 rep = Representation::Integer32();
2146 } else {
2147 rep = Representation::Double();
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00002148 // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, ===
2149 // and !=) have special handling of undefined, e.g. undefined == undefined
2150 // is 'true'. Relational comparisons have a different semantic, first
2151 // calling ToPrimitive() on their arguments. The standard Crankshaft
2152 // tagged-to-double conversion to ensure the HCompareIDAndBranch's inputs
2153 // are doubles caused 'undefined' to be converted to NaN. That's compatible
2154 // out-of-the box with ordered relational comparisons (<, >, <=,
2155 // >=). However, for equality comparisons (and for 'in' and 'instanceof'),
2156 // it is not consistent with the spec. For example, it would cause undefined
2157 // == undefined (should be true) to be evaluated as NaN == NaN
2158 // (false). Therefore, any comparisons other than ordered relational
2159 // comparisons must cause a deopt when one of their arguments is undefined.
2160 // See also v8:1434
2161 if (!Token::IsOrderedRelationalCompareOp(token_)) {
2162 SetFlag(kDeoptimizeOnUndefined);
2163 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002164 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002165 ChangeRepresentation(rep);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002166}
2167
2168
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002169void HParameter::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170 stream->Add("%u", index());
2171}
2172
2173
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002174void HLoadNamedField::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002175 object()->PrintNameTo(stream);
2176 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
2177}
2178
2179
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002180// Returns true if an instance of this map can never find a property with this
2181// name in its prototype chain. This means all prototypes up to the top are
2182// fast and don't have the name in them. It would be good if we could optimize
2183// polymorphic loads where the property is sometimes found in the prototype
2184// chain.
2185static bool PrototypeChainCanNeverResolve(
2186 Handle<Map> map, Handle<String> name) {
2187 Isolate* isolate = map->GetIsolate();
2188 Object* current = map->prototype();
2189 while (current != isolate->heap()->null_value()) {
2190 if (current->IsJSGlobalProxy() ||
2191 current->IsGlobalObject() ||
2192 !current->IsJSObject() ||
erik.corry@gmail.com88767242012-08-08 14:43:45 +00002193 JSObject::cast(current)->map()->has_named_interceptor() ||
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002194 JSObject::cast(current)->IsAccessCheckNeeded() ||
2195 !JSObject::cast(current)->HasFastProperties()) {
2196 return false;
2197 }
2198
2199 LookupResult lookup(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002200 Map* map = JSObject::cast(current)->map();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002201 map->LookupDescriptor(NULL, *name, &lookup);
2202 if (lookup.IsFound()) return false;
2203 if (!lookup.IsCacheable()) return false;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002204 current = JSObject::cast(current)->GetPrototype();
2205 }
2206 return true;
2207}
2208
2209
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002210HLoadNamedFieldPolymorphic::HLoadNamedFieldPolymorphic(HValue* context,
2211 HValue* object,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002212 SmallMapList* types,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002213 Handle<String> name,
2214 Zone* zone)
2215 : types_(Min(types->length(), kMaxLoadPolymorphism), zone),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002216 name_(name),
2217 need_generic_(false) {
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00002218 SetOperandAt(0, context);
2219 SetOperandAt(1, object);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002220 set_representation(Representation::Tagged());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002221 SetGVNFlag(kDependsOnMaps);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002222 SmallMapList negative_lookups;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002223 for (int i = 0;
2224 i < types->length() && types_.length() < kMaxLoadPolymorphism;
2225 ++i) {
2226 Handle<Map> map = types->at(i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002227 LookupResult lookup(map->GetIsolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002228 map->LookupDescriptor(NULL, *name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002229 if (lookup.IsFound()) {
lrn@chromium.org1c092762011-05-09 09:42:16 +00002230 switch (lookup.type()) {
2231 case FIELD: {
2232 int index = lookup.GetLocalFieldIndexFromMap(*map);
2233 if (index < 0) {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002234 SetGVNFlag(kDependsOnInobjectFields);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002235 } else {
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00002236 SetGVNFlag(kDependsOnBackingStoreFields);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002237 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002238 types_.Add(types->at(i), zone);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002239 break;
2240 }
2241 case CONSTANT_FUNCTION:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002242 types_.Add(types->at(i), zone);
lrn@chromium.org1c092762011-05-09 09:42:16 +00002243 break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002244 case CALLBACKS:
2245 break;
2246 case TRANSITION:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002247 case INTERCEPTOR:
2248 case NONEXISTENT:
2249 case NORMAL:
2250 case HANDLER:
2251 UNREACHABLE();
lrn@chromium.org1c092762011-05-09 09:42:16 +00002252 break;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002253 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002254 } else if (lookup.IsCacheable() &&
erik.corry@gmail.com88767242012-08-08 14:43:45 +00002255 // For dicts the lookup on the map will fail, but the object may
2256 // contain the property so we cannot generate a negative lookup
2257 // (which would just be a map check and return undefined).
2258 !map->is_dictionary_map() &&
2259 !map->has_named_interceptor() &&
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002260 PrototypeChainCanNeverResolve(map, name)) {
2261 negative_lookups.Add(types->at(i), zone);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002262 }
2263 }
2264
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002265 bool need_generic =
2266 (types->length() != negative_lookups.length() + types_.length());
2267 if (!need_generic && FLAG_deoptimize_uncommon_cases) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002268 SetFlag(kUseGVN);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002269 for (int i = 0; i < negative_lookups.length(); i++) {
2270 types_.Add(negative_lookups.at(i), zone);
2271 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002272 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002273 // We don't have an easy way to handle both a call (to the generic stub) and
2274 // a deopt in the same hydrogen instruction, so in this case we don't add
2275 // the negative lookups which can deopt - just let the generic stub handle
2276 // them.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002277 SetAllSideEffects();
2278 need_generic_ = true;
2279 }
2280}
2281
2282
2283bool HLoadNamedFieldPolymorphic::DataEquals(HValue* value) {
2284 HLoadNamedFieldPolymorphic* other = HLoadNamedFieldPolymorphic::cast(value);
2285 if (types_.length() != other->types()->length()) return false;
2286 if (!name_.is_identical_to(other->name())) return false;
2287 if (need_generic_ != other->need_generic_) return false;
2288 for (int i = 0; i < types_.length(); i++) {
2289 bool found = false;
2290 for (int j = 0; j < types_.length(); j++) {
2291 if (types_.at(j).is_identical_to(other->types()->at(i))) {
2292 found = true;
2293 break;
2294 }
2295 }
2296 if (!found) return false;
2297 }
2298 return true;
2299}
2300
2301
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002302void HLoadNamedFieldPolymorphic::PrintDataTo(StringStream* stream) {
2303 object()->PrintNameTo(stream);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002304 stream->Add(".");
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002305 stream->Add(*String::cast(*name())->ToCString());
2306}
2307
2308
2309void HLoadNamedGeneric::PrintDataTo(StringStream* stream) {
2310 object()->PrintNameTo(stream);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002311 stream->Add(".");
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00002312 stream->Add(*String::cast(*name())->ToCString());
2313}
2314
2315
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002316void HLoadKeyed::PrintDataTo(StringStream* stream) {
2317 if (!is_external()) {
2318 elements()->PrintNameTo(stream);
2319 } else {
2320 ASSERT(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
2321 elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
2322 elements()->PrintNameTo(stream);
2323 stream->Add(".");
2324 stream->Add(ElementsKindToString(elements_kind()));
2325 }
2326
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002327 stream->Add("[");
2328 key()->PrintNameTo(stream);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002329 if (IsDehoisted()) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002330 stream->Add(" + %d]", index_offset());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002331 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002332 stream->Add("]");
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002333 }
2334
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002335 if (HasDependency()) {
2336 stream->Add(" ");
2337 dependency()->PrintNameTo(stream);
2338 }
2339
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002340 if (RequiresHoleCheck()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002341 stream->Add(" check_hole");
2342 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002343}
2344
2345
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002346bool HLoadKeyed::UsesMustHandleHole() const {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002347 if (IsFastPackedElementsKind(elements_kind())) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002348 return false;
2349 }
2350
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002351 if (hole_mode() == ALLOW_RETURN_HOLE) return true;
2352
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002353 if (IsFastDoubleElementsKind(elements_kind())) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002354 return false;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002355 }
2356
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002357 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
2358 HValue* use = it.value();
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002359 if (!use->IsChange()) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002360 return false;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002361 }
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002362 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002363
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002364 return true;
2365}
2366
2367
2368bool HLoadKeyed::RequiresHoleCheck() const {
2369 if (IsFastPackedElementsKind(elements_kind())) {
2370 return false;
2371 }
2372
2373 return !UsesMustHandleHole();
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002374}
2375
2376
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002377void HLoadKeyedGeneric::PrintDataTo(StringStream* stream) {
2378 object()->PrintNameTo(stream);
2379 stream->Add("[");
2380 key()->PrintNameTo(stream);
2381 stream->Add("]");
2382}
2383
2384
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002385HValue* HLoadKeyedGeneric::Canonicalize() {
2386 // Recognize generic keyed loads that use property name generated
2387 // by for-in statement as a key and rewrite them into fast property load
2388 // by index.
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002389 if (key()->IsLoadKeyed()) {
2390 HLoadKeyed* key_load = HLoadKeyed::cast(key());
2391 if (key_load->elements()->IsForInCacheArray()) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002392 HForInCacheArray* names_cache =
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002393 HForInCacheArray::cast(key_load->elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002394
2395 if (names_cache->enumerable() == object()) {
2396 HForInCacheArray* index_cache =
2397 names_cache->index_cache();
2398 HCheckMapValue* map_check =
2399 new(block()->zone()) HCheckMapValue(object(), names_cache->map());
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002400 HInstruction* index = new(block()->zone()) HLoadKeyed(
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002401 index_cache,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002402 key_load->key(),
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002403 key_load->key(),
2404 key_load->elements_kind());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002405 map_check->InsertBefore(this);
2406 index->InsertBefore(this);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002407 HLoadFieldByIndex* load = new(block()->zone()) HLoadFieldByIndex(
2408 object(), index);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002409 load->InsertBefore(this);
2410 return load;
2411 }
2412 }
2413 }
2414
2415 return this;
2416}
2417
2418
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002419void HStoreNamedGeneric::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002420 object()->PrintNameTo(stream);
2421 stream->Add(".");
2422 ASSERT(name()->IsString());
2423 stream->Add(*String::cast(*name())->ToCString());
2424 stream->Add(" = ");
2425 value()->PrintNameTo(stream);
2426}
2427
2428
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002429void HStoreNamedField::PrintDataTo(StringStream* stream) {
2430 object()->PrintNameTo(stream);
2431 stream->Add(".");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002432 stream->Add(*String::cast(*name())->ToCString());
2433 stream->Add(" = ");
2434 value()->PrintNameTo(stream);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002435 stream->Add(" @%d%s", offset(), is_in_object() ? "[in-object]" : "");
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002436 if (NeedsWriteBarrier()) {
2437 stream->Add(" (write-barrier)");
2438 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002439 if (!transition().is_null()) {
2440 stream->Add(" (transition map %p)", *transition());
2441 }
2442}
2443
2444
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002445void HStoreKeyed::PrintDataTo(StringStream* stream) {
2446 if (!is_external()) {
2447 elements()->PrintNameTo(stream);
2448 } else {
2449 elements()->PrintNameTo(stream);
2450 stream->Add(".");
2451 stream->Add(ElementsKindToString(elements_kind()));
2452 ASSERT(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND &&
2453 elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND);
2454 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002455
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002456 stream->Add("[");
2457 key()->PrintNameTo(stream);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002458 if (IsDehoisted()) {
2459 stream->Add(" + %d] = ", index_offset());
2460 } else {
2461 stream->Add("] = ");
2462 }
2463
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002464 value()->PrintNameTo(stream);
2465}
2466
2467
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002468void HStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
2469 object()->PrintNameTo(stream);
2470 stream->Add("[");
2471 key()->PrintNameTo(stream);
2472 stream->Add("] = ");
2473 value()->PrintNameTo(stream);
2474}
2475
2476
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002477void HTransitionElementsKind::PrintDataTo(StringStream* stream) {
2478 object()->PrintNameTo(stream);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002479 ElementsKind from_kind = original_map()->elements_kind();
2480 ElementsKind to_kind = transitioned_map()->elements_kind();
2481 stream->Add(" %p [%s] -> %p [%s]",
2482 *original_map(),
2483 ElementsAccessor::ForKind(from_kind)->name(),
2484 *transitioned_map(),
2485 ElementsAccessor::ForKind(to_kind)->name());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002486}
2487
2488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002489void HLoadGlobalCell::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002490 stream->Add("[%p]", *cell());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002491 if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
2492 if (details_.IsReadOnly()) stream->Add(" (read-only)");
2493}
2494
2495
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002496bool HLoadGlobalCell::RequiresHoleCheck() const {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002497 if (details_.IsDontDelete() && !details_.IsReadOnly()) return false;
2498 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
2499 HValue* use = it.value();
2500 if (!use->IsChange()) return true;
2501 }
2502 return false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002503}
2504
2505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002506void HLoadGlobalGeneric::PrintDataTo(StringStream* stream) {
2507 stream->Add("%o ", *name());
2508}
2509
2510
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002511void HStoreGlobalCell::PrintDataTo(StringStream* stream) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512 stream->Add("[%p] = ", *cell());
2513 value()->PrintNameTo(stream);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002514 if (!details_.IsDontDelete()) stream->Add(" (deleteable)");
2515 if (details_.IsReadOnly()) stream->Add(" (read-only)");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002516}
2517
2518
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002519void HStoreGlobalGeneric::PrintDataTo(StringStream* stream) {
2520 stream->Add("%o = ", *name());
2521 value()->PrintNameTo(stream);
2522}
2523
2524
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002525void HLoadContextSlot::PrintDataTo(StringStream* stream) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002526 value()->PrintNameTo(stream);
2527 stream->Add("[%d]", slot_index());
2528}
2529
2530
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002531void HStoreContextSlot::PrintDataTo(StringStream* stream) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002532 context()->PrintNameTo(stream);
2533 stream->Add("[%d] = ", slot_index());
2534 value()->PrintNameTo(stream);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002535}
2536
2537
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002538// Implementation of type inference and type conversions. Calculates
2539// the inferred type of this instruction based on the input operands.
2540
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002541HType HValue::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002542 return type_;
2543}
2544
2545
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00002546HType HCheckMaps::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002547 return value()->type();
2548}
2549
2550
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002551HType HCheckFunction::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002552 return value()->type();
2553}
2554
2555
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002556HType HCheckNonSmi::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002557 // TODO(kasperl): Is there any way to signal that this isn't a smi?
2558 return HType::Tagged();
2559}
2560
2561
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002562HType HCheckSmi::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002563 return HType::Smi();
2564}
2565
2566
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002567void HCheckSmiOrInt32::InferRepresentation(HInferRepresentation* h_infer) {
2568 ASSERT(CheckFlag(kFlexibleRepresentation));
2569 Representation r = value()->representation().IsTagged()
2570 ? Representation::Tagged() : Representation::Integer32();
2571 UpdateRepresentation(r, h_infer, "checksmiorint32");
2572}
2573
2574
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002575HType HPhi::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002576 HType result = HType::Uninitialized();
2577 for (int i = 0; i < OperandCount(); ++i) {
2578 HType current = OperandAt(i)->type();
2579 result = result.Combine(current);
2580 }
2581 return result;
2582}
2583
2584
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002585HType HConstant::CalculateInferredType() {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002586 if (has_int32_value_) {
2587 return Smi::IsValid(int32_value_) ? HType::Smi() : HType::HeapNumber();
2588 }
2589 if (has_double_value_) return HType::HeapNumber();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002590 return HType::TypeFromValue(isolate(), handle_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002591}
2592
2593
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002594HType HCompareGeneric::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002595 return HType::Boolean();
2596}
2597
2598
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002599HType HInstanceOf::CalculateInferredType() {
2600 return HType::Boolean();
2601}
2602
2603
2604HType HDeleteProperty::CalculateInferredType() {
2605 return HType::Boolean();
2606}
2607
2608
2609HType HInstanceOfKnownGlobal::CalculateInferredType() {
2610 return HType::Boolean();
2611}
2612
2613
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002614HType HChange::CalculateInferredType() {
2615 if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber();
2616 return type();
2617}
2618
2619
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002620HType HBitwiseBinaryOperation::CalculateInferredType() {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002621 return HType::TaggedNumber();
2622}
2623
2624
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002625HType HArithmeticBinaryOperation::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002626 return HType::TaggedNumber();
2627}
2628
2629
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002630HType HAdd::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002631 return HType::Tagged();
2632}
2633
2634
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002635HType HBitNot::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002636 return HType::TaggedNumber();
2637}
2638
2639
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002640HType HUnaryMathOperation::CalculateInferredType() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002641 return HType::TaggedNumber();
2642}
2643
2644
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002645HType HStringCharFromCode::CalculateInferredType() {
2646 return HType::String();
2647}
2648
2649
ulan@chromium.org967e2702012-02-28 09:49:15 +00002650HType HAllocateObject::CalculateInferredType() {
2651 return HType::JSObject();
2652}
2653
2654
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002655HType HAllocate::CalculateInferredType() {
2656 return type_;
2657}
2658
2659
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002660HType HFastLiteral::CalculateInferredType() {
2661 // TODO(mstarzinger): Be smarter, could also be JSArray here.
2662 return HType::JSObject();
2663}
2664
2665
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002666HType HArrayLiteral::CalculateInferredType() {
2667 return HType::JSArray();
2668}
2669
2670
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002671HType HObjectLiteral::CalculateInferredType() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002672 return HType::JSObject();
2673}
2674
2675
2676HType HRegExpLiteral::CalculateInferredType() {
2677 return HType::JSObject();
2678}
2679
2680
2681HType HFunctionLiteral::CalculateInferredType() {
2682 return HType::JSObject();
2683}
2684
2685
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002686HValue* HUnaryMathOperation::EnsureAndPropagateNotMinusZero(
2687 BitVector* visited) {
2688 visited->Add(id());
2689 if (representation().IsInteger32() &&
2690 !value()->representation().IsInteger32()) {
2691 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
2692 SetFlag(kBailoutOnMinusZero);
2693 }
2694 }
2695 if (RequiredInputRepresentation(0).IsInteger32() &&
2696 representation().IsInteger32()) {
2697 return value();
2698 }
2699 return NULL;
2700}
2701
2702
2703
2704HValue* HChange::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2705 visited->Add(id());
2706 if (from().IsInteger32()) return NULL;
2707 if (CanTruncateToInt32()) return NULL;
2708 if (value()->range() == NULL || value()->range()->CanBeMinusZero()) {
2709 SetFlag(kBailoutOnMinusZero);
2710 }
2711 ASSERT(!from().IsInteger32() || !to().IsInteger32());
2712 return NULL;
2713}
2714
2715
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00002716HValue* HForceRepresentation::EnsureAndPropagateNotMinusZero(
2717 BitVector* visited) {
2718 visited->Add(id());
2719 return value();
2720}
2721
2722
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002723HValue* HMod::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2724 visited->Add(id());
2725 if (range() == NULL || range()->CanBeMinusZero()) {
2726 SetFlag(kBailoutOnMinusZero);
2727 return left();
2728 }
2729 return NULL;
2730}
2731
2732
2733HValue* HDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2734 visited->Add(id());
2735 if (range() == NULL || range()->CanBeMinusZero()) {
2736 SetFlag(kBailoutOnMinusZero);
2737 }
2738 return NULL;
2739}
2740
2741
yangguo@chromium.orgd2899aa2012-06-21 11:16:20 +00002742HValue* HMathFloorOfDiv::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2743 visited->Add(id());
2744 SetFlag(kBailoutOnMinusZero);
2745 return NULL;
2746}
2747
2748
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002749HValue* HMul::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2750 visited->Add(id());
2751 if (range() == NULL || range()->CanBeMinusZero()) {
2752 SetFlag(kBailoutOnMinusZero);
2753 }
2754 return NULL;
2755}
2756
2757
2758HValue* HSub::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2759 visited->Add(id());
2760 // Propagate to the left argument. If the left argument cannot be -0, then
2761 // the result of the add operation cannot be either.
2762 if (range() == NULL || range()->CanBeMinusZero()) {
2763 return left();
2764 }
2765 return NULL;
2766}
2767
2768
2769HValue* HAdd::EnsureAndPropagateNotMinusZero(BitVector* visited) {
2770 visited->Add(id());
2771 // Propagate to the left argument. If the left argument cannot be -0, then
2772 // the result of the sub operation cannot be either.
2773 if (range() == NULL || range()->CanBeMinusZero()) {
2774 return left();
2775 }
2776 return NULL;
2777}
2778
2779
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00002780bool HStoreKeyed::NeedsCanonicalization() {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002781 // If value is an integer or smi or comes from the result of a keyed load or
2782 // constant then it is either be a non-hole value or in the case of a constant
2783 // the hole is only being stored explicitly: no need for canonicalization.
2784 if (value()->IsLoadKeyed() || value()->IsConstant()) {
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002785 return false;
2786 }
danno@chromium.org94b0d6f2013-02-04 13:33:20 +00002787
2788 if (value()->IsChange()) {
2789 if (HChange::cast(value())->from().IsInteger32()) {
2790 return false;
2791 }
2792 if (HChange::cast(value())->value()->type().IsSmi()) {
2793 return false;
2794 }
2795 }
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00002796 return true;
2797}
2798
2799
erikcorry0ad885c2011-11-21 13:51:57 +00002800#define H_CONSTANT_INT32(val) \
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002801new(zone) HConstant(static_cast<int32_t>(val), Representation::Integer32())
erikcorry0ad885c2011-11-21 13:51:57 +00002802#define H_CONSTANT_DOUBLE(val) \
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002803new(zone) HConstant(static_cast<double>(val), Representation::Double())
erikcorry0ad885c2011-11-21 13:51:57 +00002804
2805#define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002806HInstruction* HInstr::New( \
2807 Zone* zone, HValue* context, HValue* left, HValue* right) { \
2808 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \
erikcorry0ad885c2011-11-21 13:51:57 +00002809 HConstant* c_left = HConstant::cast(left); \
2810 HConstant* c_right = HConstant::cast(right); \
2811 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
2812 double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \
2813 if (TypeInfo::IsInt32Double(double_res)) { \
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002814 return H_CONSTANT_INT32(double_res); \
erikcorry0ad885c2011-11-21 13:51:57 +00002815 } \
2816 return H_CONSTANT_DOUBLE(double_res); \
2817 } \
2818 } \
2819 return new(zone) HInstr(context, left, right); \
2820}
2821
2822
2823DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HAdd, +)
2824DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HMul, *)
2825DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -)
2826
2827#undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR
2828
2829
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002830HInstruction* HStringAdd::New(
2831 Zone* zone, HValue* context, HValue* left, HValue* right) {
2832 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
2833 HConstant* c_right = HConstant::cast(right);
2834 HConstant* c_left = HConstant::cast(left);
2835 if (c_left->HasStringValue() && c_right->HasStringValue()) {
2836 return new(zone) HConstant(FACTORY->NewConsString(c_left->StringValue(),
2837 c_right->StringValue()),
2838 Representation::Tagged());
2839 }
2840 }
2841 return new(zone) HStringAdd(context, left, right);
2842}
2843
2844
2845HInstruction* HStringCharFromCode::New(
2846 Zone* zone, HValue* context, HValue* char_code) {
2847 if (FLAG_fold_constants && char_code->IsConstant()) {
2848 HConstant* c_code = HConstant::cast(char_code);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002849 Isolate* isolate = Isolate::Current();
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002850 if (c_code->HasNumberValue()) {
2851 if (isfinite(c_code->DoubleValue())) {
2852 uint32_t code = c_code->NumberValueAsInteger32() & 0xffff;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002853 return new(zone) HConstant(LookupSingleCharacterStringFromCode(isolate,
2854 code),
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002855 Representation::Tagged());
2856 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002857 return new(zone) HConstant(isolate->factory()->empty_string(),
ulan@chromium.org2e04b582013-02-21 14:06:02 +00002858 Representation::Tagged());
2859 }
2860 }
2861 return new(zone) HStringCharFromCode(context, char_code);
2862}
2863
2864
2865HInstruction* HStringLength::New(Zone* zone, HValue* string) {
2866 if (FLAG_fold_constants && string->IsConstant()) {
2867 HConstant* c_string = HConstant::cast(string);
2868 if (c_string->HasStringValue()) {
2869 return H_CONSTANT_INT32(c_string->StringValue()->length());
2870 }
2871 }
2872 return new(zone) HStringLength(string);
2873}
2874
2875
2876HInstruction* HUnaryMathOperation::New(
2877 Zone* zone, HValue* context, HValue* value, BuiltinFunctionId op) {
2878 do {
2879 if (!FLAG_fold_constants) break;
2880 if (!value->IsConstant()) break;
2881 HConstant* constant = HConstant::cast(value);
2882 if (!constant->HasNumberValue()) break;
2883 double d = constant->DoubleValue();
2884 if (isnan(d)) { // NaN poisons everything.
2885 return H_CONSTANT_DOUBLE(OS::nan_value());
2886 }
2887 if (isinf(d)) { // +Infinity and -Infinity.
2888 switch (op) {
2889 case kMathSin:
2890 case kMathCos:
2891 case kMathTan:
2892 return H_CONSTANT_DOUBLE(OS::nan_value());
2893 case kMathExp:
2894 return H_CONSTANT_DOUBLE((d > 0.0) ? d : 0.0);
2895 case kMathLog:
2896 case kMathSqrt:
2897 return H_CONSTANT_DOUBLE((d > 0.0) ? d : OS::nan_value());
2898 case kMathPowHalf:
2899 case kMathAbs:
2900 return H_CONSTANT_DOUBLE((d > 0.0) ? d : -d);
2901 case kMathRound:
2902 case kMathFloor:
2903 return H_CONSTANT_DOUBLE(d);
2904 default:
2905 UNREACHABLE();
2906 break;
2907 }
2908 }
2909 switch (op) {
2910 case kMathSin:
2911 return H_CONSTANT_DOUBLE(fast_sin(d));
2912 case kMathCos:
2913 return H_CONSTANT_DOUBLE(fast_cos(d));
2914 case kMathTan:
2915 return H_CONSTANT_DOUBLE(fast_tan(d));
2916 case kMathExp:
2917 return H_CONSTANT_DOUBLE(fast_exp(d));
2918 case kMathLog:
2919 return H_CONSTANT_DOUBLE(fast_log(d));
2920 case kMathSqrt:
2921 return H_CONSTANT_DOUBLE(fast_sqrt(d));
2922 case kMathPowHalf:
2923 return H_CONSTANT_DOUBLE(power_double_double(d, 0.5));
2924 case kMathAbs:
2925 return H_CONSTANT_DOUBLE((d >= 0.0) ? d + 0.0 : -d);
2926 case kMathRound:
2927 // -0.5 .. -0.0 round to -0.0.
2928 if ((d >= -0.5 && Double(d).Sign() < 0)) return H_CONSTANT_DOUBLE(-0.0);
2929 // Doubles are represented as Significant * 2 ^ Exponent. If the
2930 // Exponent is not negative, the double value is already an integer.
2931 if (Double(d).Exponent() >= 0) return H_CONSTANT_DOUBLE(d);
2932 return H_CONSTANT_DOUBLE(floor(d + 0.5));
2933 case kMathFloor:
2934 return H_CONSTANT_DOUBLE(floor(d));
2935 default:
2936 UNREACHABLE();
2937 break;
2938 }
2939 } while (false);
2940 return new(zone) HUnaryMathOperation(context, value, op);
2941}
2942
2943
2944HInstruction* HPower::New(Zone* zone, HValue* left, HValue* right) {
2945 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
2946 HConstant* c_left = HConstant::cast(left);
2947 HConstant* c_right = HConstant::cast(right);
2948 if (c_left->HasNumberValue() && c_right->HasNumberValue()) {
2949 double result = power_helper(c_left->DoubleValue(),
2950 c_right->DoubleValue());
2951 return H_CONSTANT_DOUBLE(isnan(result) ? OS::nan_value() : result);
2952 }
2953 }
2954 return new(zone) HPower(left, right);
2955}
2956
2957
2958HInstruction* HMathMinMax::New(
2959 Zone* zone, HValue* context, HValue* left, HValue* right, Operation op) {
2960 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
2961 HConstant* c_left = HConstant::cast(left);
2962 HConstant* c_right = HConstant::cast(right);
2963 if (c_left->HasNumberValue() && c_right->HasNumberValue()) {
2964 double d_left = c_left->DoubleValue();
2965 double d_right = c_right->DoubleValue();
2966 if (op == kMathMin) {
2967 if (d_left > d_right) return H_CONSTANT_DOUBLE(d_right);
2968 if (d_left < d_right) return H_CONSTANT_DOUBLE(d_left);
2969 if (d_left == d_right) {
2970 // Handle +0 and -0.
2971 return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_left
2972 : d_right);
2973 }
2974 } else {
2975 if (d_left < d_right) return H_CONSTANT_DOUBLE(d_right);
2976 if (d_left > d_right) return H_CONSTANT_DOUBLE(d_left);
2977 if (d_left == d_right) {
2978 // Handle +0 and -0.
2979 return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_right
2980 : d_left);
2981 }
2982 }
2983 // All comparisons failed, must be NaN.
2984 return H_CONSTANT_DOUBLE(OS::nan_value());
2985 }
2986 }
2987 return new(zone) HMathMinMax(context, left, right, op);
2988}
2989
2990
2991HInstruction* HMod::New(
2992 Zone* zone, HValue* context, HValue* left, HValue* right) {
2993 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
erikcorry0ad885c2011-11-21 13:51:57 +00002994 HConstant* c_left = HConstant::cast(left);
2995 HConstant* c_right = HConstant::cast(right);
2996 if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) {
2997 int32_t dividend = c_left->Integer32Value();
2998 int32_t divisor = c_right->Integer32Value();
2999 if (divisor != 0) {
3000 int32_t res = dividend % divisor;
3001 if ((res == 0) && (dividend < 0)) {
3002 return H_CONSTANT_DOUBLE(-0.0);
3003 }
3004 return H_CONSTANT_INT32(res);
3005 }
3006 }
3007 }
3008 return new(zone) HMod(context, left, right);
3009}
3010
3011
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003012HInstruction* HDiv::New(
3013 Zone* zone, HValue* context, HValue* left, HValue* right) {
erikcorry0ad885c2011-11-21 13:51:57 +00003014 // If left and right are constant values, try to return a constant value.
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003015 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003016 HConstant* c_left = HConstant::cast(left);
3017 HConstant* c_right = HConstant::cast(right);
3018 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
3019 if (c_right->DoubleValue() != 0) {
3020 double double_res = c_left->DoubleValue() / c_right->DoubleValue();
3021 if (TypeInfo::IsInt32Double(double_res)) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003022 return H_CONSTANT_INT32(double_res);
erikcorry0ad885c2011-11-21 13:51:57 +00003023 }
3024 return H_CONSTANT_DOUBLE(double_res);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003025 } else {
3026 int sign = Double(c_left->DoubleValue()).Sign() *
3027 Double(c_right->DoubleValue()).Sign(); // Right could be -0.
3028 return H_CONSTANT_DOUBLE(sign * V8_INFINITY);
erikcorry0ad885c2011-11-21 13:51:57 +00003029 }
3030 }
3031 }
3032 return new(zone) HDiv(context, left, right);
3033}
3034
3035
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003036HInstruction* HBitwise::New(
3037 Zone* zone, Token::Value op, HValue* context, HValue* left, HValue* right) {
3038 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003039 HConstant* c_left = HConstant::cast(left);
3040 HConstant* c_right = HConstant::cast(right);
3041 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
3042 int32_t result;
3043 int32_t v_left = c_left->NumberValueAsInteger32();
3044 int32_t v_right = c_right->NumberValueAsInteger32();
3045 switch (op) {
3046 case Token::BIT_XOR:
3047 result = v_left ^ v_right;
3048 break;
3049 case Token::BIT_AND:
3050 result = v_left & v_right;
3051 break;
3052 case Token::BIT_OR:
3053 result = v_left | v_right;
3054 break;
3055 default:
3056 result = 0; // Please the compiler.
3057 UNREACHABLE();
3058 }
3059 return H_CONSTANT_INT32(result);
3060 }
3061 }
3062 return new(zone) HBitwise(op, context, left, right);
3063}
3064
3065
3066#define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003067HInstruction* HInstr::New( \
3068 Zone* zone, HValue* context, HValue* left, HValue* right) { \
3069 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \
erikcorry0ad885c2011-11-21 13:51:57 +00003070 HConstant* c_left = HConstant::cast(left); \
3071 HConstant* c_right = HConstant::cast(right); \
3072 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \
3073 return H_CONSTANT_INT32(result); \
3074 } \
3075 } \
3076 return new(zone) HInstr(context, left, right); \
3077}
3078
3079
3080DEFINE_NEW_H_BITWISE_INSTR(HSar,
3081c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f))
3082DEFINE_NEW_H_BITWISE_INSTR(HShl,
3083c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f))
3084
3085#undef DEFINE_NEW_H_BITWISE_INSTR
3086
3087
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003088HInstruction* HShr::New(
3089 Zone* zone, HValue* context, HValue* left, HValue* right) {
3090 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) {
erikcorry0ad885c2011-11-21 13:51:57 +00003091 HConstant* c_left = HConstant::cast(left);
3092 HConstant* c_right = HConstant::cast(right);
3093 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) {
3094 int32_t left_val = c_left->NumberValueAsInteger32();
3095 int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f;
3096 if ((right_val == 0) && (left_val < 0)) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +00003097 return H_CONSTANT_DOUBLE(static_cast<uint32_t>(left_val));
erikcorry0ad885c2011-11-21 13:51:57 +00003098 }
3099 return H_CONSTANT_INT32(static_cast<uint32_t>(left_val) >> right_val);
3100 }
3101 }
3102 return new(zone) HShr(context, left, right);
3103}
3104
3105
3106#undef H_CONSTANT_INT32
3107#undef H_CONSTANT_DOUBLE
3108
3109
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003110void HIn::PrintDataTo(StringStream* stream) {
3111 key()->PrintNameTo(stream);
3112 stream->Add(" ");
3113 object()->PrintNameTo(stream);
3114}
3115
3116
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00003117void HBitwise::PrintDataTo(StringStream* stream) {
3118 stream->Add(Token::Name(op_));
3119 stream->Add(" ");
3120 HBitwiseBinaryOperation::PrintDataTo(stream);
3121}
3122
3123
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003124void HPhi::InferRepresentation(HInferRepresentation* h_infer) {
3125 ASSERT(CheckFlag(kFlexibleRepresentation));
3126 // If there are non-Phi uses, and all of them have observed the same
3127 // representation, than that's what this Phi is going to use.
3128 Representation new_rep = RepresentationObservedByAllNonPhiUses();
3129 if (!new_rep.IsNone()) {
3130 UpdateRepresentation(new_rep, h_infer, "unanimous use observations");
3131 return;
3132 }
3133 new_rep = RepresentationFromInputs();
3134 UpdateRepresentation(new_rep, h_infer, "inputs");
3135 new_rep = RepresentationFromUses();
3136 UpdateRepresentation(new_rep, h_infer, "uses");
3137 new_rep = RepresentationFromUseRequirements();
3138 UpdateRepresentation(new_rep, h_infer, "use requirements");
3139}
3140
3141
3142Representation HPhi::RepresentationObservedByAllNonPhiUses() {
3143 int non_phi_use_count = 0;
3144 for (int i = Representation::kInteger32;
3145 i < Representation::kNumRepresentations; ++i) {
3146 non_phi_use_count += non_phi_uses_[i];
3147 }
3148 if (non_phi_use_count <= 1) return Representation::None();
3149 for (int i = 0; i < Representation::kNumRepresentations; ++i) {
3150 if (non_phi_uses_[i] == non_phi_use_count) {
3151 return Representation::FromKind(static_cast<Representation::Kind>(i));
3152 }
3153 }
3154 return Representation::None();
3155}
3156
3157
3158Representation HPhi::RepresentationFromInputs() {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003159 bool double_occurred = false;
3160 bool int32_occurred = false;
3161 for (int i = 0; i < OperandCount(); ++i) {
3162 HValue* value = OperandAt(i);
3163 if (value->IsUnknownOSRValue()) {
3164 HPhi* hint_value = HUnknownOSRValue::cast(value)->incoming_value();
3165 if (hint_value != NULL) {
3166 Representation hint = hint_value->representation();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003167 if (hint.IsTagged()) return hint;
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003168 if (hint.IsDouble()) double_occurred = true;
3169 if (hint.IsInteger32()) int32_occurred = true;
3170 }
3171 continue;
3172 }
3173 if (value->representation().IsDouble()) double_occurred = true;
3174 if (value->representation().IsInteger32()) int32_occurred = true;
3175 if (value->representation().IsTagged()) {
3176 if (value->IsConstant()) {
3177 HConstant* constant = HConstant::cast(value);
3178 if (constant->IsConvertibleToInteger()) {
3179 int32_occurred = true;
3180 } else if (constant->HasNumberValue()) {
3181 double_occurred = true;
3182 } else {
3183 return Representation::Tagged();
3184 }
3185 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003186 if (value->IsPhi() && !IsConvertibleToInteger()) {
3187 return Representation::Tagged();
3188 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00003189 }
3190 }
3191 }
3192
3193 if (double_occurred) return Representation::Double();
3194
3195 if (int32_occurred) return Representation::Integer32();
3196
3197 return Representation::None();
3198}
3199
3200
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003201Representation HPhi::RepresentationFromUseRequirements() {
3202 Representation all_uses_require = Representation::None();
3203 bool all_uses_require_the_same = true;
3204 for (HUseIterator it(uses()); !it.Done(); it.Advance()) {
3205 // We check for observed_input_representation elsewhere.
3206 Representation use_rep =
3207 it.value()->RequiredInputRepresentation(it.index());
3208 // No useful info from this use -> look at the next one.
3209 if (use_rep.IsNone()) {
3210 continue;
3211 }
3212 if (use_rep.Equals(all_uses_require)) {
3213 continue;
3214 }
3215 // This use's representation contradicts what we've seen so far.
3216 if (!all_uses_require.IsNone()) {
3217 ASSERT(!use_rep.Equals(all_uses_require));
3218 all_uses_require_the_same = false;
3219 break;
3220 }
3221 // Otherwise, initialize observed representation.
3222 all_uses_require = use_rep;
3223 }
3224 if (all_uses_require_the_same) {
3225 return all_uses_require;
3226 }
3227
3228 return Representation::None();
3229}
3230
3231
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003232// Node-specific verification code is only included in debug mode.
3233#ifdef DEBUG
3234
ager@chromium.org378b34e2011-01-28 08:04:38 +00003235void HPhi::Verify() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003236 ASSERT(OperandCount() == block()->predecessors()->length());
3237 for (int i = 0; i < OperandCount(); ++i) {
3238 HValue* value = OperandAt(i);
3239 HBasicBlock* defining_block = value->block();
3240 HBasicBlock* predecessor_block = block()->predecessors()->at(i);
3241 ASSERT(defining_block == predecessor_block ||
3242 defining_block->Dominates(predecessor_block));
3243 }
3244}
3245
3246
ager@chromium.org378b34e2011-01-28 08:04:38 +00003247void HSimulate::Verify() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003248 HInstruction::Verify();
3249 ASSERT(HasAstId());
3250}
3251
3252
ager@chromium.org378b34e2011-01-28 08:04:38 +00003253void HCheckSmi::Verify() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003254 HInstruction::Verify();
3255 ASSERT(HasNoUses());
3256}
3257
3258
ager@chromium.org378b34e2011-01-28 08:04:38 +00003259void HCheckNonSmi::Verify() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003260 HInstruction::Verify();
3261 ASSERT(HasNoUses());
3262}
3263
3264
ager@chromium.org378b34e2011-01-28 08:04:38 +00003265void HCheckFunction::Verify() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003266 HInstruction::Verify();
3267 ASSERT(HasNoUses());
3268}
3269
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003270#endif
3271
3272} } // namespace v8::internal