Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/crankshaft/x64/lithium-x64.h"
6 :
7 : #include <sstream>
8 :
9 : #if V8_TARGET_ARCH_X64
10 :
11 : #include "src/crankshaft/hydrogen-osr.h"
12 : #include "src/crankshaft/lithium-inl.h"
13 : #include "src/crankshaft/x64/lithium-codegen-x64.h"
14 : #include "src/objects-inl.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 : #define DEFINE_COMPILE(type) \
20 : void L##type::CompileToNative(LCodeGen* generator) { \
21 : generator->Do##type(this); \
22 : }
23 30836102 : LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
24 : #undef DEFINE_COMPILE
25 :
26 :
27 : #ifdef DEBUG
28 : void LInstruction::VerifyCall() {
29 : // Call instructions can use only fixed registers as temporaries and
30 : // outputs because all registers are blocked by the calling convention.
31 : // Inputs operands must use a fixed register or use-at-start policy or
32 : // a non-register policy.
33 : DCHECK(Output() == NULL ||
34 : LUnallocated::cast(Output())->HasFixedPolicy() ||
35 : !LUnallocated::cast(Output())->HasRegisterPolicy());
36 : for (UseIterator it(this); !it.Done(); it.Advance()) {
37 : LUnallocated* operand = LUnallocated::cast(it.Current());
38 : DCHECK(operand->HasFixedPolicy() ||
39 : operand->IsUsedAtStart());
40 : }
41 : for (TempIterator it(this); !it.Done(); it.Advance()) {
42 : LUnallocated* operand = LUnallocated::cast(it.Current());
43 : DCHECK(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
44 : }
45 : }
46 : #endif
47 :
48 :
49 0 : void LInstruction::PrintTo(StringStream* stream) {
50 0 : stream->Add("%s ", this->Mnemonic());
51 :
52 0 : PrintOutputOperandTo(stream);
53 :
54 0 : PrintDataTo(stream);
55 :
56 0 : if (HasEnvironment()) {
57 0 : stream->Add(" ");
58 0 : environment()->PrintTo(stream);
59 : }
60 :
61 0 : if (HasPointerMap()) {
62 0 : stream->Add(" ");
63 0 : pointer_map()->PrintTo(stream);
64 : }
65 0 : }
66 :
67 :
68 0 : void LInstruction::PrintDataTo(StringStream* stream) {
69 0 : stream->Add("= ");
70 0 : for (int i = 0; i < InputCount(); i++) {
71 0 : if (i > 0) stream->Add(" ");
72 0 : if (InputAt(i) == NULL) {
73 0 : stream->Add("NULL");
74 : } else {
75 0 : InputAt(i)->PrintTo(stream);
76 : }
77 : }
78 0 : }
79 :
80 :
81 0 : void LInstruction::PrintOutputOperandTo(StringStream* stream) {
82 0 : if (HasResult()) result()->PrintTo(stream);
83 0 : }
84 :
85 :
86 0 : void LLabel::PrintDataTo(StringStream* stream) {
87 0 : LGap::PrintDataTo(stream);
88 : LLabel* rep = replacement();
89 0 : if (rep != NULL) {
90 0 : stream->Add(" Dead block replaced with B%d", rep->block_id());
91 : }
92 0 : }
93 :
94 :
95 8393490 : bool LGap::IsRedundant() const {
96 40958944 : for (int i = 0; i < 4; i++) {
97 32911632 : if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) {
98 : return false;
99 : }
100 : }
101 :
102 : return true;
103 : }
104 :
105 :
106 0 : void LGap::PrintDataTo(StringStream* stream) {
107 0 : for (int i = 0; i < 4; i++) {
108 0 : stream->Add("(");
109 0 : if (parallel_moves_[i] != NULL) {
110 0 : parallel_moves_[i]->PrintDataTo(stream);
111 : }
112 0 : stream->Add(") ");
113 : }
114 0 : }
115 :
116 :
117 0 : const char* LArithmeticD::Mnemonic() const {
118 0 : switch (op()) {
119 : case Token::ADD: return "add-d";
120 0 : case Token::SUB: return "sub-d";
121 0 : case Token::MUL: return "mul-d";
122 0 : case Token::DIV: return "div-d";
123 0 : case Token::MOD: return "mod-d";
124 : default:
125 0 : UNREACHABLE();
126 : return NULL;
127 : }
128 : }
129 :
130 :
131 0 : const char* LArithmeticT::Mnemonic() const {
132 0 : switch (op()) {
133 : case Token::ADD: return "add-t";
134 0 : case Token::SUB: return "sub-t";
135 0 : case Token::MUL: return "mul-t";
136 0 : case Token::MOD: return "mod-t";
137 0 : case Token::DIV: return "div-t";
138 0 : case Token::BIT_AND: return "bit-and-t";
139 0 : case Token::BIT_OR: return "bit-or-t";
140 0 : case Token::BIT_XOR: return "bit-xor-t";
141 0 : case Token::ROR: return "ror-t";
142 0 : case Token::SHL: return "sal-t";
143 0 : case Token::SAR: return "sar-t";
144 0 : case Token::SHR: return "shr-t";
145 : default:
146 0 : UNREACHABLE();
147 : return NULL;
148 : }
149 : }
150 :
151 :
152 0 : bool LGoto::HasInterestingComment(LCodeGen* gen) const {
153 0 : return !gen->IsNextEmittedBlock(block_id());
154 : }
155 :
156 :
157 : template<int R>
158 7133966 : bool LTemplateResultInstruction<R>::MustSignExtendResult(
159 : LPlatformChunk* chunk) const {
160 8168988 : HValue* hvalue = this->hydrogen_value();
161 : return hvalue != NULL &&
162 : hvalue->representation().IsInteger32() &&
163 9204010 : chunk->GetDehoistedKeyIds()->Contains(hvalue->id());
164 : }
165 :
166 :
167 0 : void LGoto::PrintDataTo(StringStream* stream) {
168 0 : stream->Add("B%d", block_id());
169 0 : }
170 :
171 :
172 0 : void LBranch::PrintDataTo(StringStream* stream) {
173 0 : stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
174 0 : value()->PrintTo(stream);
175 0 : }
176 :
177 :
178 0 : void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
179 0 : stream->Add("if ");
180 0 : left()->PrintTo(stream);
181 0 : stream->Add(" %s ", Token::String(op()));
182 0 : right()->PrintTo(stream);
183 0 : stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
184 0 : }
185 :
186 :
187 0 : void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
188 0 : stream->Add("if is_string(");
189 0 : value()->PrintTo(stream);
190 0 : stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
191 0 : }
192 :
193 :
194 0 : void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
195 0 : stream->Add("if is_smi(");
196 0 : value()->PrintTo(stream);
197 0 : stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
198 0 : }
199 :
200 :
201 0 : void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
202 0 : stream->Add("if is_undetectable(");
203 0 : value()->PrintTo(stream);
204 0 : stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
205 0 : }
206 :
207 :
208 0 : void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
209 0 : stream->Add("if string_compare(");
210 0 : left()->PrintTo(stream);
211 0 : right()->PrintTo(stream);
212 0 : stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
213 0 : }
214 :
215 :
216 0 : void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
217 0 : stream->Add("if has_instance_type(");
218 0 : value()->PrintTo(stream);
219 0 : stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
220 0 : }
221 :
222 0 : void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
223 0 : stream->Add("if class_of_test(");
224 0 : value()->PrintTo(stream);
225 : stream->Add(", \"%o\") then B%d else B%d", *hydrogen()->class_name(),
226 0 : true_block_id(), false_block_id());
227 0 : }
228 :
229 0 : void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
230 0 : stream->Add("if typeof ");
231 0 : value()->PrintTo(stream);
232 : stream->Add(" == \"%s\" then B%d else B%d",
233 : hydrogen()->type_literal()->ToCString().get(),
234 0 : true_block_id(), false_block_id());
235 0 : }
236 :
237 :
238 0 : void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
239 0 : stream->Add(" = ");
240 0 : function()->PrintTo(stream);
241 0 : stream->Add(".code_entry = ");
242 0 : code_object()->PrintTo(stream);
243 0 : }
244 :
245 :
246 0 : void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
247 0 : stream->Add(" = ");
248 0 : base_object()->PrintTo(stream);
249 0 : stream->Add(" + ");
250 0 : offset()->PrintTo(stream);
251 0 : }
252 :
253 :
254 0 : void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
255 0 : for (int i = 0; i < InputCount(); i++) {
256 0 : InputAt(i)->PrintTo(stream);
257 0 : stream->Add(" ");
258 : }
259 0 : stream->Add("#%d / ", arity());
260 0 : }
261 :
262 :
263 0 : void LLoadContextSlot::PrintDataTo(StringStream* stream) {
264 0 : context()->PrintTo(stream);
265 0 : stream->Add("[%d]", slot_index());
266 0 : }
267 :
268 :
269 0 : void LStoreContextSlot::PrintDataTo(StringStream* stream) {
270 0 : context()->PrintTo(stream);
271 0 : stream->Add("[%d] <- ", slot_index());
272 0 : value()->PrintTo(stream);
273 0 : }
274 :
275 :
276 0 : void LInvokeFunction::PrintDataTo(StringStream* stream) {
277 0 : stream->Add("= ");
278 0 : function()->PrintTo(stream);
279 0 : stream->Add(" #%d / ", arity());
280 0 : }
281 :
282 :
283 0 : void LCallNewArray::PrintDataTo(StringStream* stream) {
284 0 : stream->Add("= ");
285 0 : constructor()->PrintTo(stream);
286 0 : stream->Add(" #%d / ", arity());
287 0 : ElementsKind kind = hydrogen()->elements_kind();
288 0 : stream->Add(" (%s) ", ElementsKindToString(kind));
289 0 : }
290 :
291 :
292 0 : void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
293 0 : arguments()->PrintTo(stream);
294 :
295 0 : stream->Add(" length ");
296 0 : length()->PrintTo(stream);
297 :
298 0 : stream->Add(" index ");
299 0 : index()->PrintTo(stream);
300 0 : }
301 :
302 :
303 0 : int LPlatformChunk::GetNextSpillIndex(RegisterKind kind) {
304 : if (kind == DOUBLE_REGISTERS && kDoubleSize == 2 * kPointerSize) {
305 : // Skip a slot if for a double-width slot for x32 port.
306 : current_frame_slots_++;
307 : // The spill slot's address is at rbp - (index + 1) * kPointerSize -
308 : // StandardFrameConstants::kFixedFrameSizeFromFp. kFixedFrameSizeFromFp is
309 : // 2 * kPointerSize, if rbp is aligned at 8-byte boundary, the below "|= 1"
310 : // will make sure the spilled doubles are aligned at 8-byte boundary.
311 : // TODO(haitao): make sure rbp is aligned at 8-byte boundary for x32 port.
312 : current_frame_slots_ |= 1;
313 : }
314 806387 : return current_frame_slots_++;
315 : }
316 :
317 :
318 798359 : LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
319 : // All stack slots are Double stack slots on x64.
320 : // Alternatively, at some point, start using half-size
321 : // stack slots for int32 values.
322 : int index = GetNextSpillIndex(kind);
323 798359 : if (kind == DOUBLE_REGISTERS) {
324 26202 : return LDoubleStackSlot::Create(index, zone());
325 : } else {
326 : DCHECK(kind == GENERAL_REGISTERS);
327 785258 : return LStackSlot::Create(index, zone());
328 : }
329 : }
330 :
331 :
332 0 : void LStoreNamedField::PrintDataTo(StringStream* stream) {
333 0 : object()->PrintTo(stream);
334 0 : std::ostringstream os;
335 0 : os << hydrogen()->access() << " <- ";
336 0 : stream->Add(os.str().c_str());
337 0 : value()->PrintTo(stream);
338 0 : }
339 :
340 :
341 0 : void LLoadKeyed::PrintDataTo(StringStream* stream) {
342 0 : elements()->PrintTo(stream);
343 0 : stream->Add("[");
344 0 : key()->PrintTo(stream);
345 0 : if (hydrogen()->IsDehoisted()) {
346 0 : stream->Add(" + %d]", base_offset());
347 : } else {
348 0 : stream->Add("]");
349 : }
350 0 : }
351 :
352 :
353 0 : void LStoreKeyed::PrintDataTo(StringStream* stream) {
354 0 : elements()->PrintTo(stream);
355 0 : stream->Add("[");
356 0 : key()->PrintTo(stream);
357 0 : if (hydrogen()->IsDehoisted()) {
358 0 : stream->Add(" + %d] <-", base_offset());
359 : } else {
360 0 : stream->Add("] <- ");
361 : }
362 :
363 0 : if (value() == NULL) {
364 : DCHECK(hydrogen()->IsConstantHoleStore() &&
365 : hydrogen()->value()->representation().IsDouble());
366 0 : stream->Add("<the hole(nan)>");
367 : } else {
368 0 : value()->PrintTo(stream);
369 : }
370 0 : }
371 :
372 :
373 0 : void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
374 0 : object()->PrintTo(stream);
375 0 : stream->Add(" %p -> %p", *original_map(), *transitioned_map());
376 0 : }
377 :
378 :
379 283727 : LPlatformChunk* LChunkBuilder::Build() {
380 : DCHECK(is_unused());
381 5362786 : chunk_ = new(zone()) LPlatformChunk(info(), graph());
382 : LPhase phase("L_Building chunk", chunk_);
383 283721 : status_ = BUILDING;
384 :
385 : // If compiling for OSR, reserve space for the unoptimized frame,
386 : // which will be subsumed into this frame.
387 283721 : if (graph()->has_osr()) {
388 10397 : for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
389 8028 : chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
390 : }
391 : }
392 :
393 : const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
394 9590664 : for (int i = 0; i < blocks->length(); i++) {
395 : HBasicBlock* next = NULL;
396 13534821 : if (i < blocks->length() - 1) next = blocks->at(i + 1);
397 4511602 : DoBasicBlock(blocks->at(i), next);
398 4511611 : if (is_aborted()) return NULL;
399 : }
400 283730 : status_ = DONE;
401 283730 : return chunk_;
402 : }
403 :
404 :
405 7393089 : LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
406 14786190 : return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
407 : }
408 :
409 :
410 65826 : LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
411 65826 : return new (zone())
412 65826 : LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
413 : }
414 :
415 :
416 5915663 : LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
417 5915663 : return Use(value, ToUnallocated(fixed_register));
418 : }
419 :
420 :
421 6164 : LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) {
422 6164 : return Use(value, ToUnallocated(reg));
423 : }
424 :
425 :
426 1033046 : LOperand* LChunkBuilder::UseRegister(HValue* value) {
427 2066093 : return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
428 : }
429 :
430 :
431 1952362 : LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
432 : return Use(value,
433 1952362 : new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
434 1952367 : LUnallocated::USED_AT_START));
435 : }
436 :
437 :
438 133444 : LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
439 266888 : return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
440 : }
441 :
442 :
443 0 : LOperand* LChunkBuilder::UseTempRegisterOrConstant(HValue* value) {
444 : return value->IsConstant()
445 0 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
446 0 : : UseTempRegister(value);
447 : }
448 :
449 :
450 695665 : LOperand* LChunkBuilder::Use(HValue* value) {
451 1391330 : return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
452 : }
453 :
454 :
455 131355 : LOperand* LChunkBuilder::UseAtStart(HValue* value) {
456 131355 : return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
457 131355 : LUnallocated::USED_AT_START));
458 : }
459 :
460 :
461 1368672 : LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
462 : return value->IsConstant()
463 710879 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
464 2079551 : : Use(value);
465 : }
466 :
467 :
468 366253 : LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
469 : return value->IsConstant()
470 239469 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
471 605722 : : UseAtStart(value);
472 : }
473 :
474 :
475 474270 : LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
476 : return value->IsConstant()
477 469198 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
478 943470 : : UseRegister(value);
479 : }
480 :
481 :
482 1274860 : LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
483 : return value->IsConstant()
484 990773 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
485 2265634 : : UseRegisterAtStart(value);
486 : }
487 :
488 :
489 0 : LOperand* LChunkBuilder::UseConstant(HValue* value) {
490 18056 : return chunk_->DefineConstantOperand(HConstant::cast(value));
491 : }
492 :
493 :
494 37780563 : LOperand* LChunkBuilder::UseAny(HValue* value) {
495 : return value->IsConstant()
496 17972358 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
497 75563677 : : Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
498 : }
499 :
500 :
501 59352453 : LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
502 29676305 : if (value->EmitAtUses()) {
503 : HInstruction* instr = HInstruction::cast(value);
504 3550637 : VisitInstruction(instr);
505 : }
506 29676148 : operand->set_virtual_register(value->id());
507 29676148 : return operand;
508 : }
509 :
510 :
511 0 : LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
512 : LUnallocated* result) {
513 7776693 : result->set_virtual_register(current_instruction_->id());
514 : instr->set_result(result);
515 0 : return instr;
516 : }
517 :
518 :
519 5492810 : LInstruction* LChunkBuilder::DefineAsRegister(
520 : LTemplateResultInstruction<1>* instr) {
521 : return Define(instr,
522 10985621 : new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
523 : }
524 :
525 :
526 436926 : LInstruction* LChunkBuilder::DefineAsSpilled(
527 : LTemplateResultInstruction<1>* instr,
528 : int index) {
529 : return Define(instr,
530 873853 : new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
531 : }
532 :
533 :
534 350136 : LInstruction* LChunkBuilder::DefineSameAsFirst(
535 : LTemplateResultInstruction<1>* instr) {
536 : return Define(instr,
537 700272 : new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
538 : }
539 :
540 :
541 1466261 : LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
542 : Register reg) {
543 2932524 : return Define(instr, ToUnallocated(reg));
544 : }
545 :
546 :
547 3551 : LInstruction* LChunkBuilder::DefineFixedDouble(
548 : LTemplateResultInstruction<1>* instr,
549 : XMMRegister reg) {
550 7102 : return Define(instr, ToUnallocated(reg));
551 : }
552 :
553 :
554 0 : LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
555 1239321 : HEnvironment* hydrogen_env = current_block_->last_environment();
556 1239321 : return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
557 : }
558 :
559 :
560 2504157 : LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
561 : HInstruction* hinstr,
562 : CanDeoptimize can_deoptimize) {
563 1695110 : info()->MarkAsNonDeferredCalling();
564 :
565 : #ifdef DEBUG
566 : instr->VerifyCall();
567 : #endif
568 : instr->MarkAsCall();
569 1695110 : instr = AssignPointerMap(instr);
570 :
571 : // If instruction does not have side-effects lazy deoptimization
572 : // after the call will try to deoptimize to the point before the call.
573 : // Thus we still need to attach environment to this call even if
574 : // call sequence can not deoptimize eagerly.
575 : bool needs_environment =
576 3388515 : (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
577 : !hinstr->HasObservableSideEffects();
578 2099639 : if (needs_environment && !instr->HasEnvironment()) {
579 : instr = AssignEnvironment(instr);
580 : // We can't really figure out if the environment is needed or not.
581 : instr->environment()->set_has_been_used();
582 : }
583 :
584 1695115 : return instr;
585 : }
586 :
587 :
588 1800266 : LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
589 : DCHECK(!instr->HasPointerMap());
590 3600538 : instr->set_pointer_map(new(zone()) LPointerMap(zone()));
591 1800271 : return instr;
592 : }
593 :
594 :
595 158092 : LUnallocated* LChunkBuilder::TempRegister() {
596 : LUnallocated* operand =
597 158092 : new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
598 316184 : int vreg = allocator_->GetVirtualRegister();
599 158092 : if (!allocator_->AllocationOk()) {
600 0 : Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
601 : vreg = 0;
602 : }
603 158092 : operand->set_virtual_register(vreg);
604 158092 : return operand;
605 : }
606 :
607 :
608 0 : LOperand* LChunkBuilder::FixedTemp(Register reg) {
609 6057 : LUnallocated* operand = ToUnallocated(reg);
610 : DCHECK(operand->HasFixedPolicy());
611 0 : return operand;
612 : }
613 :
614 :
615 0 : LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
616 56111 : LUnallocated* operand = ToUnallocated(reg);
617 : DCHECK(operand->HasFixedPolicy());
618 0 : return operand;
619 : }
620 :
621 :
622 4511579 : LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
623 9023155 : return new(zone()) LLabel(instr->block());
624 : }
625 :
626 :
627 0 : LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
628 0 : return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
629 : }
630 :
631 :
632 0 : LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
633 0 : UNREACHABLE();
634 : return NULL;
635 : }
636 :
637 :
638 188914 : LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
639 377827 : return AssignEnvironment(new(zone()) LDeoptimize);
640 : }
641 :
642 :
643 38689 : LInstruction* LChunkBuilder::DoShift(Token::Value op,
644 : HBitwiseBinaryOperation* instr) {
645 42264 : if (instr->representation().IsSmiOrInteger32()) {
646 : DCHECK(instr->left()->representation().Equals(instr->representation()));
647 : DCHECK(instr->right()->representation().Equals(instr->representation()));
648 36897 : LOperand* left = UseRegisterAtStart(instr->left());
649 :
650 : HValue* right_value = instr->right();
651 : LOperand* right = NULL;
652 : int constant_value = 0;
653 : bool does_deopt = false;
654 36897 : if (right_value->IsConstant()) {
655 31839 : HConstant* constant = HConstant::cast(right_value);
656 31839 : right = chunk_->DefineConstantOperand(constant);
657 31839 : constant_value = constant->Integer32Value() & 0x1f;
658 : if (SmiValuesAre31Bits() && instr->representation().IsSmi() &&
659 : constant_value > 0) {
660 : // Left shift can deoptimize if we shift by > 0 and the result
661 : // cannot be truncated to smi.
662 : does_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToSmi);
663 : }
664 : } else {
665 5058 : right = UseFixed(right_value, rcx);
666 : }
667 :
668 : // Shift operations can only deoptimize if we do a logical shift by 0 and
669 : // the result cannot be truncated to int32.
670 36897 : if (op == Token::SHR && constant_value == 0) {
671 3575 : does_deopt = !instr->CheckFlag(HInstruction::kUint32);
672 : }
673 :
674 : LInstruction* result =
675 73794 : DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
676 73794 : return does_deopt ? AssignEnvironment(result) : result;
677 : } else {
678 1792 : return DoArithmeticT(op, instr);
679 : }
680 : }
681 :
682 :
683 83800 : LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
684 : HArithmeticBinaryOperation* instr) {
685 : DCHECK(instr->representation().IsDouble());
686 : DCHECK(instr->left()->representation().IsDouble());
687 : DCHECK(instr->right()->representation().IsDouble());
688 83800 : if (op == Token::MOD) {
689 4450 : LOperand* left = UseFixedDouble(instr->BetterLeftOperand(), xmm0);
690 2225 : LOperand* right = UseFixedDouble(instr->BetterRightOperand(), xmm1);
691 83800 : LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
692 2225 : return MarkAsCall(DefineFixedDouble(result, xmm0), instr);
693 : } else {
694 163150 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
695 81575 : LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
696 : LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
697 : return CpuFeatures::IsSupported(AVX) ? DefineAsRegister(result)
698 81575 : : DefineSameAsFirst(result);
699 : }
700 : }
701 :
702 :
703 47577 : LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
704 : HBinaryOperation* instr) {
705 : HValue* left = instr->left();
706 : HValue* right = instr->right();
707 : DCHECK(left->representation().IsTagged());
708 : DCHECK(right->representation().IsTagged());
709 47577 : LOperand* context = UseFixed(instr->context(), rsi);
710 47577 : LOperand* left_operand = UseFixed(left, rdx);
711 47577 : LOperand* right_operand = UseFixed(right, rax);
712 : LArithmeticT* result =
713 47577 : new(zone()) LArithmeticT(op, context, left_operand, right_operand);
714 47577 : return MarkAsCall(DefineFixed(result, rax), instr);
715 : }
716 :
717 :
718 12053981 : void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
719 : DCHECK(is_building());
720 4511662 : current_block_ = block;
721 4511662 : next_block_ = next_block;
722 4511662 : if (block->IsStartBlock()) {
723 283722 : block->UpdateEnvironment(graph_->start_environment());
724 283766 : argument_count_ = 0;
725 4227940 : } else if (block->predecessors()->length() == 1) {
726 : // We have a single predecessor => copy environment and outgoing
727 : // argument count from the predecessor.
728 : DCHECK(block->phis()->length() == 0);
729 10595254 : HBasicBlock* pred = block->predecessors()->at(0);
730 : HEnvironment* last_environment = pred->last_environment();
731 : DCHECK(last_environment != NULL);
732 : // Only copy the environment, if it is later used again.
733 3782316 : if (pred->end()->SecondSuccessor() == NULL) {
734 : DCHECK(pred->end()->FirstSuccessor() == block);
735 : } else {
736 4991588 : if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
737 1069711 : pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
738 980476 : last_environment = last_environment->Copy();
739 : }
740 : }
741 3782296 : block->UpdateEnvironment(last_environment);
742 : DCHECK(pred->argument_count() >= 0);
743 3782284 : argument_count_ = pred->argument_count();
744 : } else {
745 : // We are at a state join => process phis.
746 891248 : HBasicBlock* pred = block->predecessors()->at(0);
747 : // No need to copy the environment, it cannot be used later.
748 : HEnvironment* last_environment = pred->last_environment();
749 746770 : for (int i = 0; i < block->phis()->length(); ++i) {
750 301146 : HPhi* phi = block->phis()->at(i);
751 301146 : if (phi->HasMergedIndex()) {
752 : last_environment->SetValueAt(phi->merged_index(), phi);
753 : }
754 : }
755 25 : for (int i = 0; i < block->deleted_phis()->length(); ++i) {
756 50 : if (block->deleted_phis()->at(i) < last_environment->length()) {
757 : last_environment->SetValueAt(block->deleted_phis()->at(i),
758 50 : graph_->GetConstantUndefined());
759 : }
760 : }
761 445624 : block->UpdateEnvironment(last_environment);
762 : // Pick up the outgoing argument count of one of the predecessors.
763 445624 : argument_count_ = pred->argument_count();
764 : }
765 25194533 : HInstruction* current = block->first();
766 4511674 : int start = chunk_->instructions()->length();
767 34217881 : while (current != NULL && !is_aborted()) {
768 : // Code for constants in registers is generated lazily.
769 25194598 : if (!current->EmitAtUses()) {
770 20871802 : VisitInstruction(current);
771 : }
772 : current = current->next();
773 : }
774 4511609 : int end = chunk_->instructions()->length() - 1;
775 4511609 : if (end >= start) {
776 : block->set_first_instruction_index(start);
777 : block->set_last_instruction_index(end);
778 : }
779 4511609 : block->set_argument_count(argument_count_);
780 4511609 : next_block_ = NULL;
781 4511609 : current_block_ = NULL;
782 4511609 : }
783 :
784 :
785 24422111 : void LChunkBuilder::VisitInstruction(HInstruction* current) {
786 24422111 : HInstruction* old_current = current_instruction_;
787 24422111 : current_instruction_ = current;
788 :
789 : LInstruction* instr = NULL;
790 24422111 : if (current->CanReplaceWithDummyUses()) {
791 567135 : if (current->OperandCount() == 0) {
792 4919214 : instr = DefineAsRegister(new(zone()) LDummy());
793 : } else {
794 : DCHECK(!current->OperandAt(0)->IsControlInstruction());
795 : instr = DefineAsRegister(new(zone())
796 1120747 : LDummyUse(UseAny(current->OperandAt(0))));
797 : }
798 1772936 : for (int i = 1; i < current->OperandCount(); ++i) {
799 1205804 : if (current->OperandAt(i)->IsControlInstruction()) continue;
800 : LInstruction* dummy =
801 1205784 : new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
802 : dummy->set_hydrogen_value(current);
803 1205780 : chunk_->AddInstruction(dummy, current_block_);
804 : }
805 : } else {
806 : HBasicBlock* successor;
807 52222615 : if (current->IsControlInstruction() &&
808 27184198 : HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
809 3328444 : successor != NULL) {
810 3139526 : instr = new(zone()) LGoto(successor);
811 : } else {
812 20716178 : instr = current->CompileToLithium(this);
813 : }
814 : }
815 :
816 24422378 : argument_count_ += current->argument_delta();
817 : DCHECK(argument_count_ >= 0);
818 :
819 24422179 : if (instr != NULL) {
820 18046308 : AddInstruction(instr, current);
821 : }
822 :
823 24422202 : current_instruction_ = old_current;
824 24422202 : }
825 :
826 :
827 19407399 : void LChunkBuilder::AddInstruction(LInstruction* instr,
828 : HInstruction* hydrogen_val) {
829 : // Associate the hydrogen instruction first, since we may need it for
830 : // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
831 : instr->set_hydrogen_value(hydrogen_val);
832 :
833 : #if DEBUG
834 : // Make sure that the lithium instruction has either no fixed register
835 : // constraints in temps or the result OR no uses that are only used at
836 : // start. If this invariant doesn't hold, the register allocator can decide
837 : // to insert a split of a range immediately before the instruction due to an
838 : // already allocated register needing to be used for the instruction's fixed
839 : // register constraint. In this case, The register allocator won't see an
840 : // interference between the split child and the use-at-start (it would if
841 : // the it was just a plain use), so it is free to move the split child into
842 : // the same register that is used for the use-at-start.
843 : // See https://code.google.com/p/chromium/issues/detail?id=201590
844 : if (!(instr->ClobbersRegisters() &&
845 : instr->ClobbersDoubleRegisters(isolate()))) {
846 : int fixed = 0;
847 : int used_at_start = 0;
848 : for (UseIterator it(instr); !it.Done(); it.Advance()) {
849 : LUnallocated* operand = LUnallocated::cast(it.Current());
850 : if (operand->IsUsedAtStart()) ++used_at_start;
851 : }
852 : if (instr->Output() != NULL) {
853 : if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
854 : }
855 : for (TempIterator it(instr); !it.Done(); it.Advance()) {
856 : LUnallocated* operand = LUnallocated::cast(it.Current());
857 : if (operand->HasFixedPolicy()) ++fixed;
858 : }
859 : DCHECK(fixed == 0 || used_at_start == 0);
860 : }
861 : #endif
862 :
863 19407399 : if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
864 0 : instr = AssignPointerMap(instr);
865 : }
866 19407537 : if (FLAG_stress_environments && !instr->HasEnvironment()) {
867 : instr = AssignEnvironment(instr);
868 : }
869 19407537 : chunk_->AddInstruction(instr, current_block_);
870 :
871 19407383 : CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
872 19407403 : }
873 :
874 :
875 0 : LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
876 0 : return new(zone()) LGoto(instr->FirstSuccessor());
877 : }
878 :
879 :
880 260189 : LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
881 520380 : LInstruction* result = new (zone()) LPrologue();
882 520381 : if (info_->scope()->NeedsContext()) {
883 6496 : result = MarkAsCall(result, instr);
884 : }
885 260190 : return result;
886 : }
887 :
888 :
889 0 : LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
890 0 : return new(zone()) LDebugBreak();
891 : }
892 :
893 :
894 480811 : LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
895 : HValue* value = instr->value();
896 : Representation r = value->representation();
897 : HType type = value->type();
898 : ToBooleanHints expected = instr->expected_input_types();
899 480811 : if (expected == ToBooleanHint::kNone) expected = ToBooleanHint::kAny;
900 :
901 786709 : bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
902 787343 : type.IsJSArray() || type.IsHeapNumber() || type.IsString();
903 480811 : LInstruction* branch = new(zone()) LBranch(UseRegister(value));
904 1166772 : if (!easy_case && ((!(expected & ToBooleanHint::kSmallInteger) &&
905 143758 : (expected & ToBooleanHint::kNeedsMap)) ||
906 : expected != ToBooleanHint::kAny)) {
907 : branch = AssignEnvironment(branch);
908 : }
909 480810 : return branch;
910 : }
911 :
912 :
913 19102 : LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
914 : DCHECK(instr->value()->representation().IsTagged());
915 19102 : LOperand* value = UseRegisterAtStart(instr->value());
916 38206 : return new(zone()) LCmpMapAndBranch(value);
917 : }
918 :
919 :
920 574 : LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) {
921 1148 : info()->MarkAsRequiresFrame();
922 1148 : return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value())));
923 : }
924 :
925 :
926 760 : LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
927 1520 : info()->MarkAsRequiresFrame();
928 760 : return DefineAsRegister(new(zone()) LArgumentsElements);
929 : }
930 :
931 :
932 319 : LInstruction* LChunkBuilder::DoHasInPrototypeChainAndBranch(
933 : HHasInPrototypeChainAndBranch* instr) {
934 319 : LOperand* object = UseRegister(instr->object());
935 319 : LOperand* prototype = UseRegister(instr->prototype());
936 : LHasInPrototypeChainAndBranch* result =
937 319 : new (zone()) LHasInPrototypeChainAndBranch(object, prototype);
938 319 : return AssignEnvironment(result);
939 : }
940 :
941 :
942 4495 : LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
943 4495 : LOperand* receiver = UseRegister(instr->receiver());
944 4495 : LOperand* function = UseRegisterAtStart(instr->function());
945 4495 : LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
946 8990 : return AssignEnvironment(DefineSameAsFirst(result));
947 : }
948 :
949 :
950 136 : LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
951 136 : LOperand* function = UseFixed(instr->function(), rdi);
952 136 : LOperand* receiver = UseFixed(instr->receiver(), rax);
953 136 : LOperand* length = UseFixed(instr->length(), rbx);
954 136 : LOperand* elements = UseFixed(instr->elements(), rcx);
955 136 : LApplyArguments* result = new(zone()) LApplyArguments(function,
956 : receiver,
957 : length,
958 : elements);
959 136 : return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
960 : }
961 :
962 :
963 573579 : LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
964 : int argc = instr->OperandCount();
965 1934441 : for (int i = 0; i < argc; ++i) {
966 1360866 : LOperand* argument = UseOrConstant(instr->argument(i));
967 2721729 : AddInstruction(new(zone()) LPushArgument(argument), instr);
968 : }
969 573575 : return NULL;
970 : }
971 :
972 :
973 0 : LInstruction* LChunkBuilder::DoStoreCodeEntry(
974 : HStoreCodeEntry* store_code_entry) {
975 0 : LOperand* function = UseRegister(store_code_entry->function());
976 0 : LOperand* code_object = UseTempRegister(store_code_entry->code_object());
977 0 : return new(zone()) LStoreCodeEntry(function, code_object);
978 : }
979 :
980 :
981 7160 : LInstruction* LChunkBuilder::DoInnerAllocatedObject(
982 : HInnerAllocatedObject* instr) {
983 7160 : LOperand* base_object = UseRegisterAtStart(instr->base_object());
984 7160 : LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
985 : return DefineAsRegister(
986 14320 : new(zone()) LInnerAllocatedObject(base_object, offset));
987 : }
988 :
989 :
990 26683 : LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
991 26683 : return instr->HasNoUses()
992 : ? NULL
993 48674 : : DefineAsRegister(new(zone()) LThisFunction);
994 : }
995 :
996 :
997 286091 : LInstruction* LChunkBuilder::DoContext(HContext* instr) {
998 286091 : if (instr->HasNoUses()) return NULL;
999 :
1000 548665 : if (info()->IsStub()) {
1001 23533 : return DefineFixed(new(zone()) LContext, rsi);
1002 : }
1003 :
1004 262562 : return DefineAsRegister(new(zone()) LContext);
1005 : }
1006 :
1007 :
1008 12333 : LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1009 12333 : LOperand* context = UseFixed(instr->context(), rsi);
1010 24666 : return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1011 : }
1012 :
1013 :
1014 852958 : LInstruction* LChunkBuilder::DoCallWithDescriptor(
1015 852957 : HCallWithDescriptor* instr) {
1016 : CallInterfaceDescriptor descriptor = instr->descriptor();
1017 : DCHECK_EQ(descriptor.GetParameterCount() +
1018 : LCallWithDescriptor::kImplicitRegisterParameterCount,
1019 : instr->OperandCount());
1020 :
1021 852958 : LOperand* target = UseRegisterOrConstantAtStart(instr->target());
1022 6490222 : ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1023 : // Target
1024 : ops.Add(target, zone());
1025 : // Context
1026 852957 : LOperand* op = UseFixed(instr->OperandAt(1), rsi);
1027 : ops.Add(op, zone());
1028 : // Load register parameters.
1029 : int i = 0;
1030 7861862 : for (; i < descriptor.GetRegisterParameterCount(); i++) {
1031 : op = UseFixed(instr->OperandAt(
1032 : i + LCallWithDescriptor::kImplicitRegisterParameterCount),
1033 6155942 : descriptor.GetRegisterParameter(i));
1034 : ops.Add(op, zone());
1035 : }
1036 : // Push stack parameters.
1037 853794 : for (; i < descriptor.GetParameterCount(); i++) {
1038 : op = UseAny(instr->OperandAt(
1039 834 : i + LCallWithDescriptor::kImplicitRegisterParameterCount));
1040 417 : AddInstruction(new (zone()) LPushArgument(op), instr);
1041 : }
1042 :
1043 : LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
1044 1705917 : descriptor, ops, zone());
1045 852957 : if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
1046 : result->MarkAsSyntacticTailCall();
1047 : }
1048 852957 : return MarkAsCall(DefineFixed(result, rax), instr);
1049 : }
1050 :
1051 :
1052 258595 : LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1053 129298 : LOperand* context = UseFixed(instr->context(), rsi);
1054 129299 : LOperand* function = UseFixed(instr->function(), rdi);
1055 129298 : LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1056 129297 : if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
1057 : result->MarkAsSyntacticTailCall();
1058 : }
1059 129297 : return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1060 : }
1061 :
1062 :
1063 26474 : LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1064 26474 : switch (instr->op()) {
1065 : case kMathFloor:
1066 23431 : return DoMathFloor(instr);
1067 : case kMathRound:
1068 1388 : return DoMathRound(instr);
1069 : case kMathFround:
1070 628 : return DoMathFround(instr);
1071 : case kMathAbs:
1072 384 : return DoMathAbs(instr);
1073 : case kMathCos:
1074 60 : return DoMathCos(instr);
1075 : case kMathLog:
1076 291 : return DoMathLog(instr);
1077 : case kMathExp:
1078 58 : return DoMathExp(instr);
1079 : case kMathSin:
1080 90 : return DoMathSin(instr);
1081 : case kMathSqrt:
1082 61 : return DoMathSqrt(instr);
1083 : case kMathPowHalf:
1084 41 : return DoMathPowHalf(instr);
1085 : case kMathClz32:
1086 42 : return DoMathClz32(instr);
1087 : default:
1088 0 : UNREACHABLE();
1089 : return NULL;
1090 : }
1091 : }
1092 :
1093 23431 : LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1094 : DCHECK(instr->value()->representation().IsDouble());
1095 23431 : LOperand* input = UseRegisterAtStart(instr->value());
1096 23431 : if (instr->representation().IsInteger32()) {
1097 23431 : LMathFloorI* result = new (zone()) LMathFloorI(input);
1098 37542 : return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1099 : } else {
1100 : DCHECK(instr->representation().IsDouble());
1101 : LMathFloorD* result = new (zone()) LMathFloorD(input);
1102 4661 : return DefineAsRegister(result);
1103 : }
1104 : }
1105 :
1106 1388 : LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1107 : DCHECK(instr->value()->representation().IsDouble());
1108 1388 : LOperand* input = UseRegister(instr->value());
1109 1388 : if (instr->representation().IsInteger32()) {
1110 : LOperand* temp = FixedTemp(xmm4);
1111 1388 : LMathRoundI* result = new (zone()) LMathRoundI(input, temp);
1112 1452 : return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1113 : } else {
1114 : DCHECK(instr->representation().IsDouble());
1115 : LMathRoundD* result = new (zone()) LMathRoundD(input);
1116 662 : return DefineAsRegister(result);
1117 : }
1118 : }
1119 :
1120 628 : LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1121 628 : LOperand* input = UseRegister(instr->value());
1122 628 : LMathFround* result = new (zone()) LMathFround(input);
1123 628 : return DefineAsRegister(result);
1124 : }
1125 :
1126 :
1127 384 : LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1128 384 : LOperand* context = UseAny(instr->context());
1129 384 : LOperand* input = UseRegisterAtStart(instr->value());
1130 : LInstruction* result =
1131 768 : DefineSameAsFirst(new(zone()) LMathAbs(context, input));
1132 : Representation r = instr->value()->representation();
1133 571 : if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1134 384 : if (!r.IsDouble()) result = AssignEnvironment(result);
1135 384 : return result;
1136 : }
1137 :
1138 :
1139 291 : LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) {
1140 : DCHECK(instr->representation().IsDouble());
1141 : DCHECK(instr->value()->representation().IsDouble());
1142 291 : LOperand* input = UseFixedDouble(instr->value(), xmm0);
1143 291 : return MarkAsCall(DefineFixedDouble(new (zone()) LMathLog(input), xmm0),
1144 291 : instr);
1145 : }
1146 :
1147 :
1148 42 : LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
1149 42 : LOperand* input = UseRegisterAtStart(instr->value());
1150 42 : LMathClz32* result = new(zone()) LMathClz32(input);
1151 42 : return DefineAsRegister(result);
1152 : }
1153 :
1154 60 : LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) {
1155 : DCHECK(instr->representation().IsDouble());
1156 : DCHECK(instr->value()->representation().IsDouble());
1157 60 : LOperand* input = UseFixedDouble(instr->value(), xmm0);
1158 60 : return MarkAsCall(DefineFixedDouble(new (zone()) LMathCos(input), xmm0),
1159 60 : instr);
1160 : }
1161 :
1162 58 : LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
1163 : DCHECK(instr->representation().IsDouble());
1164 : DCHECK(instr->value()->representation().IsDouble());
1165 58 : LOperand* input = UseFixedDouble(instr->value(), xmm0);
1166 58 : return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), xmm0),
1167 58 : instr);
1168 : }
1169 :
1170 90 : LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) {
1171 : DCHECK(instr->representation().IsDouble());
1172 : DCHECK(instr->value()->representation().IsDouble());
1173 90 : LOperand* input = UseFixedDouble(instr->value(), xmm0);
1174 90 : return MarkAsCall(DefineFixedDouble(new (zone()) LMathSin(input), xmm0),
1175 90 : instr);
1176 : }
1177 :
1178 61 : LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1179 61 : LOperand* input = UseAtStart(instr->value());
1180 122 : return DefineAsRegister(new(zone()) LMathSqrt(input));
1181 : }
1182 :
1183 :
1184 41 : LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
1185 41 : LOperand* input = UseRegisterAtStart(instr->value());
1186 41 : LMathPowHalf* result = new(zone()) LMathPowHalf(input);
1187 41 : return DefineSameAsFirst(result);
1188 : }
1189 :
1190 :
1191 404 : LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1192 404 : LOperand* context = UseFixed(instr->context(), rsi);
1193 404 : LOperand* constructor = UseFixed(instr->constructor(), rdi);
1194 404 : LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1195 404 : return MarkAsCall(DefineFixed(result, rax), instr);
1196 : }
1197 :
1198 :
1199 104666 : LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1200 104666 : LOperand* context = UseFixed(instr->context(), rsi);
1201 104666 : LCallRuntime* result = new(zone()) LCallRuntime(context);
1202 104667 : return MarkAsCall(DefineFixed(result, rax), instr);
1203 : }
1204 :
1205 :
1206 500 : LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1207 500 : return DoShift(Token::ROR, instr);
1208 : }
1209 :
1210 :
1211 8337 : LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1212 8337 : return DoShift(Token::SHR, instr);
1213 : }
1214 :
1215 :
1216 13535 : LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1217 13535 : return DoShift(Token::SAR, instr);
1218 : }
1219 :
1220 :
1221 16317 : LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1222 16317 : return DoShift(Token::SHL, instr);
1223 : }
1224 :
1225 :
1226 98920 : LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1227 94392 : if (instr->representation().IsSmiOrInteger32()) {
1228 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1229 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1230 : DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
1231 :
1232 179728 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1233 : LOperand* right;
1234 89864 : if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
1235 : // We don't support tagged immediates, so we request it in a register.
1236 892 : right = UseRegisterAtStart(instr->BetterRightOperand());
1237 : } else {
1238 88972 : right = UseOrConstantAtStart(instr->BetterRightOperand());
1239 : }
1240 179728 : return DefineSameAsFirst(new(zone()) LBitI(left, right));
1241 : } else {
1242 4528 : return DoArithmeticT(instr->op(), instr);
1243 : }
1244 : }
1245 :
1246 :
1247 564 : LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
1248 : DCHECK(instr->representation().IsSmiOrInteger32());
1249 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1250 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1251 564 : LOperand* dividend = UseRegister(instr->left());
1252 564 : int32_t divisor = instr->right()->GetInteger32Constant();
1253 564 : LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
1254 564 : dividend, divisor));
1255 1747 : if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1256 1116 : (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1257 : (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1258 124 : divisor != 1 && divisor != -1)) {
1259 : result = AssignEnvironment(result);
1260 : }
1261 564 : return result;
1262 : }
1263 :
1264 :
1265 1497 : LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
1266 : DCHECK(instr->representation().IsInteger32());
1267 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1268 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1269 1497 : LOperand* dividend = UseRegister(instr->left());
1270 1497 : int32_t divisor = instr->right()->GetInteger32Constant();
1271 : LOperand* temp1 = FixedTemp(rax);
1272 : LOperand* temp2 = FixedTemp(rdx);
1273 1497 : LInstruction* result = DefineFixed(new(zone()) LDivByConstI(
1274 1497 : dividend, divisor, temp1, temp2), rdx);
1275 2994 : if (divisor == 0 ||
1276 3003 : (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1277 : !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1278 : result = AssignEnvironment(result);
1279 : }
1280 1497 : return result;
1281 : }
1282 :
1283 :
1284 453 : LInstruction* LChunkBuilder::DoDivI(HDiv* instr) {
1285 : DCHECK(instr->representation().IsSmiOrInteger32());
1286 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1287 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1288 453 : LOperand* dividend = UseFixed(instr->left(), rax);
1289 453 : LOperand* divisor = UseRegister(instr->right());
1290 : LOperand* temp = FixedTemp(rdx);
1291 453 : LInstruction* result = DefineFixed(new(zone()) LDivI(
1292 453 : dividend, divisor, temp), rax);
1293 910 : if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1294 4 : instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1295 457 : instr->CheckFlag(HValue::kCanOverflow) ||
1296 : !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1297 : result = AssignEnvironment(result);
1298 : }
1299 453 : return result;
1300 : }
1301 :
1302 :
1303 39439 : LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1304 39439 : if (instr->representation().IsSmiOrInteger32()) {
1305 2514 : if (instr->RightIsPowerOf2()) {
1306 564 : return DoDivByPowerOf2I(instr);
1307 1950 : } else if (instr->right()->IsConstant()) {
1308 1497 : return DoDivByConstI(instr);
1309 : } else {
1310 453 : return DoDivI(instr);
1311 : }
1312 36925 : } else if (instr->representation().IsDouble()) {
1313 19122 : return DoArithmeticD(Token::DIV, instr);
1314 : } else {
1315 17803 : return DoArithmeticT(Token::DIV, instr);
1316 : }
1317 : }
1318 :
1319 :
1320 519 : LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1321 519 : LOperand* dividend = UseRegisterAtStart(instr->left());
1322 519 : int32_t divisor = instr->right()->GetInteger32Constant();
1323 519 : LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
1324 519 : dividend, divisor));
1325 1803 : if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1326 246 : (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1327 : result = AssignEnvironment(result);
1328 : }
1329 519 : return result;
1330 : }
1331 :
1332 :
1333 2010 : LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
1334 : DCHECK(instr->representation().IsInteger32());
1335 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1336 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1337 2010 : LOperand* dividend = UseRegister(instr->left());
1338 2010 : int32_t divisor = instr->right()->GetInteger32Constant();
1339 : LOperand* temp1 = FixedTemp(rax);
1340 : LOperand* temp2 = FixedTemp(rdx);
1341 : LOperand* temp3 =
1342 4035 : ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1343 987 : (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
1344 4020 : NULL : TempRegister();
1345 : LInstruction* result =
1346 2010 : DefineFixed(new(zone()) LFlooringDivByConstI(dividend,
1347 : divisor,
1348 : temp1,
1349 : temp2,
1350 : temp3),
1351 2010 : rdx);
1352 6023 : if (divisor == 0 ||
1353 2002 : (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1354 : result = AssignEnvironment(result);
1355 : }
1356 2010 : return result;
1357 : }
1358 :
1359 :
1360 71 : LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
1361 : DCHECK(instr->representation().IsSmiOrInteger32());
1362 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1363 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1364 71 : LOperand* dividend = UseFixed(instr->left(), rax);
1365 71 : LOperand* divisor = UseRegister(instr->right());
1366 : LOperand* temp = FixedTemp(rdx);
1367 71 : LInstruction* result = DefineFixed(new(zone()) LFlooringDivI(
1368 71 : dividend, divisor, temp), rax);
1369 148 : if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1370 77 : instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1371 : instr->CheckFlag(HValue::kCanOverflow)) {
1372 : result = AssignEnvironment(result);
1373 : }
1374 71 : return result;
1375 : }
1376 :
1377 :
1378 2600 : LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1379 2600 : if (instr->RightIsPowerOf2()) {
1380 519 : return DoFlooringDivByPowerOf2I(instr);
1381 2081 : } else if (instr->right()->IsConstant()) {
1382 2010 : return DoFlooringDivByConstI(instr);
1383 : } else {
1384 71 : return DoFlooringDivI(instr);
1385 : }
1386 : }
1387 :
1388 :
1389 1083 : LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
1390 : DCHECK(instr->representation().IsSmiOrInteger32());
1391 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1392 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1393 1083 : LOperand* dividend = UseRegisterAtStart(instr->left());
1394 1083 : int32_t divisor = instr->right()->GetInteger32Constant();
1395 1083 : LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
1396 1083 : dividend, divisor));
1397 3225 : if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1398 : instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1399 : result = AssignEnvironment(result);
1400 : }
1401 1083 : return result;
1402 : }
1403 :
1404 :
1405 1623 : LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
1406 : DCHECK(instr->representation().IsSmiOrInteger32());
1407 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1408 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1409 1623 : LOperand* dividend = UseRegister(instr->left());
1410 1623 : int32_t divisor = instr->right()->GetInteger32Constant();
1411 : LOperand* temp1 = FixedTemp(rax);
1412 : LOperand* temp2 = FixedTemp(rdx);
1413 1623 : LInstruction* result = DefineFixed(new(zone()) LModByConstI(
1414 1623 : dividend, divisor, temp1, temp2), rax);
1415 3245 : if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1416 : result = AssignEnvironment(result);
1417 : }
1418 1623 : return result;
1419 : }
1420 :
1421 :
1422 403 : LInstruction* LChunkBuilder::DoModI(HMod* instr) {
1423 : DCHECK(instr->representation().IsSmiOrInteger32());
1424 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1425 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1426 403 : LOperand* dividend = UseFixed(instr->left(), rax);
1427 403 : LOperand* divisor = UseRegister(instr->right());
1428 : LOperand* temp = FixedTemp(rdx);
1429 403 : LInstruction* result = DefineFixed(new(zone()) LModI(
1430 403 : dividend, divisor, temp), rdx);
1431 814 : if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1432 : instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1433 : result = AssignEnvironment(result);
1434 : }
1435 403 : return result;
1436 : }
1437 :
1438 :
1439 5399 : LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1440 5399 : if (instr->representation().IsSmiOrInteger32()) {
1441 3109 : if (instr->RightIsPowerOf2()) {
1442 1083 : return DoModByPowerOf2I(instr);
1443 2026 : } else if (instr->right()->IsConstant()) {
1444 1623 : return DoModByConstI(instr);
1445 : } else {
1446 403 : return DoModI(instr);
1447 : }
1448 2290 : } else if (instr->representation().IsDouble()) {
1449 2225 : return DoArithmeticD(Token::MOD, instr);
1450 : } else {
1451 65 : return DoArithmeticT(Token::MOD, instr);
1452 : }
1453 : }
1454 :
1455 :
1456 22914 : LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1457 30536 : if (instr->representation().IsSmiOrInteger32()) {
1458 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1459 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1460 15244 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1461 : HValue* h_right = instr->BetterRightOperand();
1462 7622 : LOperand* right = UseOrConstant(h_right);
1463 7622 : LMulI* mul = new(zone()) LMulI(left, right);
1464 : int constant_value =
1465 7622 : h_right->IsConstant() ? HConstant::cast(h_right)->Integer32Value() : 0;
1466 : // |needs_environment| must mirror the cases where LCodeGen::DoMulI calls
1467 : // |DeoptimizeIf|.
1468 : bool needs_environment =
1469 8402 : instr->CheckFlag(HValue::kCanOverflow) ||
1470 76 : (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
1471 29 : (!right->IsConstantOperand() || constant_value <= 0));
1472 7622 : if (needs_environment) {
1473 : AssignEnvironment(mul);
1474 : }
1475 7622 : return DefineSameAsFirst(mul);
1476 15292 : } else if (instr->representation().IsDouble()) {
1477 13180 : return DoArithmeticD(Token::MUL, instr);
1478 : } else {
1479 2112 : return DoArithmeticT(Token::MUL, instr);
1480 : }
1481 : }
1482 :
1483 :
1484 23579 : LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1485 37119 : if (instr->representation().IsSmiOrInteger32()) {
1486 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1487 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1488 13540 : LOperand* left = UseRegisterAtStart(instr->left());
1489 : LOperand* right;
1490 13540 : if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
1491 : // We don't support tagged immediates, so we request it in a register.
1492 289 : right = UseRegisterAtStart(instr->right());
1493 : } else {
1494 13251 : right = UseOrConstantAtStart(instr->right());
1495 : }
1496 13540 : LSubI* sub = new(zone()) LSubI(left, right);
1497 13540 : LInstruction* result = DefineSameAsFirst(sub);
1498 13540 : if (instr->CheckFlag(HValue::kCanOverflow)) {
1499 : result = AssignEnvironment(result);
1500 : }
1501 13540 : return result;
1502 10039 : } else if (instr->representation().IsDouble()) {
1503 3104 : return DoArithmeticD(Token::SUB, instr);
1504 : } else {
1505 6935 : return DoArithmeticT(Token::SUB, instr);
1506 : }
1507 : }
1508 :
1509 :
1510 209057 : LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1511 355325 : if (instr->representation().IsSmiOrInteger32()) {
1512 : // Check to see if it would be advantageous to use an lea instruction rather
1513 : // than an add. This is the case when no overflow check is needed and there
1514 : // are multiple uses of the add's inputs, so using a 3-register add will
1515 : // preserve all input values for later uses.
1516 146268 : bool use_lea = LAddI::UseLea(instr);
1517 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1518 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1519 292536 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1520 : HValue* right_candidate = instr->BetterRightOperand();
1521 : LOperand* right;
1522 146268 : if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
1523 : // We cannot add a tagged immediate to a tagged value,
1524 : // so we request it in a register.
1525 714 : right = UseRegisterAtStart(right_candidate);
1526 : } else {
1527 : right = use_lea ? UseRegisterOrConstantAtStart(right_candidate)
1528 145554 : : UseOrConstantAtStart(right_candidate);
1529 : }
1530 148546 : LAddI* add = new(zone()) LAddI(left, right);
1531 : bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1532 : LInstruction* result = use_lea ? DefineAsRegister(add)
1533 146268 : : DefineSameAsFirst(add);
1534 146268 : if (can_overflow) {
1535 : result = AssignEnvironment(result);
1536 : }
1537 146268 : return result;
1538 62789 : } else if (instr->representation().IsExternal()) {
1539 : DCHECK(instr->IsConsistentExternalRepresentation());
1540 : DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1541 2278 : bool use_lea = LAddI::UseLea(instr);
1542 2278 : LOperand* left = UseRegisterAtStart(instr->left());
1543 : HValue* right_candidate = instr->right();
1544 : LOperand* right = use_lea
1545 : ? UseRegisterOrConstantAtStart(right_candidate)
1546 2278 : : UseOrConstantAtStart(right_candidate);
1547 : LAddI* add = new(zone()) LAddI(left, right);
1548 : LInstruction* result = use_lea
1549 : ? DefineAsRegister(add)
1550 2278 : : DefineSameAsFirst(add);
1551 2278 : return result;
1552 60511 : } else if (instr->representation().IsDouble()) {
1553 46169 : return DoArithmeticD(Token::ADD, instr);
1554 : } else {
1555 14342 : return DoArithmeticT(Token::ADD, instr);
1556 : }
1557 : return NULL;
1558 : }
1559 :
1560 :
1561 1582 : LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
1562 : LOperand* left = NULL;
1563 : LOperand* right = NULL;
1564 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1565 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1566 1582 : if (instr->representation().IsSmi()) {
1567 0 : left = UseRegisterAtStart(instr->BetterLeftOperand());
1568 0 : right = UseAtStart(instr->BetterRightOperand());
1569 1582 : } else if (instr->representation().IsInteger32()) {
1570 426 : left = UseRegisterAtStart(instr->BetterLeftOperand());
1571 213 : right = UseOrConstantAtStart(instr->BetterRightOperand());
1572 : } else {
1573 : DCHECK(instr->representation().IsDouble());
1574 1369 : left = UseRegisterAtStart(instr->left());
1575 1368 : right = UseRegisterAtStart(instr->right());
1576 : }
1577 1581 : LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
1578 1581 : return DefineSameAsFirst(minmax);
1579 : }
1580 :
1581 :
1582 827 : LInstruction* LChunkBuilder::DoPower(HPower* instr) {
1583 : DCHECK(instr->representation().IsDouble());
1584 : // We call a C function for double power. It can't trigger a GC.
1585 : // We need to use fixed result register for the call.
1586 : Representation exponent_type = instr->right()->representation();
1587 : DCHECK(instr->left()->representation().IsDouble());
1588 827 : LOperand* left = UseFixedDouble(instr->left(), xmm2);
1589 : LOperand* right =
1590 : exponent_type.IsDouble()
1591 : ? UseFixedDouble(instr->right(), xmm1)
1592 1654 : : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1593 827 : LPower* result = new(zone()) LPower(left, right);
1594 : return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1595 827 : CAN_DEOPTIMIZE_EAGERLY);
1596 : }
1597 :
1598 :
1599 201241 : LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1600 : DCHECK(instr->left()->representation().IsTagged());
1601 : DCHECK(instr->right()->representation().IsTagged());
1602 201241 : LOperand* context = UseFixed(instr->context(), rsi);
1603 201242 : LOperand* left = UseFixed(instr->left(), rdx);
1604 201242 : LOperand* right = UseFixed(instr->right(), rax);
1605 201242 : LCmpT* result = new(zone()) LCmpT(context, left, right);
1606 201242 : return MarkAsCall(DefineFixed(result, rax), instr);
1607 : }
1608 :
1609 :
1610 166019 : LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1611 : HCompareNumericAndBranch* instr) {
1612 : Representation r = instr->representation();
1613 166019 : if (r.IsSmiOrInteger32()) {
1614 : DCHECK(instr->left()->representation().Equals(r));
1615 : DCHECK(instr->right()->representation().Equals(r));
1616 148216 : LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1617 148216 : LOperand* right = UseOrConstantAtStart(instr->right());
1618 314234 : return new(zone()) LCompareNumericAndBranch(left, right);
1619 : } else {
1620 : DCHECK(r.IsDouble());
1621 : DCHECK(instr->left()->representation().IsDouble());
1622 : DCHECK(instr->right()->representation().IsDouble());
1623 : LOperand* left;
1624 : LOperand* right;
1625 19776 : if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1626 1731 : left = UseRegisterOrConstantAtStart(instr->left());
1627 1731 : right = UseRegisterOrConstantAtStart(instr->right());
1628 : } else {
1629 16072 : left = UseRegisterAtStart(instr->left());
1630 16072 : right = UseRegisterAtStart(instr->right());
1631 : }
1632 17803 : return new(zone()) LCompareNumericAndBranch(left, right);
1633 : }
1634 : }
1635 :
1636 :
1637 43374 : LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1638 : HCompareObjectEqAndBranch* instr) {
1639 43374 : LOperand* left = UseRegisterAtStart(instr->left());
1640 43374 : LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1641 86748 : return new(zone()) LCmpObjectEqAndBranch(left, right);
1642 : }
1643 :
1644 :
1645 33 : LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
1646 : HCompareHoleAndBranch* instr) {
1647 33 : LOperand* value = UseRegisterAtStart(instr->value());
1648 66 : return new(zone()) LCmpHoleAndBranch(value);
1649 : }
1650 :
1651 :
1652 446 : LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
1653 : DCHECK(instr->value()->representation().IsTagged());
1654 446 : LOperand* value = UseRegisterAtStart(instr->value());
1655 446 : LOperand* temp = TempRegister();
1656 892 : return new(zone()) LIsStringAndBranch(value, temp);
1657 : }
1658 :
1659 :
1660 9194 : LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1661 : DCHECK(instr->value()->representation().IsTagged());
1662 18388 : return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1663 : }
1664 :
1665 :
1666 1257 : LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1667 : HIsUndetectableAndBranch* instr) {
1668 : DCHECK(instr->value()->representation().IsTagged());
1669 1257 : LOperand* value = UseRegisterAtStart(instr->value());
1670 1257 : LOperand* temp = TempRegister();
1671 2514 : return new(zone()) LIsUndetectableAndBranch(value, temp);
1672 : }
1673 :
1674 :
1675 15235 : LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1676 : HStringCompareAndBranch* instr) {
1677 :
1678 : DCHECK(instr->left()->representation().IsTagged());
1679 : DCHECK(instr->right()->representation().IsTagged());
1680 15235 : LOperand* context = UseFixed(instr->context(), rsi);
1681 15235 : LOperand* left = UseFixed(instr->left(), rdx);
1682 15235 : LOperand* right = UseFixed(instr->right(), rax);
1683 : LStringCompareAndBranch* result =
1684 15235 : new(zone()) LStringCompareAndBranch(context, left, right);
1685 :
1686 15235 : return MarkAsCall(result, instr);
1687 : }
1688 :
1689 :
1690 1966 : LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1691 : HHasInstanceTypeAndBranch* instr) {
1692 : DCHECK(instr->value()->representation().IsTagged());
1693 1966 : LOperand* value = UseRegisterAtStart(instr->value());
1694 3932 : return new(zone()) LHasInstanceTypeAndBranch(value);
1695 : }
1696 :
1697 7697 : LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1698 : HClassOfTestAndBranch* instr) {
1699 7697 : LOperand* value = UseRegister(instr->value());
1700 7697 : return new (zone())
1701 15394 : LClassOfTestAndBranch(value, TempRegister(), TempRegister());
1702 : }
1703 :
1704 14320 : LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1705 14320 : LOperand* string = UseRegisterAtStart(instr->string());
1706 14320 : LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1707 28640 : return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
1708 : }
1709 :
1710 :
1711 14320 : LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1712 14320 : LOperand* string = UseRegisterAtStart(instr->string());
1713 : LOperand* index = FLAG_debug_code
1714 : ? UseRegisterAtStart(instr->index())
1715 28640 : : UseRegisterOrConstantAtStart(instr->index());
1716 : LOperand* value = FLAG_debug_code
1717 : ? UseRegisterAtStart(instr->value())
1718 28640 : : UseRegisterOrConstantAtStart(instr->value());
1719 14320 : LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), rsi) : NULL;
1720 14320 : LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
1721 : index, value);
1722 14320 : if (FLAG_debug_code) {
1723 0 : result = MarkAsCall(result, instr);
1724 : }
1725 14320 : return result;
1726 : }
1727 :
1728 :
1729 63566 : LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1730 63555 : if (!FLAG_debug_code && instr->skip_check()) return NULL;
1731 31784 : LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1732 : LOperand* length = !index->IsConstantOperand()
1733 : ? UseOrConstantAtStart(instr->length())
1734 63570 : : UseAtStart(instr->length());
1735 31785 : LInstruction* result = new(zone()) LBoundsCheck(index, length);
1736 31795 : if (!FLAG_debug_code || !instr->skip_check()) {
1737 : result = AssignEnvironment(result);
1738 : }
1739 31785 : return result;
1740 : }
1741 :
1742 :
1743 15675 : LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
1744 : // The control instruction marking the end of a block that completed
1745 : // abruptly (e.g., threw an exception). There is nothing specific to do.
1746 15675 : return NULL;
1747 : }
1748 :
1749 :
1750 0 : LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
1751 0 : return NULL;
1752 : }
1753 :
1754 :
1755 0 : LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) {
1756 : // All HForceRepresentation instructions should be eliminated in the
1757 : // representation change phase of Hydrogen.
1758 0 : UNREACHABLE();
1759 : return NULL;
1760 : }
1761 :
1762 :
1763 343178 : LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1764 : Representation from = instr->from();
1765 : Representation to = instr->to();
1766 23910 : HValue* val = instr->value();
1767 343178 : if (from.IsSmi()) {
1768 12166 : if (to.IsTagged()) {
1769 5603 : LOperand* value = UseRegister(val);
1770 525197 : return DefineSameAsFirst(new(zone()) LDummyUse(value));
1771 : }
1772 : from = Representation::Tagged();
1773 : }
1774 337575 : if (from.IsTagged()) {
1775 152096 : if (to.IsDouble()) {
1776 54126 : LOperand* value = UseRegister(val);
1777 54125 : LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
1778 54126 : if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1779 54127 : return result;
1780 97970 : } else if (to.IsSmi()) {
1781 21979 : LOperand* value = UseRegister(val);
1782 21979 : if (val->type().IsSmi()) {
1783 0 : return DefineSameAsFirst(new(zone()) LDummyUse(value));
1784 : }
1785 43958 : return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1786 : } else {
1787 : DCHECK(to.IsInteger32());
1788 75991 : if (val->type().IsSmi() || val->representation().IsSmi()) {
1789 4422 : LOperand* value = UseRegister(val);
1790 4422 : return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
1791 : } else {
1792 71569 : LOperand* value = UseRegister(val);
1793 : bool truncating = instr->CanTruncateToInt32();
1794 71569 : LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
1795 : LInstruction* result =
1796 71568 : DefineSameAsFirst(new(zone()) LTaggedToI(value, xmm_temp));
1797 71568 : if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1798 71568 : return result;
1799 : }
1800 : }
1801 185479 : } else if (from.IsDouble()) {
1802 36067 : if (to.IsTagged()) {
1803 : info()->MarkAsDeferredCalling();
1804 27005 : LOperand* value = UseRegister(val);
1805 27005 : LOperand* temp = TempRegister();
1806 27005 : LUnallocated* result_temp = TempRegister();
1807 : LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1808 27005 : return AssignPointerMap(Define(result, result_temp));
1809 9062 : } else if (to.IsSmi()) {
1810 82 : LOperand* value = UseRegister(val);
1811 : return AssignEnvironment(
1812 164 : DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1813 : } else {
1814 : DCHECK(to.IsInteger32());
1815 8980 : LOperand* value = UseRegister(val);
1816 8980 : LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
1817 8980 : if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1818 8980 : return result;
1819 : }
1820 149412 : } else if (from.IsInteger32()) {
1821 : info()->MarkAsDeferredCalling();
1822 149412 : if (to.IsTagged()) {
1823 219077 : if (!instr->CheckFlag(HValue::kCanOverflow)) {
1824 92023 : LOperand* value = UseRegister(val);
1825 92024 : return DefineAsRegister(new(zone()) LSmiTag(value));
1826 776 : } else if (val->CheckFlag(HInstruction::kUint32)) {
1827 776 : LOperand* value = UseRegister(val);
1828 776 : LOperand* temp1 = TempRegister();
1829 : LOperand* temp2 = FixedTemp(xmm1);
1830 : LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
1831 776 : return AssignPointerMap(DefineSameAsFirst(result));
1832 : } else {
1833 0 : LOperand* value = UseRegister(val);
1834 : LOperand* temp1 = SmiValuesAre32Bits() ? NULL : TempRegister();
1835 : LOperand* temp2 = SmiValuesAre32Bits() ? NULL : FixedTemp(xmm1);
1836 : LNumberTagI* result = new(zone()) LNumberTagI(value, temp1, temp2);
1837 0 : return AssignPointerMap(DefineSameAsFirst(result));
1838 : }
1839 56613 : } else if (to.IsSmi()) {
1840 33479 : LOperand* value = UseRegister(val);
1841 33479 : LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
1842 33479 : if (instr->CheckFlag(HValue::kCanOverflow)) {
1843 : result = AssignEnvironment(result);
1844 : }
1845 33479 : return result;
1846 : } else {
1847 : DCHECK(to.IsDouble());
1848 23134 : if (val->CheckFlag(HInstruction::kUint32)) {
1849 1300 : return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1850 : } else {
1851 22484 : LOperand* value = Use(val);
1852 22484 : return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
1853 : }
1854 : }
1855 : }
1856 0 : UNREACHABLE();
1857 : return NULL;
1858 : }
1859 :
1860 :
1861 91629 : LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1862 91629 : LOperand* value = UseRegisterAtStart(instr->value());
1863 91631 : LInstruction* result = new(zone()) LCheckNonSmi(value);
1864 91628 : if (!instr->value()->type().IsHeapObject()) {
1865 : result = AssignEnvironment(result);
1866 : }
1867 91631 : return result;
1868 : }
1869 :
1870 :
1871 0 : LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
1872 0 : LOperand* value = UseRegisterAtStart(instr->value());
1873 0 : return AssignEnvironment(new(zone()) LCheckSmi(value));
1874 : }
1875 :
1876 :
1877 2361 : LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1878 : HCheckArrayBufferNotNeutered* instr) {
1879 2361 : LOperand* view = UseRegisterAtStart(instr->value());
1880 : LCheckArrayBufferNotNeutered* result =
1881 2361 : new (zone()) LCheckArrayBufferNotNeutered(view);
1882 2361 : return AssignEnvironment(result);
1883 : }
1884 :
1885 :
1886 43198 : LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1887 43198 : LOperand* value = UseRegisterAtStart(instr->value());
1888 43198 : LCheckInstanceType* result = new(zone()) LCheckInstanceType(value);
1889 43197 : return AssignEnvironment(result);
1890 : }
1891 :
1892 :
1893 36259 : LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1894 36259 : LOperand* value = UseRegisterAtStart(instr->value());
1895 72518 : return AssignEnvironment(new(zone()) LCheckValue(value));
1896 : }
1897 :
1898 :
1899 271458 : LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1900 392543 : if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
1901 75963 : LOperand* value = UseRegisterAtStart(instr->value());
1902 : LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
1903 75966 : if (instr->HasMigrationTarget()) {
1904 : info()->MarkAsDeferredCalling();
1905 1557 : result = AssignPointerMap(result);
1906 : }
1907 75966 : return result;
1908 : }
1909 :
1910 :
1911 328 : LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
1912 : HValue* value = instr->value();
1913 : Representation input_rep = value->representation();
1914 328 : LOperand* reg = UseRegister(value);
1915 328 : if (input_rep.IsDouble()) {
1916 551 : return DefineAsRegister(new(zone()) LClampDToUint8(reg));
1917 105 : } else if (input_rep.IsInteger32()) {
1918 84 : return DefineSameAsFirst(new(zone()) LClampIToUint8(reg));
1919 : } else {
1920 : DCHECK(input_rep.IsSmiOrTagged());
1921 : // Register allocator doesn't (yet) support allocation of double
1922 : // temps. Reserve xmm1 explicitly.
1923 : LClampTToUint8* result = new(zone()) LClampTToUint8(reg,
1924 : FixedTemp(xmm1));
1925 42 : return AssignEnvironment(DefineSameAsFirst(result));
1926 : }
1927 : }
1928 :
1929 :
1930 365862 : LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1931 769016 : LOperand* context = info()->IsStub() ? UseFixed(instr->context(), rsi) : NULL;
1932 365861 : LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1933 : return new(zone()) LReturn(
1934 731726 : UseFixed(instr->value(), rax), context, parameter_count);
1935 : }
1936 :
1937 :
1938 3597215 : LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1939 : Representation r = instr->representation();
1940 3597215 : if (r.IsSmi()) {
1941 4011772 : return DefineAsRegister(new(zone()) LConstantS);
1942 3182658 : } else if (r.IsInteger32()) {
1943 510638 : return DefineAsRegister(new(zone()) LConstantI);
1944 2672020 : } else if (r.IsDouble()) {
1945 43739 : return DefineAsRegister(new (zone()) LConstantD);
1946 2628281 : } else if (r.IsExternal()) {
1947 8083 : return DefineAsRegister(new(zone()) LConstantE);
1948 2620198 : } else if (r.IsTagged()) {
1949 2620194 : return DefineAsRegister(new(zone()) LConstantT);
1950 : } else {
1951 0 : UNREACHABLE();
1952 : return NULL;
1953 : }
1954 : }
1955 :
1956 :
1957 609214 : LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1958 304607 : LOperand* context = UseRegisterAtStart(instr->value());
1959 : LInstruction* result =
1960 609214 : DefineAsRegister(new(zone()) LLoadContextSlot(context));
1961 304607 : if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1962 : result = AssignEnvironment(result);
1963 : }
1964 304607 : return result;
1965 : }
1966 :
1967 :
1968 140342 : LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1969 : LOperand* context;
1970 : LOperand* value;
1971 : LOperand* temp;
1972 70171 : context = UseRegister(instr->context());
1973 70171 : if (instr->NeedsWriteBarrier()) {
1974 38613 : value = UseTempRegister(instr->value());
1975 38613 : temp = TempRegister();
1976 : } else {
1977 31558 : value = UseRegister(instr->value());
1978 : temp = NULL;
1979 : }
1980 70171 : LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
1981 70171 : if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1982 : result = AssignEnvironment(result);
1983 : }
1984 70171 : return result;
1985 : }
1986 :
1987 :
1988 246759 : LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
1989 : // Use the special mov rax, moffs64 encoding for external
1990 : // memory accesses with 64-bit word-sized values.
1991 246759 : if (instr->access().IsExternalMemory() &&
1992 493518 : instr->access().offset() == 0 &&
1993 246759 : (instr->access().representation().IsSmi() ||
1994 246759 : instr->access().representation().IsTagged() ||
1995 246759 : instr->access().representation().IsHeapObject() ||
1996 246759 : instr->access().representation().IsExternal())) {
1997 0 : LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
1998 246759 : return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
1999 : }
2000 246759 : LOperand* obj = UseRegisterAtStart(instr->object());
2001 246761 : return DefineAsRegister(new(zone()) LLoadNamedField(obj));
2002 : }
2003 :
2004 :
2005 5770 : LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
2006 : HLoadFunctionPrototype* instr) {
2007 : return AssignEnvironment(DefineAsRegister(
2008 17310 : new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()))));
2009 : }
2010 :
2011 :
2012 5298 : LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2013 10596 : return DefineAsRegister(new(zone()) LLoadRoot);
2014 : }
2015 :
2016 :
2017 25000 : void LChunkBuilder::FindDehoistedKeyDefinitions(HValue* candidate) {
2018 : // We sign extend the dehoisted key at the definition point when the pointer
2019 : // size is 64-bit. For x32 port, we sign extend the dehoisted key at the use
2020 : // points and should not invoke this function. We can't use STATIC_ASSERT
2021 : // here as the pointer size is 32-bit for x32.
2022 : DCHECK(kPointerSize == kInt64Size);
2023 25000 : BitVector* dehoisted_key_ids = chunk_->GetDehoistedKeyIds();
2024 12500 : if (dehoisted_key_ids->Contains(candidate->id())) return;
2025 : dehoisted_key_ids->Add(candidate->id());
2026 10782 : if (!candidate->IsPhi()) return;
2027 3394 : for (int i = 0; i < candidate->OperandCount(); ++i) {
2028 3394 : FindDehoistedKeyDefinitions(candidate->OperandAt(i));
2029 : }
2030 : }
2031 :
2032 :
2033 197987 : LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
2034 : DCHECK((kPointerSize == kInt64Size &&
2035 : instr->key()->representation().IsInteger32()) ||
2036 : (kPointerSize == kInt32Size &&
2037 : instr->key()->representation().IsSmiOrInteger32()));
2038 : ElementsKind elements_kind = instr->elements_kind();
2039 : LOperand* key = NULL;
2040 : LInstruction* result = NULL;
2041 :
2042 : if (kPointerSize == kInt64Size) {
2043 50531 : key = UseRegisterOrConstantAtStart(instr->key());
2044 : } else {
2045 : bool clobbers_key = ExternalArrayOpRequiresTemp(
2046 : instr->key()->representation(), elements_kind);
2047 : key = clobbers_key
2048 : ? UseTempRegister(instr->key())
2049 : : UseRegisterOrConstantAtStart(instr->key());
2050 : }
2051 :
2052 50531 : if ((kPointerSize == kInt64Size) && instr->IsDehoisted()) {
2053 7912 : FindDehoistedKeyDefinitions(instr->key());
2054 : }
2055 :
2056 50531 : if (!instr->is_fixed_typed_array()) {
2057 48504 : LOperand* obj = UseRegisterAtStart(instr->elements());
2058 101984 : result = DefineAsRegister(new (zone()) LLoadKeyed(obj, key, nullptr));
2059 : } else {
2060 : DCHECK(
2061 : (instr->representation().IsInteger32() &&
2062 : !(IsDoubleOrFloatElementsKind(elements_kind))) ||
2063 : (instr->representation().IsDouble() &&
2064 : (IsDoubleOrFloatElementsKind(elements_kind))));
2065 2027 : LOperand* backing_store = UseRegister(instr->elements());
2066 2027 : LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2067 : result = DefineAsRegister(
2068 2027 : new (zone()) LLoadKeyed(backing_store, key, backing_store_owner));
2069 : }
2070 :
2071 : bool needs_environment;
2072 50530 : if (instr->is_fixed_typed_array()) {
2073 : // see LCodeGen::DoLoadKeyedExternalArray
2074 2232 : needs_environment = elements_kind == UINT32_ELEMENTS &&
2075 205 : !instr->CheckFlag(HInstruction::kUint32);
2076 : } else {
2077 : // see LCodeGen::DoLoadKeyedFixedDoubleArray and
2078 : // LCodeGen::DoLoadKeyedFixedArray
2079 : needs_environment =
2080 94898 : instr->RequiresHoleCheck() ||
2081 2950 : (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
2082 : }
2083 :
2084 50531 : if (needs_environment) {
2085 : result = AssignEnvironment(result);
2086 : }
2087 50531 : return result;
2088 : }
2089 :
2090 :
2091 55906 : LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2092 : ElementsKind elements_kind = instr->elements_kind();
2093 :
2094 27953 : if ((kPointerSize == kInt64Size) && instr->IsDehoisted()) {
2095 1194 : FindDehoistedKeyDefinitions(instr->key());
2096 : }
2097 :
2098 27953 : if (!instr->is_fixed_typed_array()) {
2099 : DCHECK(instr->elements()->representation().IsTagged());
2100 26158 : bool needs_write_barrier = instr->NeedsWriteBarrier();
2101 : LOperand* object = NULL;
2102 : LOperand* key = NULL;
2103 : LOperand* val = NULL;
2104 :
2105 : Representation value_representation = instr->value()->representation();
2106 26158 : if (value_representation.IsDouble()) {
2107 5967 : object = UseRegisterAtStart(instr->elements());
2108 5967 : val = UseRegisterAtStart(instr->value());
2109 5967 : key = UseRegisterOrConstantAtStart(instr->key());
2110 : } else {
2111 : DCHECK(value_representation.IsSmiOrTagged() ||
2112 : value_representation.IsInteger32());
2113 20191 : if (needs_write_barrier) {
2114 6616 : object = UseTempRegister(instr->elements());
2115 6616 : val = UseTempRegister(instr->value());
2116 6616 : key = UseTempRegister(instr->key());
2117 : } else {
2118 13575 : object = UseRegisterAtStart(instr->elements());
2119 13575 : val = UseRegisterOrConstantAtStart(instr->value());
2120 13575 : key = UseRegisterOrConstantAtStart(instr->key());
2121 : }
2122 : }
2123 :
2124 27953 : return new (zone()) LStoreKeyed(object, key, val, nullptr);
2125 : }
2126 :
2127 : DCHECK(
2128 : (instr->value()->representation().IsInteger32() &&
2129 : !IsDoubleOrFloatElementsKind(elements_kind)) ||
2130 : (instr->value()->representation().IsDouble() &&
2131 : IsDoubleOrFloatElementsKind(elements_kind)));
2132 : DCHECK(instr->elements()->representation().IsExternal());
2133 1795 : bool val_is_temp_register = elements_kind == UINT8_CLAMPED_ELEMENTS ||
2134 1795 : elements_kind == FLOAT32_ELEMENTS;
2135 : LOperand* val = val_is_temp_register ? UseTempRegister(instr->value())
2136 3590 : : UseRegister(instr->value());
2137 : LOperand* key = NULL;
2138 : if (kPointerSize == kInt64Size) {
2139 1795 : key = UseRegisterOrConstantAtStart(instr->key());
2140 : } else {
2141 : bool clobbers_key = ExternalArrayOpRequiresTemp(
2142 : instr->key()->representation(), elements_kind);
2143 : key = clobbers_key
2144 : ? UseTempRegister(instr->key())
2145 : : UseRegisterOrConstantAtStart(instr->key());
2146 : }
2147 1795 : LOperand* backing_store = UseRegister(instr->elements());
2148 1795 : LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2149 1795 : return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2150 : }
2151 :
2152 :
2153 754 : LInstruction* LChunkBuilder::DoTransitionElementsKind(
2154 754 : HTransitionElementsKind* instr) {
2155 754 : if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2156 352 : LOperand* object = UseRegister(instr->object());
2157 352 : LOperand* new_map_reg = TempRegister();
2158 352 : LOperand* temp_reg = TempRegister();
2159 754 : LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(
2160 : object, NULL, new_map_reg, temp_reg);
2161 352 : return result;
2162 : } else {
2163 402 : LOperand* object = UseFixed(instr->object(), rax);
2164 402 : LOperand* context = UseFixed(instr->context(), rsi);
2165 : LTransitionElementsKind* result =
2166 : new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2167 402 : return MarkAsCall(result, instr);
2168 : }
2169 : }
2170 :
2171 :
2172 37 : LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2173 : HTrapAllocationMemento* instr) {
2174 37 : LOperand* object = UseRegister(instr->object());
2175 37 : LOperand* temp = TempRegister();
2176 : LTrapAllocationMemento* result =
2177 37 : new(zone()) LTrapAllocationMemento(object, temp);
2178 37 : return AssignEnvironment(result);
2179 : }
2180 :
2181 :
2182 2584 : LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
2183 5168 : info()->MarkAsDeferredCalling();
2184 2584 : LOperand* context = UseFixed(instr->context(), rsi);
2185 2584 : LOperand* object = Use(instr->object());
2186 2584 : LOperand* elements = Use(instr->elements());
2187 2584 : LOperand* key = UseRegisterOrConstant(instr->key());
2188 2584 : LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
2189 :
2190 : LMaybeGrowElements* result = new (zone())
2191 : LMaybeGrowElements(context, object, elements, key, current_capacity);
2192 2584 : DefineFixed(result, rax);
2193 2584 : return AssignPointerMap(AssignEnvironment(result));
2194 : }
2195 :
2196 :
2197 362583 : LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2198 : bool is_in_object = instr->access().IsInobject();
2199 181292 : bool is_external_location = instr->access().IsExternalMemory() &&
2200 181292 : instr->access().offset() == 0;
2201 181292 : bool needs_write_barrier = instr->NeedsWriteBarrier();
2202 192396 : bool needs_write_barrier_for_map = instr->has_transition() &&
2203 : instr->NeedsWriteBarrierForMap();
2204 :
2205 : LOperand* obj;
2206 181291 : if (needs_write_barrier) {
2207 : obj = is_in_object
2208 : ? UseRegister(instr->object())
2209 31868 : : UseTempRegister(instr->object());
2210 165357 : } else if (is_external_location) {
2211 : DCHECK(!is_in_object);
2212 : DCHECK(!needs_write_barrier);
2213 : DCHECK(!needs_write_barrier_for_map);
2214 0 : obj = UseRegisterOrConstant(instr->object());
2215 : } else {
2216 : obj = needs_write_barrier_for_map
2217 : ? UseRegister(instr->object())
2218 330714 : : UseRegisterAtStart(instr->object());
2219 : }
2220 :
2221 104190 : bool can_be_constant = instr->value()->IsConstant() &&
2222 389087 : HConstant::cast(instr->value())->NotInNewSpace() &&
2223 : !instr->field_representation().IsDouble();
2224 :
2225 : LOperand* val;
2226 181292 : if (needs_write_barrier) {
2227 15934 : val = UseTempRegister(instr->value());
2228 165358 : } else if (is_external_location) {
2229 0 : val = UseFixed(instr->value(), rax);
2230 165358 : } else if (can_be_constant) {
2231 103058 : val = UseRegisterOrConstant(instr->value());
2232 62300 : } else if (instr->field_representation().IsDouble()) {
2233 273 : val = UseRegisterAtStart(instr->value());
2234 : } else {
2235 62027 : val = UseRegister(instr->value());
2236 : }
2237 :
2238 : // We only need a scratch register if we have a write barrier or we
2239 : // have a store into the properties array (not in-object-property).
2240 346330 : LOperand* temp = (!is_in_object || needs_write_barrier ||
2241 200390 : needs_write_barrier_for_map) ? TempRegister() : NULL;
2242 :
2243 362584 : return new(zone()) LStoreNamedField(obj, val, temp);
2244 : }
2245 :
2246 :
2247 21242 : LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2248 21242 : LOperand* context = UseFixed(instr->context(), rsi);
2249 21242 : LOperand* left = UseFixed(instr->left(), rdx);
2250 21242 : LOperand* right = UseFixed(instr->right(), rax);
2251 : return MarkAsCall(
2252 42484 : DefineFixed(new(zone()) LStringAdd(context, left, right), rax), instr);
2253 : }
2254 :
2255 :
2256 377 : LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2257 377 : LOperand* string = UseTempRegister(instr->string());
2258 377 : LOperand* index = UseTempRegister(instr->index());
2259 377 : LOperand* context = UseAny(instr->context());
2260 : LStringCharCodeAt* result =
2261 377 : new(zone()) LStringCharCodeAt(context, string, index);
2262 377 : return AssignPointerMap(DefineAsRegister(result));
2263 : }
2264 :
2265 :
2266 477 : LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2267 477 : LOperand* char_code = UseRegister(instr->value());
2268 477 : LOperand* context = UseAny(instr->context());
2269 : LStringCharFromCode* result =
2270 477 : new(zone()) LStringCharFromCode(context, char_code);
2271 477 : return AssignPointerMap(DefineAsRegister(result));
2272 : }
2273 :
2274 :
2275 51496 : LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2276 : LOperand* size = instr->size()->IsConstant() ? UseConstant(instr->size())
2277 33440 : : UseRegister(instr->size());
2278 25748 : if (instr->IsAllocationFolded()) {
2279 4903 : LOperand* temp = TempRegister();
2280 46593 : LFastAllocate* result = new (zone()) LFastAllocate(size, temp);
2281 4903 : return DefineAsRegister(result);
2282 : } else {
2283 : info()->MarkAsDeferredCalling();
2284 20845 : LOperand* context = UseAny(instr->context());
2285 20845 : LOperand* temp = TempRegister();
2286 : LAllocate* result = new (zone()) LAllocate(context, size, temp);
2287 20845 : return AssignPointerMap(DefineAsRegister(result));
2288 : }
2289 : }
2290 :
2291 :
2292 2369 : LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2293 : DCHECK(argument_count_ == 0);
2294 2369 : allocator_->MarkAsOsrEntry();
2295 2369 : current_block_->last_environment()->set_ast_id(instr->ast_id());
2296 4738 : return AssignEnvironment(new(zone()) LOsrEntry);
2297 : }
2298 :
2299 :
2300 1379974 : LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2301 919984 : LParameter* result = new(zone()) LParameter;
2302 459990 : if (instr->kind() == HParameter::STACK_PARAMETER) {
2303 845626 : int spill_index = chunk()->GetParameterStackSlot(instr->index());
2304 422823 : return DefineAsSpilled(result, spill_index);
2305 : } else {
2306 : DCHECK(info()->IsStub());
2307 : CallInterfaceDescriptor descriptor = graph()->descriptor();
2308 37177 : int index = static_cast<int>(instr->index());
2309 37177 : Register reg = descriptor.GetRegisterParameter(index);
2310 37177 : return DefineFixed(result, reg);
2311 : }
2312 : }
2313 :
2314 :
2315 14103 : LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
2316 : // Use an index that corresponds to the location in the unoptimized frame,
2317 : // which the optimized frame will subsume.
2318 : int env_index = instr->index();
2319 : int spill_index = 0;
2320 14103 : if (instr->environment()->is_parameter_index(env_index)) {
2321 17809 : spill_index = chunk()->GetParameterStackSlot(env_index);
2322 : } else {
2323 10397 : spill_index = env_index - instr->environment()->first_local_index();
2324 10397 : if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2325 0 : Retry(kTooManySpillSlotsNeededForOSR);
2326 : spill_index = 0;
2327 : }
2328 10397 : spill_index += StandardFrameConstants::kFixedSlotCount;
2329 : }
2330 14103 : return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2331 : }
2332 :
2333 :
2334 366876 : LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
2335 : // There are no real uses of the arguments object.
2336 : // arguments.length and element access are supported directly on
2337 : // stack arguments, and any real arguments object use causes a bailout.
2338 : // So this value is never used.
2339 366876 : return NULL;
2340 : }
2341 :
2342 :
2343 10961 : LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2344 10961 : instr->ReplayEnvironment(current_block_->last_environment());
2345 :
2346 : // There are no real uses of a captured object.
2347 10961 : return NULL;
2348 : }
2349 :
2350 :
2351 636 : LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2352 1272 : info()->MarkAsRequiresFrame();
2353 636 : LOperand* args = UseRegister(instr->arguments());
2354 : LOperand* length;
2355 : LOperand* index;
2356 921 : if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2357 184 : length = UseRegisterOrConstant(instr->length());
2358 184 : index = UseOrConstant(instr->index());
2359 : } else {
2360 452 : length = UseTempRegister(instr->length());
2361 452 : index = Use(instr->index());
2362 : }
2363 636 : return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2364 : }
2365 :
2366 :
2367 38635 : LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2368 38635 : LOperand* context = UseFixed(instr->context(), rsi);
2369 38635 : LOperand* value = UseFixed(instr->value(), rbx);
2370 38635 : LTypeof* result = new(zone()) LTypeof(context, value);
2371 38635 : return MarkAsCall(DefineFixed(result, rax), instr);
2372 : }
2373 :
2374 :
2375 56211 : LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2376 112422 : return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2377 : }
2378 :
2379 :
2380 4739986 : LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2381 4739986 : instr->ReplayEnvironment(current_block_->last_environment());
2382 4739994 : return NULL;
2383 : }
2384 :
2385 :
2386 583022 : LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2387 583026 : info()->MarkAsDeferredCalling();
2388 291511 : if (instr->is_function_entry()) {
2389 260188 : LOperand* context = UseFixed(instr->context(), rsi);
2390 260193 : return MarkAsCall(new(zone()) LStackCheck(context), instr);
2391 : } else {
2392 : DCHECK(instr->is_backwards_branch());
2393 31323 : LOperand* context = UseAny(instr->context());
2394 : return AssignEnvironment(
2395 62646 : AssignPointerMap(new(zone()) LStackCheck(context)));
2396 : }
2397 : }
2398 :
2399 :
2400 427472 : LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2401 106691 : HEnvironment* outer = current_block_->last_environment();
2402 : outer->set_ast_id(instr->ReturnId());
2403 106691 : HConstant* undefined = graph()->GetConstantUndefined();
2404 : HEnvironment* inner = outer->CopyForInlining(
2405 : instr->closure(), instr->arguments_count(), instr->function(), undefined,
2406 106691 : instr->inlining_kind(), instr->syntactic_tail_call_mode());
2407 : // Only replay binding of arguments object if it wasn't removed from graph.
2408 107045 : if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2409 354 : inner->Bind(instr->arguments_var(), instr->arguments_object());
2410 : }
2411 : inner->BindContext(instr->closure_context());
2412 : inner->set_entry(instr);
2413 106691 : current_block_->UpdateEnvironment(inner);
2414 106691 : return NULL;
2415 : }
2416 :
2417 :
2418 558631 : LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2419 : LInstruction* pop = NULL;
2420 :
2421 1117262 : HEnvironment* env = current_block_->last_environment();
2422 :
2423 558631 : if (env->entry()->arguments_pushed()) {
2424 247 : int argument_count = env->arguments_environment()->parameter_count();
2425 247 : pop = new(zone()) LDrop(argument_count);
2426 : DCHECK(instr->argument_delta() == -argument_count);
2427 : }
2428 :
2429 : HEnvironment* outer = current_block_->last_environment()->
2430 1117262 : DiscardInlined(false);
2431 558631 : current_block_->UpdateEnvironment(outer);
2432 :
2433 558631 : return pop;
2434 : }
2435 :
2436 :
2437 754 : LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
2438 754 : LOperand* context = UseFixed(instr->context(), rsi);
2439 754 : LOperand* object = UseFixed(instr->enumerable(), rax);
2440 754 : LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
2441 754 : return MarkAsCall(DefineFixed(result, rax), instr, CAN_DEOPTIMIZE_EAGERLY);
2442 : }
2443 :
2444 :
2445 1732 : LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2446 1732 : LOperand* map = UseRegister(instr->map());
2447 : return AssignEnvironment(DefineAsRegister(
2448 5196 : new(zone()) LForInCacheArray(map)));
2449 : }
2450 :
2451 :
2452 1209 : LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
2453 1209 : LOperand* value = UseRegisterAtStart(instr->value());
2454 1209 : LOperand* map = UseRegisterAtStart(instr->map());
2455 2418 : return AssignEnvironment(new(zone()) LCheckMapValue(value, map));
2456 : }
2457 :
2458 :
2459 589 : LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
2460 589 : LOperand* object = UseRegister(instr->object());
2461 589 : LOperand* index = UseTempRegister(instr->index());
2462 589 : LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
2463 589 : LInstruction* result = DefineSameAsFirst(load);
2464 589 : return AssignPointerMap(result);
2465 : }
2466 :
2467 : } // namespace internal
2468 : } // namespace v8
2469 :
2470 : #endif // V8_TARGET_ARCH_X64
|