1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/crankshaft/s390/lithium-s390.h"
6
7 #include <sstream>
8
9 #include "src/crankshaft/hydrogen-osr.h"
10 #include "src/crankshaft/lithium-inl.h"
11 #include "src/crankshaft/s390/lithium-codegen-s390.h"
12
13 namespace v8 {
14 namespace internal {
15
16 #define DEFINE_COMPILE(type) \
17 void L##type::CompileToNative(LCodeGen* generator) { \
18 generator->Do##type(this); \
19 }
LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)20 LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
21 #undef DEFINE_COMPILE
22
23 #ifdef DEBUG
24 void LInstruction::VerifyCall() {
25 // Call instructions can use only fixed registers as temporaries and
26 // outputs because all registers are blocked by the calling convention.
27 // Inputs operands must use a fixed register or use-at-start policy or
28 // a non-register policy.
29 DCHECK(Output() == NULL || LUnallocated::cast(Output())->HasFixedPolicy() ||
30 !LUnallocated::cast(Output())->HasRegisterPolicy());
31 for (UseIterator it(this); !it.Done(); it.Advance()) {
32 LUnallocated* operand = LUnallocated::cast(it.Current());
33 DCHECK(operand->HasFixedPolicy() || operand->IsUsedAtStart());
34 }
35 for (TempIterator it(this); !it.Done(); it.Advance()) {
36 LUnallocated* operand = LUnallocated::cast(it.Current());
37 DCHECK(operand->HasFixedPolicy() || !operand->HasRegisterPolicy());
38 }
39 }
40 #endif
41
PrintTo(StringStream * stream)42 void LInstruction::PrintTo(StringStream* stream) {
43 stream->Add("%s ", this->Mnemonic());
44
45 PrintOutputOperandTo(stream);
46
47 PrintDataTo(stream);
48
49 if (HasEnvironment()) {
50 stream->Add(" ");
51 environment()->PrintTo(stream);
52 }
53
54 if (HasPointerMap()) {
55 stream->Add(" ");
56 pointer_map()->PrintTo(stream);
57 }
58 }
59
PrintDataTo(StringStream * stream)60 void LInstruction::PrintDataTo(StringStream* stream) {
61 stream->Add("= ");
62 for (int i = 0; i < InputCount(); i++) {
63 if (i > 0) stream->Add(" ");
64 if (InputAt(i) == NULL) {
65 stream->Add("NULL");
66 } else {
67 InputAt(i)->PrintTo(stream);
68 }
69 }
70 }
71
PrintOutputOperandTo(StringStream * stream)72 void LInstruction::PrintOutputOperandTo(StringStream* stream) {
73 if (HasResult()) result()->PrintTo(stream);
74 }
75
PrintDataTo(StringStream * stream)76 void LLabel::PrintDataTo(StringStream* stream) {
77 LGap::PrintDataTo(stream);
78 LLabel* rep = replacement();
79 if (rep != NULL) {
80 stream->Add(" Dead block replaced with B%d", rep->block_id());
81 }
82 }
83
IsRedundant() const84 bool LGap::IsRedundant() const {
85 for (int i = 0; i < 4; i++) {
86 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
87 return false;
88 }
89 }
90
91 return true;
92 }
93
PrintDataTo(StringStream * stream)94 void LGap::PrintDataTo(StringStream* stream) {
95 for (int i = 0; i < 4; i++) {
96 stream->Add("(");
97 if (parallel_moves_[i] != NULL) {
98 parallel_moves_[i]->PrintDataTo(stream);
99 }
100 stream->Add(") ");
101 }
102 }
103
Mnemonic() const104 const char* LArithmeticD::Mnemonic() const {
105 switch (op()) {
106 case Token::ADD:
107 return "add-d";
108 case Token::SUB:
109 return "sub-d";
110 case Token::MUL:
111 return "mul-d";
112 case Token::DIV:
113 return "div-d";
114 case Token::MOD:
115 return "mod-d";
116 default:
117 UNREACHABLE();
118 return NULL;
119 }
120 }
121
Mnemonic() const122 const char* LArithmeticT::Mnemonic() const {
123 switch (op()) {
124 case Token::ADD:
125 return "add-t";
126 case Token::SUB:
127 return "sub-t";
128 case Token::MUL:
129 return "mul-t";
130 case Token::MOD:
131 return "mod-t";
132 case Token::DIV:
133 return "div-t";
134 case Token::BIT_AND:
135 return "bit-and-t";
136 case Token::BIT_OR:
137 return "bit-or-t";
138 case Token::BIT_XOR:
139 return "bit-xor-t";
140 case Token::ROR:
141 return "ror-t";
142 case Token::SHL:
143 return "shl-t";
144 case Token::SAR:
145 return "sar-t";
146 case Token::SHR:
147 return "shr-t";
148 default:
149 UNREACHABLE();
150 return NULL;
151 }
152 }
153
HasInterestingComment(LCodeGen * gen) const154 bool LGoto::HasInterestingComment(LCodeGen* gen) const {
155 return !gen->IsNextEmittedBlock(block_id());
156 }
157
PrintDataTo(StringStream * stream)158 void LGoto::PrintDataTo(StringStream* stream) {
159 stream->Add("B%d", block_id());
160 }
161
PrintDataTo(StringStream * stream)162 void LBranch::PrintDataTo(StringStream* stream) {
163 stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
164 value()->PrintTo(stream);
165 }
166
PrintDataTo(StringStream * stream)167 void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
168 stream->Add("if ");
169 left()->PrintTo(stream);
170 stream->Add(" %s ", Token::String(op()));
171 right()->PrintTo(stream);
172 stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
173 }
174
PrintDataTo(StringStream * stream)175 void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
176 stream->Add("if is_string(");
177 value()->PrintTo(stream);
178 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
179 }
180
PrintDataTo(StringStream * stream)181 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
182 stream->Add("if is_smi(");
183 value()->PrintTo(stream);
184 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
185 }
186
PrintDataTo(StringStream * stream)187 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
188 stream->Add("if is_undetectable(");
189 value()->PrintTo(stream);
190 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
191 }
192
PrintDataTo(StringStream * stream)193 void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
194 stream->Add("if string_compare(");
195 left()->PrintTo(stream);
196 right()->PrintTo(stream);
197 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
198 }
199
PrintDataTo(StringStream * stream)200 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
201 stream->Add("if has_instance_type(");
202 value()->PrintTo(stream);
203 stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
204 }
205
PrintDataTo(StringStream * stream)206 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
207 stream->Add("if class_of_test(");
208 value()->PrintTo(stream);
209 stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
210 true_block_id(), false_block_id());
211 }
212
PrintDataTo(StringStream * stream)213 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
214 stream->Add("if typeof ");
215 value()->PrintTo(stream);
216 stream->Add(" == \"%s\" then B%d else B%d",
217 hydrogen()->type_literal()->ToCString().get(), true_block_id(),
218 false_block_id());
219 }
220
PrintDataTo(StringStream * stream)221 void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
222 stream->Add(" = ");
223 function()->PrintTo(stream);
224 stream->Add(".code_entry = ");
225 code_object()->PrintTo(stream);
226 }
227
PrintDataTo(StringStream * stream)228 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
229 stream->Add(" = ");
230 base_object()->PrintTo(stream);
231 stream->Add(" + ");
232 offset()->PrintTo(stream);
233 }
234
PrintDataTo(StringStream * stream)235 void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
236 for (int i = 0; i < InputCount(); i++) {
237 InputAt(i)->PrintTo(stream);
238 stream->Add(" ");
239 }
240 stream->Add("#%d / ", arity());
241 }
242
PrintDataTo(StringStream * stream)243 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
244 context()->PrintTo(stream);
245 stream->Add("[%d]", slot_index());
246 }
247
PrintDataTo(StringStream * stream)248 void LStoreContextSlot::PrintDataTo(StringStream* stream) {
249 context()->PrintTo(stream);
250 stream->Add("[%d] <- ", slot_index());
251 value()->PrintTo(stream);
252 }
253
PrintDataTo(StringStream * stream)254 void LInvokeFunction::PrintDataTo(StringStream* stream) {
255 stream->Add("= ");
256 function()->PrintTo(stream);
257 stream->Add(" #%d / ", arity());
258 }
259
PrintDataTo(StringStream * stream)260 void LCallNewArray::PrintDataTo(StringStream* stream) {
261 stream->Add("= ");
262 constructor()->PrintTo(stream);
263 stream->Add(" #%d / ", arity());
264 ElementsKind kind = hydrogen()->elements_kind();
265 stream->Add(" (%s) ", ElementsKindToString(kind));
266 }
267
PrintDataTo(StringStream * stream)268 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
269 arguments()->PrintTo(stream);
270 stream->Add(" length ");
271 length()->PrintTo(stream);
272 stream->Add(" index ");
273 index()->PrintTo(stream);
274 }
275
PrintDataTo(StringStream * stream)276 void LStoreNamedField::PrintDataTo(StringStream* stream) {
277 object()->PrintTo(stream);
278 std::ostringstream os;
279 os << hydrogen()->access() << " <- ";
280 stream->Add(os.str().c_str());
281 value()->PrintTo(stream);
282 }
283
PrintDataTo(StringStream * stream)284 void LLoadKeyed::PrintDataTo(StringStream* stream) {
285 elements()->PrintTo(stream);
286 stream->Add("[");
287 key()->PrintTo(stream);
288 if (hydrogen()->IsDehoisted()) {
289 stream->Add(" + %d]", base_offset());
290 } else {
291 stream->Add("]");
292 }
293 }
294
PrintDataTo(StringStream * stream)295 void LStoreKeyed::PrintDataTo(StringStream* stream) {
296 elements()->PrintTo(stream);
297 stream->Add("[");
298 key()->PrintTo(stream);
299 if (hydrogen()->IsDehoisted()) {
300 stream->Add(" + %d] <-", base_offset());
301 } else {
302 stream->Add("] <- ");
303 }
304
305 if (value() == NULL) {
306 DCHECK(hydrogen()->IsConstantHoleStore() &&
307 hydrogen()->value()->representation().IsDouble());
308 stream->Add("<the hole(nan)>");
309 } else {
310 value()->PrintTo(stream);
311 }
312 }
313
PrintDataTo(StringStream * stream)314 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
315 object()->PrintTo(stream);
316 stream->Add(" %p -> %p", *original_map(), *transitioned_map());
317 }
318
GetNextSpillIndex(RegisterKind kind)319 int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
320 // Skip a slot if for a double-width slot.
321 if (kind == DOUBLE_REGISTERS) current_frame_slots_++;
322 return current_frame_slots_++;
323 }
324
GetNextSpillSlot(RegisterKind kind)325 LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
326 int index = GetNextSpillIndex(kind);
327 if (kind == DOUBLE_REGISTERS) {
328 return LDoubleStackSlot::Create(index, zone());
329 } else {
330 DCHECK(kind == GENERAL_REGISTERS);
331 return LStackSlot::Create(index, zone());
332 }
333 }
334
Build()335 LPlatformChunk* LChunkBuilder::Build() {
336 DCHECK(is_unused());
337 chunk_ = new (zone()) LPlatformChunk(info(), graph());
338 LPhase phase("L_Building chunk", chunk_);
339 status_ = BUILDING;
340
341 // If compiling for OSR, reserve space for the unoptimized frame,
342 // which will be subsumed into this frame.
343 if (graph()->has_osr()) {
344 for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
345 chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
346 }
347 }
348
349 const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
350 for (int i = 0; i < blocks->length(); i++) {
351 HBasicBlock* next = NULL;
352 if (i < blocks->length() - 1) next = blocks->at(i + 1);
353 DoBasicBlock(blocks->at(i), next);
354 if (is_aborted()) return NULL;
355 }
356 status_ = DONE;
357 return chunk_;
358 }
359
ToUnallocated(Register reg)360 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
361 return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
362 }
363
ToUnallocated(DoubleRegister reg)364 LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
365 return new (zone())
366 LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
367 }
368
UseFixed(HValue * value,Register fixed_register)369 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
370 return Use(value, ToUnallocated(fixed_register));
371 }
372
UseFixedDouble(HValue * value,DoubleRegister reg)373 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) {
374 return Use(value, ToUnallocated(reg));
375 }
376
UseRegister(HValue * value)377 LOperand* LChunkBuilder::UseRegister(HValue* value) {
378 return Use(value,
379 new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
380 }
381
UseRegisterAtStart(HValue * value)382 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
383 return Use(value, new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
384 LUnallocated::USED_AT_START));
385 }
386
UseTempRegister(HValue * value)387 LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
388 return Use(value, new (zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
389 }
390
Use(HValue * value)391 LOperand* LChunkBuilder::Use(HValue* value) {
392 return Use(value, new (zone()) LUnallocated(LUnallocated::NONE));
393 }
394
UseAtStart(HValue * value)395 LOperand* LChunkBuilder::UseAtStart(HValue* value) {
396 return Use(value, new (zone()) LUnallocated(LUnallocated::NONE,
397 LUnallocated::USED_AT_START));
398 }
399
UseOrConstant(HValue * value)400 LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
401 return value->IsConstant()
402 ? chunk_->DefineConstantOperand(HConstant::cast(value))
403 : Use(value);
404 }
405
UseOrConstantAtStart(HValue * value)406 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
407 return value->IsConstant()
408 ? chunk_->DefineConstantOperand(HConstant::cast(value))
409 : UseAtStart(value);
410 }
411
UseRegisterOrConstant(HValue * value)412 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
413 return value->IsConstant()
414 ? chunk_->DefineConstantOperand(HConstant::cast(value))
415 : UseRegister(value);
416 }
417
UseRegisterOrConstantAtStart(HValue * value)418 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
419 return value->IsConstant()
420 ? chunk_->DefineConstantOperand(HConstant::cast(value))
421 : UseRegisterAtStart(value);
422 }
423
UseConstant(HValue * value)424 LOperand* LChunkBuilder::UseConstant(HValue* value) {
425 return chunk_->DefineConstantOperand(HConstant::cast(value));
426 }
427
UseAny(HValue * value)428 LOperand* LChunkBuilder::UseAny(HValue* value) {
429 return value->IsConstant()
430 ? chunk_->DefineConstantOperand(HConstant::cast(value))
431 : Use(value, new (zone()) LUnallocated(LUnallocated::ANY));
432 }
433
Use(HValue * value,LUnallocated * operand)434 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
435 if (value->EmitAtUses()) {
436 HInstruction* instr = HInstruction::cast(value);
437 VisitInstruction(instr);
438 }
439 operand->set_virtual_register(value->id());
440 return operand;
441 }
442
Define(LTemplateResultInstruction<1> * instr,LUnallocated * result)443 LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
444 LUnallocated* result) {
445 result->set_virtual_register(current_instruction_->id());
446 instr->set_result(result);
447 return instr;
448 }
449
DefineAsRegister(LTemplateResultInstruction<1> * instr)450 LInstruction* LChunkBuilder::DefineAsRegister(
451 LTemplateResultInstruction<1>* instr) {
452 return Define(instr,
453 new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
454 }
455
DefineAsSpilled(LTemplateResultInstruction<1> * instr,int index)456 LInstruction* LChunkBuilder::DefineAsSpilled(
457 LTemplateResultInstruction<1>* instr, int index) {
458 return Define(instr,
459 new (zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
460 }
461
DefineSameAsFirst(LTemplateResultInstruction<1> * instr)462 LInstruction* LChunkBuilder::DefineSameAsFirst(
463 LTemplateResultInstruction<1>* instr) {
464 return Define(instr,
465 new (zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
466 }
467
DefineFixed(LTemplateResultInstruction<1> * instr,Register reg)468 LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
469 Register reg) {
470 return Define(instr, ToUnallocated(reg));
471 }
472
DefineFixedDouble(LTemplateResultInstruction<1> * instr,DoubleRegister reg)473 LInstruction* LChunkBuilder::DefineFixedDouble(
474 LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
475 return Define(instr, ToUnallocated(reg));
476 }
477
AssignEnvironment(LInstruction * instr)478 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
479 HEnvironment* hydrogen_env = current_block_->last_environment();
480 return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
481 }
482
MarkAsCall(LInstruction * instr,HInstruction * hinstr,CanDeoptimize can_deoptimize)483 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
484 HInstruction* hinstr,
485 CanDeoptimize can_deoptimize) {
486 info()->MarkAsNonDeferredCalling();
487 #ifdef DEBUG
488 instr->VerifyCall();
489 #endif
490 instr->MarkAsCall();
491 instr = AssignPointerMap(instr);
492
493 // If instruction does not have side-effects lazy deoptimization
494 // after the call will try to deoptimize to the point before the call.
495 // Thus we still need to attach environment to this call even if
496 // call sequence can not deoptimize eagerly.
497 bool needs_environment = (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
498 !hinstr->HasObservableSideEffects();
499 if (needs_environment && !instr->HasEnvironment()) {
500 instr = AssignEnvironment(instr);
501 // We can't really figure out if the environment is needed or not.
502 instr->environment()->set_has_been_used();
503 }
504
505 return instr;
506 }
507
AssignPointerMap(LInstruction * instr)508 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
509 DCHECK(!instr->HasPointerMap());
510 instr->set_pointer_map(new (zone()) LPointerMap(zone()));
511 return instr;
512 }
513
TempRegister()514 LUnallocated* LChunkBuilder::TempRegister() {
515 LUnallocated* operand =
516 new (zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
517 int vreg = allocator_->GetVirtualRegister();
518 if (!allocator_->AllocationOk()) {
519 Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
520 vreg = 0;
521 }
522 operand->set_virtual_register(vreg);
523 return operand;
524 }
525
TempDoubleRegister()526 LUnallocated* LChunkBuilder::TempDoubleRegister() {
527 LUnallocated* operand =
528 new (zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
529 int vreg = allocator_->GetVirtualRegister();
530 if (!allocator_->AllocationOk()) {
531 Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
532 vreg = 0;
533 }
534 operand->set_virtual_register(vreg);
535 return operand;
536 }
537
FixedTemp(Register reg)538 LOperand* LChunkBuilder::FixedTemp(Register reg) {
539 LUnallocated* operand = ToUnallocated(reg);
540 DCHECK(operand->HasFixedPolicy());
541 return operand;
542 }
543
FixedTemp(DoubleRegister reg)544 LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
545 LUnallocated* operand = ToUnallocated(reg);
546 DCHECK(operand->HasFixedPolicy());
547 return operand;
548 }
549
DoBlockEntry(HBlockEntry * instr)550 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
551 return new (zone()) LLabel(instr->block());
552 }
553
DoDummyUse(HDummyUse * instr)554 LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
555 return DefineAsRegister(new (zone()) LDummyUse(UseAny(instr->value())));
556 }
557
DoEnvironmentMarker(HEnvironmentMarker * instr)558 LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
559 UNREACHABLE();
560 return NULL;
561 }
562
DoDeoptimize(HDeoptimize * instr)563 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
564 return AssignEnvironment(new (zone()) LDeoptimize);
565 }
566
DoShift(Token::Value op,HBitwiseBinaryOperation * instr)567 LInstruction* LChunkBuilder::DoShift(Token::Value op,
568 HBitwiseBinaryOperation* instr) {
569 if (instr->representation().IsSmiOrInteger32()) {
570 DCHECK(instr->left()->representation().Equals(instr->representation()));
571 DCHECK(instr->right()->representation().Equals(instr->representation()));
572 LOperand* left = UseRegisterAtStart(instr->left());
573
574 HValue* right_value = instr->right();
575 LOperand* right = NULL;
576 int constant_value = 0;
577 bool does_deopt = false;
578 if (right_value->IsConstant()) {
579 HConstant* constant = HConstant::cast(right_value);
580 right = chunk_->DefineConstantOperand(constant);
581 constant_value = constant->Integer32Value() & 0x1f;
582 // Left shifts can deoptimize if we shift by > 0 and the result cannot be
583 // truncated to smi.
584 if (instr->representation().IsSmi() && constant_value > 0) {
585 does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
586 }
587 } else {
588 right = UseRegisterAtStart(right_value);
589 }
590
591 // Shift operations can only deoptimize if we do a logical shift
592 // by 0 and the result cannot be truncated to int32.
593 if (op == Token::SHR && constant_value == 0) {
594 does_deopt = !instr->CheckFlag(HInstruction::kUint32);
595 }
596
597 LInstruction* result =
598 DefineAsRegister(new (zone()) LShiftI(op, left, right, does_deopt));
599 return does_deopt ? AssignEnvironment(result) : result;
600 } else {
601 return DoArithmeticT(op, instr);
602 }
603 }
604
DoArithmeticD(Token::Value op,HArithmeticBinaryOperation * instr)605 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
606 HArithmeticBinaryOperation* instr) {
607 DCHECK(instr->representation().IsDouble());
608 DCHECK(instr->left()->representation().IsDouble());
609 DCHECK(instr->right()->representation().IsDouble());
610 if (op == Token::MOD) {
611 LOperand* left = UseFixedDouble(instr->left(), d1);
612 LOperand* right = UseFixedDouble(instr->right(), d2);
613 LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
614 // We call a C function for double modulo. It can't trigger a GC. We need
615 // to use fixed result register for the call.
616 // TODO(fschneider): Allow any register as input registers.
617 return MarkAsCall(DefineFixedDouble(result, d1), instr);
618 } else {
619 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
620 LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
621 LArithmeticD* result = new (zone()) LArithmeticD(op, left, right);
622 return DefineSameAsFirst(result);
623 }
624 }
625
DoArithmeticT(Token::Value op,HBinaryOperation * instr)626 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
627 HBinaryOperation* instr) {
628 HValue* left = instr->left();
629 HValue* right = instr->right();
630 DCHECK(left->representation().IsTagged());
631 DCHECK(right->representation().IsTagged());
632 LOperand* context = UseFixed(instr->context(), cp);
633 LOperand* left_operand = UseFixed(left, r3);
634 LOperand* right_operand = UseFixed(right, r2);
635 LArithmeticT* result =
636 new (zone()) LArithmeticT(op, context, left_operand, right_operand);
637 return MarkAsCall(DefineFixed(result, r2), instr);
638 }
639
DoBasicBlock(HBasicBlock * block,HBasicBlock * next_block)640 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
641 DCHECK(is_building());
642 current_block_ = block;
643 next_block_ = next_block;
644 if (block->IsStartBlock()) {
645 block->UpdateEnvironment(graph_->start_environment());
646 argument_count_ = 0;
647 } else if (block->predecessors()->length() == 1) {
648 // We have a single predecessor => copy environment and outgoing
649 // argument count from the predecessor.
650 DCHECK(block->phis()->length() == 0);
651 HBasicBlock* pred = block->predecessors()->at(0);
652 HEnvironment* last_environment = pred->last_environment();
653 DCHECK(last_environment != NULL);
654 // Only copy the environment, if it is later used again.
655 if (pred->end()->SecondSuccessor() == NULL) {
656 DCHECK(pred->end()->FirstSuccessor() == block);
657 } else {
658 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
659 pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
660 last_environment = last_environment->Copy();
661 }
662 }
663 block->UpdateEnvironment(last_environment);
664 DCHECK(pred->argument_count() >= 0);
665 argument_count_ = pred->argument_count();
666 } else {
667 // We are at a state join => process phis.
668 HBasicBlock* pred = block->predecessors()->at(0);
669 // No need to copy the environment, it cannot be used later.
670 HEnvironment* last_environment = pred->last_environment();
671 for (int i = 0; i < block->phis()->length(); ++i) {
672 HPhi* phi = block->phis()->at(i);
673 if (phi->HasMergedIndex()) {
674 last_environment->SetValueAt(phi->merged_index(), phi);
675 }
676 }
677 for (int i = 0; i < block->deleted_phis()->length(); ++i) {
678 if (block->deleted_phis()->at(i) < last_environment->length()) {
679 last_environment->SetValueAt(block->deleted_phis()->at(i),
680 graph_->GetConstantUndefined());
681 }
682 }
683 block->UpdateEnvironment(last_environment);
684 // Pick up the outgoing argument count of one of the predecessors.
685 argument_count_ = pred->argument_count();
686 }
687 HInstruction* current = block->first();
688 int start = chunk_->instructions()->length();
689 while (current != NULL && !is_aborted()) {
690 // Code for constants in registers is generated lazily.
691 if (!current->EmitAtUses()) {
692 VisitInstruction(current);
693 }
694 current = current->next();
695 }
696 int end = chunk_->instructions()->length() - 1;
697 if (end >= start) {
698 block->set_first_instruction_index(start);
699 block->set_last_instruction_index(end);
700 }
701 block->set_argument_count(argument_count_);
702 next_block_ = NULL;
703 current_block_ = NULL;
704 }
705
VisitInstruction(HInstruction * current)706 void LChunkBuilder::VisitInstruction(HInstruction* current) {
707 HInstruction* old_current = current_instruction_;
708 current_instruction_ = current;
709
710 LInstruction* instr = NULL;
711 if (current->CanReplaceWithDummyUses()) {
712 if (current->OperandCount() == 0) {
713 instr = DefineAsRegister(new (zone()) LDummy());
714 } else {
715 DCHECK(!current->OperandAt(0)->IsControlInstruction());
716 instr = DefineAsRegister(new (zone())
717 LDummyUse(UseAny(current->OperandAt(0))));
718 }
719 for (int i = 1; i < current->OperandCount(); ++i) {
720 if (current->OperandAt(i)->IsControlInstruction()) continue;
721 LInstruction* dummy =
722 new (zone()) LDummyUse(UseAny(current->OperandAt(i)));
723 dummy->set_hydrogen_value(current);
724 chunk_->AddInstruction(dummy, current_block_);
725 }
726 } else {
727 HBasicBlock* successor;
728 if (current->IsControlInstruction() &&
729 HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
730 successor != NULL) {
731 instr = new (zone()) LGoto(successor);
732 } else {
733 instr = current->CompileToLithium(this);
734 }
735 }
736
737 argument_count_ += current->argument_delta();
738 DCHECK(argument_count_ >= 0);
739
740 if (instr != NULL) {
741 AddInstruction(instr, current);
742 }
743
744 current_instruction_ = old_current;
745 }
746
AddInstruction(LInstruction * instr,HInstruction * hydrogen_val)747 void LChunkBuilder::AddInstruction(LInstruction* instr,
748 HInstruction* hydrogen_val) {
749 // Associate the hydrogen instruction first, since we may need it for
750 // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
751 instr->set_hydrogen_value(hydrogen_val);
752
753 #if DEBUG
754 // Make sure that the lithium instruction has either no fixed register
755 // constraints in temps or the result OR no uses that are only used at
756 // start. If this invariant doesn't hold, the register allocator can decide
757 // to insert a split of a range immediately before the instruction due to an
758 // already allocated register needing to be used for the instruction's fixed
759 // register constraint. In this case, The register allocator won't see an
760 // interference between the split child and the use-at-start (it would if
761 // the it was just a plain use), so it is free to move the split child into
762 // the same register that is used for the use-at-start.
763 // See https://code.google.com/p/chromium/issues/detail?id=201590
764 if (!(instr->ClobbersRegisters() &&
765 instr->ClobbersDoubleRegisters(isolate()))) {
766 int fixed = 0;
767 int used_at_start = 0;
768 for (UseIterator it(instr); !it.Done(); it.Advance()) {
769 LUnallocated* operand = LUnallocated::cast(it.Current());
770 if (operand->IsUsedAtStart()) ++used_at_start;
771 }
772 if (instr->Output() != NULL) {
773 if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
774 }
775 for (TempIterator it(instr); !it.Done(); it.Advance()) {
776 LUnallocated* operand = LUnallocated::cast(it.Current());
777 if (operand->HasFixedPolicy()) ++fixed;
778 }
779 DCHECK(fixed == 0 || used_at_start == 0);
780 }
781 #endif
782
783 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
784 instr = AssignPointerMap(instr);
785 }
786 if (FLAG_stress_environments && !instr->HasEnvironment()) {
787 instr = AssignEnvironment(instr);
788 }
789 chunk_->AddInstruction(instr, current_block_);
790
791 CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
792 }
793
DoPrologue(HPrologue * instr)794 LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
795 LInstruction* result = new (zone()) LPrologue();
796 if (info_->scope()->NeedsContext()) {
797 result = MarkAsCall(result, instr);
798 }
799 return result;
800 }
801
DoGoto(HGoto * instr)802 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
803 return new (zone()) LGoto(instr->FirstSuccessor());
804 }
805
DoBranch(HBranch * instr)806 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
807 HValue* value = instr->value();
808 Representation r = value->representation();
809 HType type = value->type();
810 ToBooleanHints expected = instr->expected_input_types();
811 if (expected == ToBooleanHint::kNone) expected = ToBooleanHint::kAny;
812
813 bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
814 type.IsJSArray() || type.IsHeapNumber() || type.IsString();
815 LInstruction* branch = new (zone()) LBranch(UseRegister(value));
816 if (!easy_case && ((!(expected & ToBooleanHint::kSmallInteger) &&
817 (expected & ToBooleanHint::kNeedsMap)) ||
818 expected != ToBooleanHint::kAny)) {
819 branch = AssignEnvironment(branch);
820 }
821 return branch;
822 }
823
DoDebugBreak(HDebugBreak * instr)824 LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
825 return new (zone()) LDebugBreak();
826 }
827
DoCompareMap(HCompareMap * instr)828 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
829 DCHECK(instr->value()->representation().IsTagged());
830 LOperand* value = UseRegister(instr->value());
831 LOperand* temp = TempRegister();
832 return new (zone()) LCmpMapAndBranch(value, temp);
833 }
834
DoArgumentsLength(HArgumentsLength * instr)835 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
836 info()->MarkAsRequiresFrame();
837 LOperand* value = UseRegister(instr->value());
838 return DefineAsRegister(new (zone()) LArgumentsLength(value));
839 }
840
DoArgumentsElements(HArgumentsElements * elems)841 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
842 info()->MarkAsRequiresFrame();
843 return DefineAsRegister(new (zone()) LArgumentsElements);
844 }
845
DoHasInPrototypeChainAndBranch(HHasInPrototypeChainAndBranch * instr)846 LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
847 HHasInPrototypeChainAndBranch* instr) {
848 LOperand* object = UseRegister(instr->object());
849 LOperand* prototype = UseRegister(instr->prototype());
850 LHasInPrototypeChainAndBranch* result =
851 new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
852 return AssignEnvironment(result);
853 }
854
DoWrapReceiver(HWrapReceiver * instr)855 LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
856 LOperand* receiver = UseRegisterAtStart(instr->receiver());
857 LOperand* function = UseRegisterAtStart(instr->function());
858 LWrapReceiver* result = new (zone()) LWrapReceiver(receiver, function);
859 return AssignEnvironment(DefineAsRegister(result));
860 }
861
DoApplyArguments(HApplyArguments * instr)862 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
863 LOperand* function = UseFixed(instr->function(), r3);
864 LOperand* receiver = UseFixed(instr->receiver(), r2);
865 LOperand* length = UseFixed(instr->length(), r4);
866 LOperand* elements = UseFixed(instr->elements(), r5);
867 LApplyArguments* result =
868 new (zone()) LApplyArguments(function, receiver, length, elements);
869 return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
870 }
871
DoPushArguments(HPushArguments * instr)872 LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
873 int argc = instr->OperandCount();
874 for (int i = 0; i < argc; ++i) {
875 LOperand* argument = Use(instr->argument(i));
876 AddInstruction(new (zone()) LPushArgument(argument), instr);
877 }
878 return NULL;
879 }
880
DoStoreCodeEntry(HStoreCodeEntry * store_code_entry)881 LInstruction* LChunkBuilder::DoStoreCodeEntry(
882 HStoreCodeEntry* store_code_entry) {
883 LOperand* function = UseRegister(store_code_entry->function());
884 LOperand* code_object = UseTempRegister(store_code_entry->code_object());
885 return new (zone()) LStoreCodeEntry(function, code_object);
886 }
887
DoInnerAllocatedObject(HInnerAllocatedObject * instr)888 LInstruction* LChunkBuilder::DoInnerAllocatedObject(
889 HInnerAllocatedObject* instr) {
890 LOperand* base_object = UseRegisterAtStart(instr->base_object());
891 LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
892 return DefineAsRegister(new (zone())
893 LInnerAllocatedObject(base_object, offset));
894 }
895
DoThisFunction(HThisFunction * instr)896 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
897 return instr->HasNoUses() ? NULL
898 : DefineAsRegister(new (zone()) LThisFunction);
899 }
900
DoContext(HContext * instr)901 LInstruction* LChunkBuilder::DoContext(HContext* instr) {
902 if (instr->HasNoUses()) return NULL;
903
904 if (info()->IsStub()) {
905 return DefineFixed(new (zone()) LContext, cp);
906 }
907
908 return DefineAsRegister(new (zone()) LContext);
909 }
910
DoDeclareGlobals(HDeclareGlobals * instr)911 LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
912 LOperand* context = UseFixed(instr->context(), cp);
913 return MarkAsCall(new (zone()) LDeclareGlobals(context), instr);
914 }
915
DoCallWithDescriptor(HCallWithDescriptor * instr)916 LInstruction* LChunkBuilder::DoCallWithDescriptor(HCallWithDescriptor* instr) {
917 CallInterfaceDescriptor descriptor = instr->descriptor();
918 DCHECK_EQ(descriptor.GetParameterCount() +
919 LCallWithDescriptor::kImplicitRegisterParameterCount,
920 instr->OperandCount());
921
922 LOperand* target = UseRegisterOrConstantAtStart(instr->target());
923 ZoneList<LOperand*> ops(instr->OperandCount(), zone());
924 // Target
925 ops.Add(target, zone());
926 // Context
927 LOperand* op = UseFixed(instr->OperandAt(1), cp);
928 ops.Add(op, zone());
929 // Load register parameters.
930 int i = 0;
931 for (; i < descriptor.GetRegisterParameterCount(); i++) {
932 op = UseFixed(instr->OperandAt(
933 i + LCallWithDescriptor::kImplicitRegisterParameterCount),
934 descriptor.GetRegisterParameter(i));
935 ops.Add(op, zone());
936 }
937 // Push stack parameters.
938 for (; i < descriptor.GetParameterCount(); i++) {
939 op = UseAny(instr->OperandAt(
940 i + LCallWithDescriptor::kImplicitRegisterParameterCount));
941 AddInstruction(new (zone()) LPushArgument(op), instr);
942 }
943
944 LCallWithDescriptor* result =
945 new (zone()) LCallWithDescriptor(descriptor, ops, zone());
946 if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
947 result->MarkAsSyntacticTailCall();
948 }
949 return MarkAsCall(DefineFixed(result, r2), instr);
950 }
951
DoInvokeFunction(HInvokeFunction * instr)952 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
953 LOperand* context = UseFixed(instr->context(), cp);
954 LOperand* function = UseFixed(instr->function(), r3);
955 LInvokeFunction* result = new (zone()) LInvokeFunction(context, function);
956 if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
957 result->MarkAsSyntacticTailCall();
958 }
959 return MarkAsCall(DefineFixed(result, r2), instr, CANNOT_DEOPTIMIZE_EAGERLY);
960 }
961
DoUnaryMathOperation(HUnaryMathOperation * instr)962 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
963 switch (instr->op()) {
964 case kMathFloor:
965 return DoMathFloor(instr);
966 case kMathRound:
967 return DoMathRound(instr);
968 case kMathFround:
969 return DoMathFround(instr);
970 case kMathAbs:
971 return DoMathAbs(instr);
972 case kMathLog:
973 return DoMathLog(instr);
974 case kMathCos:
975 return DoMathCos(instr);
976 case kMathSin:
977 return DoMathSin(instr);
978 case kMathExp:
979 return DoMathExp(instr);
980 case kMathSqrt:
981 return DoMathSqrt(instr);
982 case kMathPowHalf:
983 return DoMathPowHalf(instr);
984 case kMathClz32:
985 return DoMathClz32(instr);
986 default:
987 UNREACHABLE();
988 return NULL;
989 }
990 }
991
DoMathFloor(HUnaryMathOperation * instr)992 LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
993 LOperand* input = UseRegister(instr->value());
994 LMathFloor* result = new (zone()) LMathFloor(input);
995 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
996 }
997
DoMathRound(HUnaryMathOperation * instr)998 LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
999 LOperand* input = UseRegister(instr->value());
1000 LOperand* temp = TempDoubleRegister();
1001 LMathRound* result = new (zone()) LMathRound(input, temp);
1002 return AssignEnvironment(DefineAsRegister(result));
1003 }
1004
DoMathFround(HUnaryMathOperation * instr)1005 LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1006 LOperand* input = UseRegister(instr->value());
1007 LMathFround* result = new (zone()) LMathFround(input);
1008 return DefineAsRegister(result);
1009 }
1010
DoMathAbs(HUnaryMathOperation * instr)1011 LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1012 Representation r = instr->value()->representation();
1013 LOperand* context = (r.IsDouble() || r.IsSmiOrInteger32())
1014 ? NULL
1015 : UseFixed(instr->context(), cp);
1016 LOperand* input = UseRegister(instr->value());
1017 LInstruction* result =
1018 DefineAsRegister(new (zone()) LMathAbs(context, input));
1019 if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1020 if (!r.IsDouble()) result = AssignEnvironment(result);
1021 return result;
1022 }
1023
DoMathLog(HUnaryMathOperation * instr)1024 LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1025 DCHECK(instr->representation().IsDouble());
1026 DCHECK(instr->value()->representation().IsDouble());
1027 LOperand* input = UseFixedDouble(instr->value(), d0);
1028 return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), d0), instr);
1029 }
1030
DoMathClz32(HUnaryMathOperation * instr)1031 LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
1032 LOperand* input = UseRegisterAtStart(instr->value());
1033 LMathClz32* result = new (zone()) LMathClz32(input);
1034 return DefineAsRegister(result);
1035 }
1036
DoMathCos(HUnaryMathOperation * instr)1037 LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1038 DCHECK(instr->representation().IsDouble());
1039 DCHECK(instr->value()->representation().IsDouble());
1040 LOperand* input = UseFixedDouble(instr->value(), d0);
1041 return MarkAsCall(DefineFixedDouble(new (zone()) LMathCos(input), d0), instr);
1042 }
1043
DoMathSin(HUnaryMathOperation * instr)1044 LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1045 DCHECK(instr->representation().IsDouble());
1046 DCHECK(instr->value()->representation().IsDouble());
1047 LOperand* input = UseFixedDouble(instr->value(), d0);
1048 return MarkAsCall(DefineFixedDouble(new (zone()) LMathSin(input), d0), instr);
1049 }
1050
DoMathExp(HUnaryMathOperation * instr)1051 LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1052 DCHECK(instr->representation().IsDouble());
1053 DCHECK(instr->value()->representation().IsDouble());
1054 LOperand* input = UseFixedDouble(instr->value(), d0);
1055 return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
1056 }
1057
DoMathSqrt(HUnaryMathOperation * instr)1058 LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1059 LOperand* input = UseRegisterAtStart(instr->value());
1060 LMathSqrt* result = new (zone()) LMathSqrt(input);
1061 return DefineAsRegister(result);
1062 }
1063
DoMathPowHalf(HUnaryMathOperation * instr)1064 LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1065 LOperand* input = UseRegisterAtStart(instr->value());
1066 LMathPowHalf* result = new (zone()) LMathPowHalf(input);
1067 return DefineAsRegister(result);
1068 }
1069
DoCallNewArray(HCallNewArray * instr)1070 LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1071 LOperand* context = UseFixed(instr->context(), cp);
1072 LOperand* constructor = UseFixed(instr->constructor(), r3);
1073 LCallNewArray* result = new (zone()) LCallNewArray(context, constructor);
1074 return MarkAsCall(DefineFixed(result, r2), instr);
1075 }
1076
DoCallRuntime(HCallRuntime * instr)1077 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1078 LOperand* context = UseFixed(instr->context(), cp);
1079 return MarkAsCall(DefineFixed(new (zone()) LCallRuntime(context), r2), instr);
1080 }
1081
DoRor(HRor * instr)1082 LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1083 return DoShift(Token::ROR, instr);
1084 }
1085
DoShr(HShr * instr)1086 LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1087 return DoShift(Token::SHR, instr);
1088 }
1089
DoSar(HSar * instr)1090 LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1091 return DoShift(Token::SAR, instr);
1092 }
1093
DoShl(HShl * instr)1094 LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1095 return DoShift(Token::SHL, instr);
1096 }
1097
DoBitwise(HBitwise * instr)1098 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1099 if (instr->representation().IsSmiOrInteger32()) {
1100 DCHECK(instr->left()->representation().Equals(instr->representation()));
1101 DCHECK(instr->right()->representation().Equals(instr->representation()));
1102 DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1103
1104 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1105 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1106 return DefineAsRegister(new (zone()) LBitI(left, right));
1107 } else {
1108 return DoArithmeticT(instr->op(), instr);
1109 }
1110 }
1111
DoDivByPowerOf2I(HDiv * instr)1112 LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1113 DCHECK(instr->representation().IsSmiOrInteger32());
1114 DCHECK(instr->left()->representation().Equals(instr->representation()));
1115 DCHECK(instr->right()->representation().Equals(instr->representation()));
1116 LOperand* dividend = UseRegister(instr->left());
1117 int32_t divisor = instr->right()->GetInteger32Constant();
1118 LInstruction* result =
1119 DefineAsRegister(new (zone()) LDivByPowerOf2I(dividend, divisor));
1120 if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1121 (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1122 (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1123 divisor != 1 && divisor != -1)) {
1124 result = AssignEnvironment(result);
1125 }
1126 return result;
1127 }
1128
DoDivByConstI(HDiv * instr)1129 LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1130 DCHECK(instr->representation().IsInteger32());
1131 DCHECK(instr->left()->representation().Equals(instr->representation()));
1132 DCHECK(instr->right()->representation().Equals(instr->representation()));
1133 LOperand* dividend = UseRegister(instr->left());
1134 int32_t divisor = instr->right()->GetInteger32Constant();
1135 LInstruction* result =
1136 DefineAsRegister(new (zone()) LDivByConstI(dividend, divisor));
1137 if (divisor == 0 ||
1138 (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1139 !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1140 result = AssignEnvironment(result);
1141 }
1142 return result;
1143 }
1144
DoDivI(HDiv * instr)1145 LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1146 DCHECK(instr->representation().IsSmiOrInteger32());
1147 DCHECK(instr->left()->representation().Equals(instr->representation()));
1148 DCHECK(instr->right()->representation().Equals(instr->representation()));
1149 LOperand* dividend = UseRegister(instr->left());
1150 LOperand* divisor = UseRegister(instr->right());
1151 LInstruction* result =
1152 DefineAsRegister(new (zone()) LDivI(dividend, divisor));
1153 if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1154 instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1155 (instr->CheckFlag(HValue::kCanOverflow) &&
1156 !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) ||
1157 (!instr->IsMathFloorOfDiv() &&
1158 !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1159 result = AssignEnvironment(result);
1160 }
1161 return result;
1162 }
1163
DoDiv(HDiv * instr)1164 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1165 if (instr->representation().IsSmiOrInteger32()) {
1166 if (instr->RightIsPowerOf2()) {
1167 return DoDivByPowerOf2I(instr);
1168 } else if (instr->right()->IsConstant()) {
1169 return DoDivByConstI(instr);
1170 } else {
1171 return DoDivI(instr);
1172 }
1173 } else if (instr->representation().IsDouble()) {
1174 return DoArithmeticD(Token::DIV, instr);
1175 } else {
1176 return DoArithmeticT(Token::DIV, instr);
1177 }
1178 }
1179
DoFlooringDivByPowerOf2I(HMathFloorOfDiv * instr)1180 LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1181 LOperand* dividend = UseRegisterAtStart(instr->left());
1182 int32_t divisor = instr->right()->GetInteger32Constant();
1183 LInstruction* result =
1184 DefineAsRegister(new (zone()) LFlooringDivByPowerOf2I(dividend, divisor));
1185 if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1186 (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1187 result = AssignEnvironment(result);
1188 }
1189 return result;
1190 }
1191
DoFlooringDivByConstI(HMathFloorOfDiv * instr)1192 LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1193 DCHECK(instr->representation().IsInteger32());
1194 DCHECK(instr->left()->representation().Equals(instr->representation()));
1195 DCHECK(instr->right()->representation().Equals(instr->representation()));
1196 LOperand* dividend = UseRegister(instr->left());
1197 int32_t divisor = instr->right()->GetInteger32Constant();
1198 LOperand* temp =
1199 ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1200 (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive)))
1201 ? NULL
1202 : TempRegister();
1203 LInstruction* result = DefineAsRegister(
1204 new (zone()) LFlooringDivByConstI(dividend, divisor, temp));
1205 if (divisor == 0 ||
1206 (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1207 result = AssignEnvironment(result);
1208 }
1209 return result;
1210 }
1211
DoFlooringDivI(HMathFloorOfDiv * instr)1212 LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1213 DCHECK(instr->representation().IsSmiOrInteger32());
1214 DCHECK(instr->left()->representation().Equals(instr->representation()));
1215 DCHECK(instr->right()->representation().Equals(instr->representation()));
1216 LOperand* dividend = UseRegister(instr->left());
1217 LOperand* divisor = UseRegister(instr->right());
1218 LInstruction* result =
1219 DefineAsRegister(new (zone()) LFlooringDivI(dividend, divisor));
1220 if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1221 instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1222 (instr->CheckFlag(HValue::kCanOverflow) &&
1223 !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32))) {
1224 result = AssignEnvironment(result);
1225 }
1226 return result;
1227 }
1228
DoMathFloorOfDiv(HMathFloorOfDiv * instr)1229 LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1230 if (instr->RightIsPowerOf2()) {
1231 return DoFlooringDivByPowerOf2I(instr);
1232 } else if (instr->right()->IsConstant()) {
1233 return DoFlooringDivByConstI(instr);
1234 } else {
1235 return DoFlooringDivI(instr);
1236 }
1237 }
1238
DoModByPowerOf2I(HMod * instr)1239 LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1240 DCHECK(instr->representation().IsSmiOrInteger32());
1241 DCHECK(instr->left()->representation().Equals(instr->representation()));
1242 DCHECK(instr->right()->representation().Equals(instr->representation()));
1243 LOperand* dividend = UseRegisterAtStart(instr->left());
1244 int32_t divisor = instr->right()->GetInteger32Constant();
1245 LInstruction* result =
1246 DefineSameAsFirst(new (zone()) LModByPowerOf2I(dividend, divisor));
1247 if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1248 instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1249 result = AssignEnvironment(result);
1250 }
1251 return result;
1252 }
1253
DoModByConstI(HMod * instr)1254 LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1255 DCHECK(instr->representation().IsSmiOrInteger32());
1256 DCHECK(instr->left()->representation().Equals(instr->representation()));
1257 DCHECK(instr->right()->representation().Equals(instr->representation()));
1258 LOperand* dividend = UseRegister(instr->left());
1259 int32_t divisor = instr->right()->GetInteger32Constant();
1260 LInstruction* result =
1261 DefineAsRegister(new (zone()) LModByConstI(dividend, divisor));
1262 if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1263 result = AssignEnvironment(result);
1264 }
1265 return result;
1266 }
1267
DoModI(HMod * instr)1268 LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1269 DCHECK(instr->representation().IsSmiOrInteger32());
1270 DCHECK(instr->left()->representation().Equals(instr->representation()));
1271 DCHECK(instr->right()->representation().Equals(instr->representation()));
1272 LOperand* dividend = UseRegister(instr->left());
1273 LOperand* divisor = UseRegister(instr->right());
1274 LInstruction* result =
1275 DefineAsRegister(new (zone()) LModI(dividend, divisor));
1276 if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1277 instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1278 result = AssignEnvironment(result);
1279 }
1280 return result;
1281 }
1282
DoMod(HMod * instr)1283 LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1284 if (instr->representation().IsSmiOrInteger32()) {
1285 if (instr->RightIsPowerOf2()) {
1286 return DoModByPowerOf2I(instr);
1287 } else if (instr->right()->IsConstant()) {
1288 return DoModByConstI(instr);
1289 } else {
1290 return DoModI(instr);
1291 }
1292 } else if (instr->representation().IsDouble()) {
1293 return DoArithmeticD(Token::MOD, instr);
1294 } else {
1295 return DoArithmeticT(Token::MOD, instr);
1296 }
1297 }
1298
DoMul(HMul * instr)1299 LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1300 if (instr->representation().IsSmiOrInteger32()) {
1301 DCHECK(instr->left()->representation().Equals(instr->representation()));
1302 DCHECK(instr->right()->representation().Equals(instr->representation()));
1303 HValue* left = instr->BetterLeftOperand();
1304 HValue* right = instr->BetterRightOperand();
1305 LOperand* left_op;
1306 LOperand* right_op;
1307 bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1308 bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
1309
1310 int32_t constant_value = 0;
1311 if (right->IsConstant()) {
1312 HConstant* constant = HConstant::cast(right);
1313 constant_value = constant->Integer32Value();
1314 // Constants -1, 0 and 1 can be optimized if the result can overflow.
1315 // For other constants, it can be optimized only without overflow.
1316 if (!can_overflow || ((constant_value >= -1) && (constant_value <= 1))) {
1317 left_op = UseRegisterAtStart(left);
1318 right_op = UseConstant(right);
1319 } else {
1320 if (bailout_on_minus_zero) {
1321 left_op = UseRegister(left);
1322 } else {
1323 left_op = UseRegisterAtStart(left);
1324 }
1325 right_op = UseRegister(right);
1326 }
1327 } else {
1328 if (bailout_on_minus_zero) {
1329 left_op = UseRegister(left);
1330 } else {
1331 left_op = UseRegisterAtStart(left);
1332 }
1333 right_op = UseRegister(right);
1334 }
1335 LMulI* mul = new (zone()) LMulI(left_op, right_op);
1336 if (right_op->IsConstantOperand()
1337 ? ((can_overflow && constant_value == -1) ||
1338 (bailout_on_minus_zero && constant_value <= 0))
1339 : (can_overflow || bailout_on_minus_zero)) {
1340 AssignEnvironment(mul);
1341 }
1342 return DefineAsRegister(mul);
1343
1344 } else if (instr->representation().IsDouble()) {
1345 return DoArithmeticD(Token::MUL, instr);
1346 } else {
1347 return DoArithmeticT(Token::MUL, instr);
1348 }
1349 }
1350
DoSub(HSub * instr)1351 LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1352 if (instr->representation().IsSmiOrInteger32()) {
1353 DCHECK(instr->left()->representation().Equals(instr->representation()));
1354 DCHECK(instr->right()->representation().Equals(instr->representation()));
1355
1356 if (instr->left()->IsConstant() &&
1357 !instr->CheckFlag(HValue::kCanOverflow)) {
1358 // If lhs is constant, do reverse subtraction instead.
1359 return DoRSub(instr);
1360 }
1361
1362 LOperand* left = UseRegisterAtStart(instr->left());
1363 LOperand* right = UseOrConstantAtStart(instr->right());
1364 LSubI* sub = new (zone()) LSubI(left, right);
1365 LInstruction* result = DefineAsRegister(sub);
1366 if (instr->CheckFlag(HValue::kCanOverflow)) {
1367 result = AssignEnvironment(result);
1368 }
1369 return result;
1370 } else if (instr->representation().IsDouble()) {
1371 return DoArithmeticD(Token::SUB, instr);
1372 } else {
1373 return DoArithmeticT(Token::SUB, instr);
1374 }
1375 }
1376
DoRSub(HSub * instr)1377 LInstruction* LChunkBuilder::DoRSub(HSub* instr) {
1378 DCHECK(instr->representation().IsSmiOrInteger32());
1379 DCHECK(instr->left()->representation().Equals(instr->representation()));
1380 DCHECK(instr->right()->representation().Equals(instr->representation()));
1381 DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1382
1383 // Note: The lhs of the subtraction becomes the rhs of the
1384 // reverse-subtraction.
1385 LOperand* left = UseRegisterAtStart(instr->right());
1386 LOperand* right = UseOrConstantAtStart(instr->left());
1387 LRSubI* rsb = new (zone()) LRSubI(left, right);
1388 LInstruction* result = DefineAsRegister(rsb);
1389 return result;
1390 }
1391
DoMultiplyAdd(HMul * mul,HValue * addend)1392 LInstruction* LChunkBuilder::DoMultiplyAdd(HMul* mul, HValue* addend) {
1393 LOperand* multiplier_op = UseRegister(mul->left());
1394 LOperand* multiplicand_op = UseRegister(mul->right());
1395 LOperand* addend_op = UseRegister(addend);
1396 return DefineAsRegister(
1397 new (zone()) LMultiplyAddD(addend_op, multiplier_op, multiplicand_op));
1398 }
1399
DoMultiplySub(HValue * minuend,HMul * mul)1400 LInstruction* LChunkBuilder::DoMultiplySub(HValue* minuend, HMul* mul) {
1401 LOperand* minuend_op = UseRegister(minuend);
1402 LOperand* multiplier_op = UseRegister(mul->left());
1403 LOperand* multiplicand_op = UseRegister(mul->right());
1404
1405 return DefineAsRegister(
1406 new (zone()) LMultiplySubD(minuend_op, multiplier_op, multiplicand_op));
1407 }
1408
DoAdd(HAdd * instr)1409 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1410 if (instr->representation().IsSmiOrInteger32()) {
1411 DCHECK(instr->left()->representation().Equals(instr->representation()));
1412 DCHECK(instr->right()->representation().Equals(instr->representation()));
1413 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1414 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand());
1415 LAddI* add = new (zone()) LAddI(left, right);
1416 LInstruction* result = DefineAsRegister(add);
1417 if (instr->CheckFlag(HValue::kCanOverflow)) {
1418 result = AssignEnvironment(result);
1419 }
1420 return result;
1421 } else if (instr->representation().IsExternal()) {
1422 DCHECK(instr->IsConsistentExternalRepresentation());
1423 DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1424 LOperand* left = UseRegisterAtStart(instr->left());
1425 LOperand* right = UseOrConstantAtStart(instr->right());
1426 LAddI* add = new (zone()) LAddI(left, right);
1427 LInstruction* result = DefineAsRegister(add);
1428 return result;
1429 } else if (instr->representation().IsDouble()) {
1430 return DoArithmeticD(Token::ADD, instr);
1431 } else {
1432 return DoArithmeticT(Token::ADD, instr);
1433 }
1434 }
1435
DoMathMinMax(HMathMinMax * instr)1436 LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1437 LOperand* left = NULL;
1438 LOperand* right = NULL;
1439 if (instr->representation().IsSmiOrInteger32()) {
1440 DCHECK(instr->left()->representation().Equals(instr->representation()));
1441 DCHECK(instr->right()->representation().Equals(instr->representation()));
1442 left = UseRegisterAtStart(instr->BetterLeftOperand());
1443 right = UseOrConstantAtStart(instr->BetterRightOperand());
1444 } else {
1445 DCHECK(instr->representation().IsDouble());
1446 DCHECK(instr->left()->representation().IsDouble());
1447 DCHECK(instr->right()->representation().IsDouble());
1448 left = UseRegister(instr->left());
1449 right = UseRegister(instr->right());
1450 }
1451 return DefineAsRegister(new (zone()) LMathMinMax(left, right));
1452 }
1453
DoPower(HPower * instr)1454 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1455 DCHECK(instr->representation().IsDouble());
1456 // We call a C function for double power. It can't trigger a GC.
1457 // We need to use fixed result register for the call.
1458 Representation exponent_type = instr->right()->representation();
1459 DCHECK(instr->left()->representation().IsDouble());
1460 LOperand* left = UseFixedDouble(instr->left(), d1);
1461 LOperand* right = exponent_type.IsDouble()
1462 ? UseFixedDouble(instr->right(), d2)
1463 : UseFixed(instr->right(), r4);
1464 LPower* result = new (zone()) LPower(left, right);
1465 return MarkAsCall(DefineFixedDouble(result, d3), instr,
1466 CAN_DEOPTIMIZE_EAGERLY);
1467 }
1468
DoCompareGeneric(HCompareGeneric * instr)1469 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1470 DCHECK(instr->left()->representation().IsTagged());
1471 DCHECK(instr->right()->representation().IsTagged());
1472 LOperand* context = UseFixed(instr->context(), cp);
1473 LOperand* left = UseFixed(instr->left(), r3);
1474 LOperand* right = UseFixed(instr->right(), r2);
1475 LCmpT* result = new (zone()) LCmpT(context, left, right);
1476 return MarkAsCall(DefineFixed(result, r2), instr);
1477 }
1478
DoCompareNumericAndBranch(HCompareNumericAndBranch * instr)1479 LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1480 HCompareNumericAndBranch* instr) {
1481 Representation r = instr->representation();
1482 if (r.IsSmiOrInteger32()) {
1483 DCHECK(instr->left()->representation().Equals(r));
1484 DCHECK(instr->right()->representation().Equals(r));
1485 LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1486 LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1487 return new (zone()) LCompareNumericAndBranch(left, right);
1488 } else {
1489 DCHECK(r.IsDouble());
1490 DCHECK(instr->left()->representation().IsDouble());
1491 DCHECK(instr->right()->representation().IsDouble());
1492 LOperand* left = UseRegisterAtStart(instr->left());
1493 LOperand* right = UseRegisterAtStart(instr->right());
1494 return new (zone()) LCompareNumericAndBranch(left, right);
1495 }
1496 }
1497
DoCompareObjectEqAndBranch(HCompareObjectEqAndBranch * instr)1498 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1499 HCompareObjectEqAndBranch* instr) {
1500 LOperand* left = UseRegisterAtStart(instr->left());
1501 LOperand* right = UseRegisterAtStart(instr->right());
1502 return new (zone()) LCmpObjectEqAndBranch(left, right);
1503 }
1504
DoCompareHoleAndBranch(HCompareHoleAndBranch * instr)1505 LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1506 HCompareHoleAndBranch* instr) {
1507 LOperand* value = UseRegisterAtStart(instr->value());
1508 return new (zone()) LCmpHoleAndBranch(value);
1509 }
1510
DoIsStringAndBranch(HIsStringAndBranch * instr)1511 LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1512 DCHECK(instr->value()->representation().IsTagged());
1513 LOperand* value = UseRegisterAtStart(instr->value());
1514 LOperand* temp = TempRegister();
1515 return new (zone()) LIsStringAndBranch(value, temp);
1516 }
1517
DoIsSmiAndBranch(HIsSmiAndBranch * instr)1518 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1519 DCHECK(instr->value()->representation().IsTagged());
1520 return new (zone()) LIsSmiAndBranch(Use(instr->value()));
1521 }
1522
DoIsUndetectableAndBranch(HIsUndetectableAndBranch * instr)1523 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1524 HIsUndetectableAndBranch* instr) {
1525 DCHECK(instr->value()->representation().IsTagged());
1526 LOperand* value = UseRegisterAtStart(instr->value());
1527 return new (zone()) LIsUndetectableAndBranch(value, TempRegister());
1528 }
1529
DoStringCompareAndBranch(HStringCompareAndBranch * instr)1530 LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1531 HStringCompareAndBranch* instr) {
1532 DCHECK(instr->left()->representation().IsTagged());
1533 DCHECK(instr->right()->representation().IsTagged());
1534 LOperand* context = UseFixed(instr->context(), cp);
1535 LOperand* left = UseFixed(instr->left(), r3);
1536 LOperand* right = UseFixed(instr->right(), r2);
1537 LStringCompareAndBranch* result =
1538 new (zone()) LStringCompareAndBranch(context, left, right);
1539 return MarkAsCall(result, instr);
1540 }
1541
DoHasInstanceTypeAndBranch(HHasInstanceTypeAndBranch * instr)1542 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1543 HHasInstanceTypeAndBranch* instr) {
1544 DCHECK(instr->value()->representation().IsTagged());
1545 LOperand* value = UseRegisterAtStart(instr->value());
1546 return new (zone()) LHasInstanceTypeAndBranch(value);
1547 }
1548
DoClassOfTestAndBranch(HClassOfTestAndBranch * instr)1549 LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1550 HClassOfTestAndBranch* instr) {
1551 DCHECK(instr->value()->representation().IsTagged());
1552 LOperand* value = UseRegister(instr->value());
1553 return new (zone()) LClassOfTestAndBranch(value, TempRegister());
1554 }
1555
DoSeqStringGetChar(HSeqStringGetChar * instr)1556 LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1557 LOperand* string = UseRegisterAtStart(instr->string());
1558 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1559 return DefineAsRegister(new (zone()) LSeqStringGetChar(string, index));
1560 }
1561
DoSeqStringSetChar(HSeqStringSetChar * instr)1562 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1563 LOperand* string = UseRegisterAtStart(instr->string());
1564 LOperand* index = FLAG_debug_code
1565 ? UseRegisterAtStart(instr->index())
1566 : UseRegisterOrConstantAtStart(instr->index());
1567 LOperand* value = UseRegisterAtStart(instr->value());
1568 LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
1569 return new (zone()) LSeqStringSetChar(context, string, index, value);
1570 }
1571
DoBoundsCheck(HBoundsCheck * instr)1572 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1573 if (!FLAG_debug_code && instr->skip_check()) return NULL;
1574 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1575 LOperand* length = !index->IsConstantOperand()
1576 ? UseRegisterOrConstantAtStart(instr->length())
1577 : UseRegisterAtStart(instr->length());
1578 LInstruction* result = new (zone()) LBoundsCheck(index, length);
1579 if (!FLAG_debug_code || !instr->skip_check()) {
1580 result = AssignEnvironment(result);
1581 }
1582 return result;
1583 }
1584
DoAbnormalExit(HAbnormalExit * instr)1585 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1586 // The control instruction marking the end of a block that completed
1587 // abruptly (e.g., threw an exception). There is nothing specific to do.
1588 return NULL;
1589 }
1590
DoUseConst(HUseConst * instr)1591 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { return NULL; }
1592
DoForceRepresentation(HForceRepresentation * bad)1593 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1594 // All HForceRepresentation instructions should be eliminated in the
1595 // representation change phase of Hydrogen.
1596 UNREACHABLE();
1597 return NULL;
1598 }
1599
DoChange(HChange * instr)1600 LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1601 Representation from = instr->from();
1602 Representation to = instr->to();
1603 HValue* val = instr->value();
1604 if (from.IsSmi()) {
1605 if (to.IsTagged()) {
1606 LOperand* value = UseRegister(val);
1607 return DefineSameAsFirst(new (zone()) LDummyUse(value));
1608 }
1609 from = Representation::Tagged();
1610 }
1611 if (from.IsTagged()) {
1612 if (to.IsDouble()) {
1613 LOperand* value = UseRegister(val);
1614 LInstruction* result =
1615 DefineAsRegister(new (zone()) LNumberUntagD(value));
1616 if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1617 return result;
1618 } else if (to.IsSmi()) {
1619 LOperand* value = UseRegister(val);
1620 if (val->type().IsSmi()) {
1621 return DefineSameAsFirst(new (zone()) LDummyUse(value));
1622 }
1623 return AssignEnvironment(
1624 DefineSameAsFirst(new (zone()) LCheckSmi(value)));
1625 } else {
1626 DCHECK(to.IsInteger32());
1627 if (val->type().IsSmi() || val->representation().IsSmi()) {
1628 LOperand* value = UseRegisterAtStart(val);
1629 return DefineAsRegister(new (zone()) LSmiUntag(value, false));
1630 } else {
1631 LOperand* value = UseRegister(val);
1632 LOperand* temp1 = TempRegister();
1633 LOperand* temp2 = TempDoubleRegister();
1634 LInstruction* result =
1635 DefineSameAsFirst(new (zone()) LTaggedToI(value, temp1, temp2));
1636 if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1637 return result;
1638 }
1639 }
1640 } else if (from.IsDouble()) {
1641 if (to.IsTagged()) {
1642 info()->MarkAsDeferredCalling();
1643 LOperand* value = UseRegister(val);
1644 LOperand* temp1 = TempRegister();
1645 LOperand* temp2 = TempRegister();
1646 LUnallocated* result_temp = TempRegister();
1647 LNumberTagD* result = new (zone()) LNumberTagD(value, temp1, temp2);
1648 return AssignPointerMap(Define(result, result_temp));
1649 } else if (to.IsSmi()) {
1650 LOperand* value = UseRegister(val);
1651 return AssignEnvironment(
1652 DefineAsRegister(new (zone()) LDoubleToSmi(value)));
1653 } else {
1654 DCHECK(to.IsInteger32());
1655 LOperand* value = UseRegister(val);
1656 LInstruction* result = DefineAsRegister(new (zone()) LDoubleToI(value));
1657 if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1658 return result;
1659 }
1660 } else if (from.IsInteger32()) {
1661 info()->MarkAsDeferredCalling();
1662 if (to.IsTagged()) {
1663 if (!instr->CheckFlag(HValue::kCanOverflow)) {
1664 LOperand* value = UseRegisterAtStart(val);
1665 return DefineAsRegister(new (zone()) LSmiTag(value));
1666 } else if (val->CheckFlag(HInstruction::kUint32)) {
1667 LOperand* value = UseRegisterAtStart(val);
1668 LOperand* temp1 = TempRegister();
1669 LOperand* temp2 = TempRegister();
1670 LNumberTagU* result = new (zone()) LNumberTagU(value, temp1, temp2);
1671 return AssignPointerMap(DefineAsRegister(result));
1672 } else {
1673 LOperand* value = UseRegisterAtStart(val);
1674 LOperand* temp1 = TempRegister();
1675 LOperand* temp2 = TempRegister();
1676 LNumberTagI* result = new (zone()) LNumberTagI(value, temp1, temp2);
1677 return AssignPointerMap(DefineAsRegister(result));
1678 }
1679 } else if (to.IsSmi()) {
1680 LOperand* value = UseRegister(val);
1681 LInstruction* result = DefineAsRegister(new (zone()) LSmiTag(value));
1682 if (instr->CheckFlag(HValue::kCanOverflow)) {
1683 result = AssignEnvironment(result);
1684 }
1685 return result;
1686 } else {
1687 DCHECK(to.IsDouble());
1688 if (val->CheckFlag(HInstruction::kUint32)) {
1689 return DefineAsRegister(new (zone()) LUint32ToDouble(UseRegister(val)));
1690 } else {
1691 return DefineAsRegister(new (zone()) LInteger32ToDouble(Use(val)));
1692 }
1693 }
1694 }
1695 UNREACHABLE();
1696 return NULL;
1697 }
1698
DoCheckHeapObject(HCheckHeapObject * instr)1699 LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1700 LOperand* value = UseRegisterAtStart(instr->value());
1701 LInstruction* result = new (zone()) LCheckNonSmi(value);
1702 if (!instr->value()->type().IsHeapObject()) {
1703 result = AssignEnvironment(result);
1704 }
1705 return result;
1706 }
1707
DoCheckSmi(HCheckSmi * instr)1708 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1709 LOperand* value = UseRegisterAtStart(instr->value());
1710 return AssignEnvironment(new (zone()) LCheckSmi(value));
1711 }
1712
DoCheckArrayBufferNotNeutered(HCheckArrayBufferNotNeutered * instr)1713 LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1714 HCheckArrayBufferNotNeutered* instr) {
1715 LOperand* view = UseRegisterAtStart(instr->value());
1716 LCheckArrayBufferNotNeutered* result =
1717 new (zone()) LCheckArrayBufferNotNeutered(view);
1718 return AssignEnvironment(result);
1719 }
1720
DoCheckInstanceType(HCheckInstanceType * instr)1721 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1722 LOperand* value = UseRegisterAtStart(instr->value());
1723 LInstruction* result = new (zone()) LCheckInstanceType(value);
1724 return AssignEnvironment(result);
1725 }
1726
DoCheckValue(HCheckValue * instr)1727 LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1728 LOperand* value = UseRegisterAtStart(instr->value());
1729 return AssignEnvironment(new (zone()) LCheckValue(value));
1730 }
1731
DoCheckMaps(HCheckMaps * instr)1732 LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1733 if (instr->IsStabilityCheck()) return new (zone()) LCheckMaps;
1734 LOperand* value = UseRegisterAtStart(instr->value());
1735 LOperand* temp = TempRegister();
1736 LInstruction* result =
1737 AssignEnvironment(new (zone()) LCheckMaps(value, temp));
1738 if (instr->HasMigrationTarget()) {
1739 info()->MarkAsDeferredCalling();
1740 result = AssignPointerMap(result);
1741 }
1742 return result;
1743 }
1744
DoClampToUint8(HClampToUint8 * instr)1745 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1746 HValue* value = instr->value();
1747 Representation input_rep = value->representation();
1748 LOperand* reg = UseRegister(value);
1749 if (input_rep.IsDouble()) {
1750 return DefineAsRegister(new (zone()) LClampDToUint8(reg));
1751 } else if (input_rep.IsInteger32()) {
1752 return DefineAsRegister(new (zone()) LClampIToUint8(reg));
1753 } else {
1754 DCHECK(input_rep.IsSmiOrTagged());
1755 LClampTToUint8* result =
1756 new (zone()) LClampTToUint8(reg, TempDoubleRegister());
1757 return AssignEnvironment(DefineAsRegister(result));
1758 }
1759 }
1760
DoReturn(HReturn * instr)1761 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1762 LOperand* context = info()->IsStub() ? UseFixed(instr->context(), cp) : NULL;
1763 LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1764 return new (zone())
1765 LReturn(UseFixed(instr->value(), r2), context, parameter_count);
1766 }
1767
DoConstant(HConstant * instr)1768 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1769 Representation r = instr->representation();
1770 if (r.IsSmi()) {
1771 return DefineAsRegister(new (zone()) LConstantS);
1772 } else if (r.IsInteger32()) {
1773 return DefineAsRegister(new (zone()) LConstantI);
1774 } else if (r.IsDouble()) {
1775 return DefineAsRegister(new (zone()) LConstantD);
1776 } else if (r.IsExternal()) {
1777 return DefineAsRegister(new (zone()) LConstantE);
1778 } else if (r.IsTagged()) {
1779 return DefineAsRegister(new (zone()) LConstantT);
1780 } else {
1781 UNREACHABLE();
1782 return NULL;
1783 }
1784 }
1785
DoLoadContextSlot(HLoadContextSlot * instr)1786 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1787 LOperand* context = UseRegisterAtStart(instr->value());
1788 LInstruction* result =
1789 DefineAsRegister(new (zone()) LLoadContextSlot(context));
1790 if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1791 result = AssignEnvironment(result);
1792 }
1793 return result;
1794 }
1795
DoStoreContextSlot(HStoreContextSlot * instr)1796 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1797 LOperand* context;
1798 LOperand* value;
1799 if (instr->NeedsWriteBarrier()) {
1800 context = UseTempRegister(instr->context());
1801 value = UseTempRegister(instr->value());
1802 } else {
1803 context = UseRegister(instr->context());
1804 value = UseRegister(instr->value());
1805 }
1806 LInstruction* result = new (zone()) LStoreContextSlot(context, value);
1807 if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1808 result = AssignEnvironment(result);
1809 }
1810 return result;
1811 }
1812
DoLoadNamedField(HLoadNamedField * instr)1813 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1814 LOperand* obj = UseRegisterAtStart(instr->object());
1815 return DefineAsRegister(new (zone()) LLoadNamedField(obj));
1816 }
1817
DoLoadFunctionPrototype(HLoadFunctionPrototype * instr)1818 LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
1819 HLoadFunctionPrototype* instr) {
1820 return AssignEnvironment(DefineAsRegister(
1821 new (zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
1822 }
1823
DoLoadRoot(HLoadRoot * instr)1824 LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
1825 return DefineAsRegister(new (zone()) LLoadRoot);
1826 }
1827
DoLoadKeyed(HLoadKeyed * instr)1828 LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
1829 DCHECK(instr->key()->representation().IsSmiOrInteger32());
1830 ElementsKind elements_kind = instr->elements_kind();
1831 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1832 LInstruction* result = NULL;
1833
1834 if (!instr->is_fixed_typed_array()) {
1835 LOperand* obj = NULL;
1836 if (instr->representation().IsDouble()) {
1837 obj = UseRegister(instr->elements());
1838 } else {
1839 obj = UseRegisterAtStart(instr->elements());
1840 }
1841 result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
1842 } else {
1843 DCHECK((instr->representation().IsInteger32() &&
1844 !IsDoubleOrFloatElementsKind(elements_kind)) ||
1845 (instr->representation().IsDouble() &&
1846 IsDoubleOrFloatElementsKind(elements_kind)));
1847 LOperand* backing_store = UseRegister(instr->elements());
1848 LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1849 result = DefineAsRegister(
1850 new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
1851 }
1852
1853 bool needs_environment;
1854 if (instr->is_fixed_typed_array()) {
1855 // see LCodeGen::DoLoadKeyedExternalArray
1856 needs_environment = elements_kind == UINT32_ELEMENTS &&
1857 !instr->CheckFlag(HInstruction::kUint32);
1858 } else {
1859 // see LCodeGen::DoLoadKeyedFixedDoubleArray and
1860 // LCodeGen::DoLoadKeyedFixedArray
1861 needs_environment =
1862 instr->RequiresHoleCheck() ||
1863 (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
1864 }
1865
1866 if (needs_environment) {
1867 result = AssignEnvironment(result);
1868 }
1869 return result;
1870 }
1871
DoStoreKeyed(HStoreKeyed * instr)1872 LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
1873 if (!instr->is_fixed_typed_array()) {
1874 DCHECK(instr->elements()->representation().IsTagged());
1875 bool needs_write_barrier = instr->NeedsWriteBarrier();
1876 LOperand* object = NULL;
1877 LOperand* key = NULL;
1878 LOperand* val = NULL;
1879
1880 if (instr->value()->representation().IsDouble()) {
1881 object = UseRegisterAtStart(instr->elements());
1882 val = UseRegister(instr->value());
1883 key = UseRegisterOrConstantAtStart(instr->key());
1884 } else {
1885 if (needs_write_barrier) {
1886 object = UseTempRegister(instr->elements());
1887 val = UseTempRegister(instr->value());
1888 key = UseTempRegister(instr->key());
1889 } else {
1890 object = UseRegisterAtStart(instr->elements());
1891 val = UseRegisterAtStart(instr->value());
1892 key = UseRegisterOrConstantAtStart(instr->key());
1893 }
1894 }
1895
1896 return new (zone()) LStoreKeyed(object, key, val, nullptr);
1897 }
1898
1899 DCHECK((instr->value()->representation().IsInteger32() &&
1900 !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
1901 (instr->value()->representation().IsDouble() &&
1902 IsDoubleOrFloatElementsKind(instr->elements_kind())));
1903 DCHECK(instr->elements()->representation().IsExternal());
1904 LOperand* val = UseRegister(instr->value());
1905 LOperand* key = UseRegisterOrConstantAtStart(instr->key());
1906 LOperand* backing_store = UseRegister(instr->elements());
1907 LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
1908 return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
1909 }
1910
DoTransitionElementsKind(HTransitionElementsKind * instr)1911 LInstruction* LChunkBuilder::DoTransitionElementsKind(
1912 HTransitionElementsKind* instr) {
1913 if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
1914 LOperand* object = UseRegister(instr->object());
1915 LOperand* new_map_reg = TempRegister();
1916 LTransitionElementsKind* result =
1917 new (zone()) LTransitionElementsKind(object, NULL, new_map_reg);
1918 return result;
1919 } else {
1920 LOperand* object = UseFixed(instr->object(), r2);
1921 LOperand* context = UseFixed(instr->context(), cp);
1922 LTransitionElementsKind* result =
1923 new (zone()) LTransitionElementsKind(object, context, NULL);
1924 return MarkAsCall(result, instr);
1925 }
1926 }
1927
DoTrapAllocationMemento(HTrapAllocationMemento * instr)1928 LInstruction* LChunkBuilder::DoTrapAllocationMemento(
1929 HTrapAllocationMemento* instr) {
1930 LOperand* object = UseRegister(instr->object());
1931 LOperand* temp1 = TempRegister();
1932 LOperand* temp2 = TempRegister();
1933 LTrapAllocationMemento* result =
1934 new (zone()) LTrapAllocationMemento(object, temp1, temp2);
1935 return AssignEnvironment(result);
1936 }
1937
DoMaybeGrowElements(HMaybeGrowElements * instr)1938 LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
1939 info()->MarkAsDeferredCalling();
1940 LOperand* context = UseFixed(instr->context(), cp);
1941 LOperand* object = Use(instr->object());
1942 LOperand* elements = Use(instr->elements());
1943 LOperand* key = UseRegisterOrConstant(instr->key());
1944 LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
1945
1946 LMaybeGrowElements* result = new (zone())
1947 LMaybeGrowElements(context, object, elements, key, current_capacity);
1948 DefineFixed(result, r2);
1949 return AssignPointerMap(AssignEnvironment(result));
1950 }
1951
DoStoreNamedField(HStoreNamedField * instr)1952 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
1953 bool is_in_object = instr->access().IsInobject();
1954 bool needs_write_barrier = instr->NeedsWriteBarrier();
1955 bool needs_write_barrier_for_map =
1956 instr->has_transition() && instr->NeedsWriteBarrierForMap();
1957
1958 LOperand* obj;
1959 if (needs_write_barrier) {
1960 obj = is_in_object ? UseRegister(instr->object())
1961 : UseTempRegister(instr->object());
1962 } else {
1963 obj = needs_write_barrier_for_map ? UseRegister(instr->object())
1964 : UseRegisterAtStart(instr->object());
1965 }
1966
1967 LOperand* val;
1968 if (needs_write_barrier) {
1969 val = UseTempRegister(instr->value());
1970 } else if (instr->field_representation().IsDouble()) {
1971 val = UseRegisterAtStart(instr->value());
1972 } else {
1973 val = UseRegister(instr->value());
1974 }
1975
1976 // We need a temporary register for write barrier of the map field.
1977 LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
1978
1979 return new (zone()) LStoreNamedField(obj, val, temp);
1980 }
1981
DoStringAdd(HStringAdd * instr)1982 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
1983 LOperand* context = UseFixed(instr->context(), cp);
1984 LOperand* left = UseFixed(instr->left(), r3);
1985 LOperand* right = UseFixed(instr->right(), r2);
1986 return MarkAsCall(
1987 DefineFixed(new (zone()) LStringAdd(context, left, right), r2), instr);
1988 }
1989
DoStringCharCodeAt(HStringCharCodeAt * instr)1990 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
1991 LOperand* string = UseTempRegister(instr->string());
1992 LOperand* index = UseTempRegister(instr->index());
1993 LOperand* context = UseAny(instr->context());
1994 LStringCharCodeAt* result =
1995 new (zone()) LStringCharCodeAt(context, string, index);
1996 return AssignPointerMap(DefineAsRegister(result));
1997 }
1998
DoStringCharFromCode(HStringCharFromCode * instr)1999 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2000 LOperand* char_code = UseRegister(instr->value());
2001 LOperand* context = UseAny(instr->context());
2002 LStringCharFromCode* result =
2003 new (zone()) LStringCharFromCode(context, char_code);
2004 return AssignPointerMap(DefineAsRegister(result));
2005 }
2006
DoAllocate(HAllocate * instr)2007 LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2008 LOperand* size = UseRegisterOrConstant(instr->size());
2009 LOperand* temp1 = TempRegister();
2010 LOperand* temp2 = TempRegister();
2011 if (instr->IsAllocationFolded()) {
2012 LFastAllocate* result = new (zone()) LFastAllocate(size, temp1, temp2);
2013 return DefineAsRegister(result);
2014 } else {
2015 info()->MarkAsDeferredCalling();
2016 LOperand* context = UseAny(instr->context());
2017 LAllocate* result = new (zone()) LAllocate(context, size, temp1, temp2);
2018 return AssignPointerMap(DefineAsRegister(result));
2019 }
2020 }
2021
DoOsrEntry(HOsrEntry * instr)2022 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2023 DCHECK(argument_count_ == 0);
2024 allocator_->MarkAsOsrEntry();
2025 current_block_->last_environment()->set_ast_id(instr->ast_id());
2026 return AssignEnvironment(new (zone()) LOsrEntry);
2027 }
2028
DoParameter(HParameter * instr)2029 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2030 LParameter* result = new (zone()) LParameter;
2031 if (instr->kind() == HParameter::STACK_PARAMETER) {
2032 int spill_index = chunk()->GetParameterStackSlot(instr->index());
2033 return DefineAsSpilled(result, spill_index);
2034 } else {
2035 DCHECK(info()->IsStub());
2036 CallInterfaceDescriptor descriptor = graph()->descriptor();
2037 int index = static_cast<int>(instr->index());
2038 Register reg = descriptor.GetRegisterParameter(index);
2039 return DefineFixed(result, reg);
2040 }
2041 }
2042
DoUnknownOSRValue(HUnknownOSRValue * instr)2043 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2044 // Use an index that corresponds to the location in the unoptimized frame,
2045 // which the optimized frame will subsume.
2046 int env_index = instr->index();
2047 int spill_index = 0;
2048 if (instr->environment()->is_parameter_index(env_index)) {
2049 spill_index = chunk()->GetParameterStackSlot(env_index);
2050 } else {
2051 spill_index = env_index - instr->environment()->first_local_index();
2052 if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2053 Retry(kTooManySpillSlotsNeededForOSR);
2054 spill_index = 0;
2055 }
2056 spill_index += StandardFrameConstants::kFixedSlotCount;
2057 }
2058 return DefineAsSpilled(new (zone()) LUnknownOSRValue, spill_index);
2059 }
2060
DoArgumentsObject(HArgumentsObject * instr)2061 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2062 // There are no real uses of the arguments object.
2063 // arguments.length and element access are supported directly on
2064 // stack arguments, and any real arguments object use causes a bailout.
2065 // So this value is never used.
2066 return NULL;
2067 }
2068
DoCapturedObject(HCapturedObject * instr)2069 LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2070 instr->ReplayEnvironment(current_block_->last_environment());
2071
2072 // There are no real uses of a captured object.
2073 return NULL;
2074 }
2075
DoAccessArgumentsAt(HAccessArgumentsAt * instr)2076 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2077 info()->MarkAsRequiresFrame();
2078 LOperand* args = UseRegister(instr->arguments());
2079 LOperand* length = UseRegisterOrConstantAtStart(instr->length());
2080 LOperand* index = UseRegisterOrConstantAtStart(instr->index());
2081 return DefineAsRegister(new (zone()) LAccessArgumentsAt(args, length, index));
2082 }
2083
DoTypeof(HTypeof * instr)2084 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2085 LOperand* context = UseFixed(instr->context(), cp);
2086 LOperand* value = UseFixed(instr->value(), r5);
2087 LTypeof* result = new (zone()) LTypeof(context, value);
2088 return MarkAsCall(DefineFixed(result, r2), instr);
2089 }
2090
DoTypeofIsAndBranch(HTypeofIsAndBranch * instr)2091 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2092 return new (zone()) LTypeofIsAndBranch(UseRegister(instr->value()));
2093 }
2094
DoSimulate(HSimulate * instr)2095 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2096 instr->ReplayEnvironment(current_block_->last_environment());
2097 return NULL;
2098 }
2099
DoStackCheck(HStackCheck * instr)2100 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2101 if (instr->is_function_entry()) {
2102 LOperand* context = UseFixed(instr->context(), cp);
2103 return MarkAsCall(new (zone()) LStackCheck(context), instr);
2104 } else {
2105 DCHECK(instr->is_backwards_branch());
2106 LOperand* context = UseAny(instr->context());
2107 return AssignEnvironment(
2108 AssignPointerMap(new (zone()) LStackCheck(context)));
2109 }
2110 }
2111
DoEnterInlined(HEnterInlined * instr)2112 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2113 HEnvironment* outer = current_block_->last_environment();
2114 outer->set_ast_id(instr->ReturnId());
2115 HConstant* undefined = graph()->GetConstantUndefined();
2116 HEnvironment* inner = outer->CopyForInlining(
2117 instr->closure(), instr->arguments_count(), instr->function(), undefined,
2118 instr->inlining_kind(), instr->syntactic_tail_call_mode());
2119 // Only replay binding of arguments object if it wasn't removed from graph.
2120 if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2121 inner->Bind(instr->arguments_var(), instr->arguments_object());
2122 }
2123 inner->BindContext(instr->closure_context());
2124 inner->set_entry(instr);
2125 current_block_->UpdateEnvironment(inner);
2126 return NULL;
2127 }
2128
DoLeaveInlined(HLeaveInlined * instr)2129 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2130 LInstruction* pop = NULL;
2131
2132 HEnvironment* env = current_block_->last_environment();
2133
2134 if (env->entry()->arguments_pushed()) {
2135 int argument_count = env->arguments_environment()->parameter_count();
2136 pop = new (zone()) LDrop(argument_count);
2137 DCHECK(instr->argument_delta() == -argument_count);
2138 }
2139
2140 HEnvironment* outer =
2141 current_block_->last_environment()->DiscardInlined(false);
2142 current_block_->UpdateEnvironment(outer);
2143
2144 return pop;
2145 }
2146
DoForInPrepareMap(HForInPrepareMap * instr)2147 LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2148 LOperand* context = UseFixed(instr->context(), cp);
2149 LOperand* object = UseFixed(instr->enumerable(), r2);
2150 LForInPrepareMap* result = new (zone()) LForInPrepareMap(context, object);
2151 return MarkAsCall(DefineFixed(result, r2), instr, CAN_DEOPTIMIZE_EAGERLY);
2152 }
2153
DoForInCacheArray(HForInCacheArray * instr)2154 LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2155 LOperand* map = UseRegister(instr->map());
2156 return AssignEnvironment(
2157 DefineAsRegister(new (zone()) LForInCacheArray(map)));
2158 }
2159
DoCheckMapValue(HCheckMapValue * instr)2160 LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2161 LOperand* value = UseRegisterAtStart(instr->value());
2162 LOperand* map = UseRegisterAtStart(instr->map());
2163 return AssignEnvironment(new (zone()) LCheckMapValue(value, map));
2164 }
2165
DoLoadFieldByIndex(HLoadFieldByIndex * instr)2166 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2167 LOperand* object = UseRegister(instr->object());
2168 LOperand* index = UseTempRegister(instr->index());
2169 LLoadFieldByIndex* load = new (zone()) LLoadFieldByIndex(object, index);
2170 LInstruction* result = DefineSameAsFirst(load);
2171 return AssignPointerMap(result);
2172 }
2173
2174 } // namespace internal
2175 } // namespace v8
2176