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 30787825 : 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 8363614 : bool LGap::IsRedundant() const {
96 40813546 : for (int i = 0; i < 4; i++) {
97 32794752 : 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 7129222 : bool LTemplateResultInstruction<R>::MustSignExtendResult(
159 : LPlatformChunk* chunk) const {
160 8165997 : HValue* hvalue = this->hydrogen_value();
161 : return hvalue != NULL &&
162 : hvalue->representation().IsInteger32() &&
163 9202772 : 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 805708 : return current_frame_slots_++;
315 : }
316 :
317 :
318 797697 : 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 797697 : if (kind == DOUBLE_REGISTERS) {
324 27094 : return LDoubleStackSlot::Create(index, zone());
325 : } else {
326 : DCHECK(kind == GENERAL_REGISTERS);
327 784150 : 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 283190 : LPlatformChunk* LChunkBuilder::Build() {
380 : DCHECK(is_unused());
381 5343083 : chunk_ = new(zone()) LPlatformChunk(info(), graph());
382 : LPhase phase("L_Building chunk", chunk_);
383 283182 : status_ = BUILDING;
384 :
385 : // If compiling for OSR, reserve space for the unoptimized frame,
386 : // which will be subsumed into this frame.
387 283182 : if (graph()->has_osr()) {
388 10376 : for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
389 8011 : chunk_->GetNextSpillIndex(GENERAL_REGISTERS);
390 : }
391 : }
392 :
393 : const ZoneList<HBasicBlock*>* blocks = graph()->blocks();
394 9553410 : for (int i = 0; i < blocks->length(); i++) {
395 : HBasicBlock* next = NULL;
396 13480532 : if (i < blocks->length() - 1) next = blocks->at(i + 1);
397 4493508 : DoBasicBlock(blocks->at(i), next);
398 4493521 : if (is_aborted()) return NULL;
399 : }
400 283197 : status_ = DONE;
401 283197 : return chunk_;
402 : }
403 :
404 :
405 7380618 : LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
406 14761247 : return new (zone()) LUnallocated(LUnallocated::FIXED_REGISTER, reg.code());
407 : }
408 :
409 :
410 65844 : LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) {
411 65844 : return new (zone())
412 65844 : LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, reg.code());
413 : }
414 :
415 :
416 5906079 : LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
417 5906079 : 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 1029542 : LOperand* LChunkBuilder::UseRegister(HValue* value) {
427 2059086 : return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
428 : }
429 :
430 :
431 1954403 : LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
432 : return Use(value,
433 1954403 : new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
434 1954406 : LUnallocated::USED_AT_START));
435 : }
436 :
437 :
438 132484 : LOperand* LChunkBuilder::UseTempRegister(HValue* value) {
439 264968 : 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 694293 : LOperand* LChunkBuilder::Use(HValue* value) {
451 1388586 : return Use(value, new(zone()) LUnallocated(LUnallocated::NONE));
452 : }
453 :
454 :
455 132173 : LOperand* LChunkBuilder::UseAtStart(HValue* value) {
456 132173 : return Use(value, new(zone()) LUnallocated(LUnallocated::NONE,
457 132173 : LUnallocated::USED_AT_START));
458 : }
459 :
460 :
461 1366471 : LOperand* LChunkBuilder::UseOrConstant(HValue* value) {
462 : return value->IsConstant()
463 710021 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
464 2076494 : : Use(value);
465 : }
466 :
467 :
468 367349 : LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) {
469 : return value->IsConstant()
470 239690 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
471 607039 : : UseAtStart(value);
472 : }
473 :
474 :
475 472814 : LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
476 : return value->IsConstant()
477 467764 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
478 940580 : : UseRegister(value);
479 : }
480 :
481 :
482 1274560 : LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
483 : return value->IsConstant()
484 990759 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
485 2265320 : : UseRegisterAtStart(value);
486 : }
487 :
488 :
489 0 : LOperand* LChunkBuilder::UseConstant(HValue* value) {
490 17979 : return chunk_->DefineConstantOperand(HConstant::cast(value));
491 : }
492 :
493 :
494 37667711 : LOperand* LChunkBuilder::UseAny(HValue* value) {
495 : return value->IsConstant()
496 17926731 : ? chunk_->DefineConstantOperand(HConstant::cast(value))
497 75336618 : : Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
498 : }
499 :
500 :
501 59191808 : LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
502 29595945 : if (value->EmitAtUses()) {
503 : HInstruction* instr = HInstruction::cast(value);
504 3546503 : VisitInstruction(instr);
505 : }
506 29595863 : operand->set_virtual_register(value->id());
507 29595863 : return operand;
508 : }
509 :
510 :
511 0 : LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
512 : LUnallocated* result) {
513 7767624 : result->set_virtual_register(current_instruction_->id());
514 : instr->set_result(result);
515 0 : return instr;
516 : }
517 :
518 :
519 5485229 : LInstruction* LChunkBuilder::DefineAsRegister(
520 : LTemplateResultInstruction<1>* instr) {
521 : return Define(instr,
522 10970464 : new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
523 : }
524 :
525 :
526 435805 : LInstruction* LChunkBuilder::DefineAsSpilled(
527 : LTemplateResultInstruction<1>* instr,
528 : int index) {
529 : return Define(instr,
530 871609 : new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
531 : }
532 :
533 :
534 352443 : LInstruction* LChunkBuilder::DefineSameAsFirst(
535 : LTemplateResultInstruction<1>* instr) {
536 : return Define(instr,
537 704886 : new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
538 : }
539 :
540 :
541 1463634 : LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
542 : Register reg) {
543 2927271 : return Define(instr, ToUnallocated(reg));
544 : }
545 :
546 :
547 3552 : LInstruction* LChunkBuilder::DefineFixedDouble(
548 : LTemplateResultInstruction<1>* instr,
549 : XMMRegister reg) {
550 7104 : return Define(instr, ToUnallocated(reg));
551 : }
552 :
553 :
554 0 : LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
555 1234803 : HEnvironment* hydrogen_env = current_block_->last_environment();
556 1234803 : return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
557 : }
558 :
559 :
560 2499718 : LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
561 : HInstruction* hinstr,
562 : CanDeoptimize can_deoptimize) {
563 1692206 : info()->MarkAsNonDeferredCalling();
564 :
565 : #ifdef DEBUG
566 : instr->VerifyCall();
567 : #endif
568 : instr->MarkAsCall();
569 1692206 : 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 3382707 : (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
577 : !hinstr->HasObservableSideEffects();
578 2095969 : 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 1692213 : return instr;
585 : }
586 :
587 :
588 1796899 : LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
589 : DCHECK(!instr->HasPointerMap());
590 3593801 : instr->set_pointer_map(new(zone()) LPointerMap(zone()));
591 1796905 : return instr;
592 : }
593 :
594 :
595 156964 : LUnallocated* LChunkBuilder::TempRegister() {
596 : LUnallocated* operand =
597 156964 : new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
598 313928 : int vreg = allocator_->GetVirtualRegister();
599 156964 : if (!allocator_->AllocationOk()) {
600 0 : Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
601 : vreg = 0;
602 : }
603 156964 : operand->set_virtual_register(vreg);
604 156964 : return operand;
605 : }
606 :
607 :
608 0 : LOperand* LChunkBuilder::FixedTemp(Register reg) {
609 5922 : LUnallocated* operand = ToUnallocated(reg);
610 : DCHECK(operand->HasFixedPolicy());
611 0 : return operand;
612 : }
613 :
614 :
615 0 : LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) {
616 56128 : LUnallocated* operand = ToUnallocated(reg);
617 : DCHECK(operand->HasFixedPolicy());
618 0 : return operand;
619 : }
620 :
621 :
622 4493484 : LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
623 8986968 : 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 187163 : LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
639 374327 : return AssignEnvironment(new(zone()) LDeoptimize);
640 : }
641 :
642 :
643 39552 : LInstruction* LChunkBuilder::DoShift(Token::Value op,
644 : HBitwiseBinaryOperation* instr) {
645 43185 : if (instr->representation().IsSmiOrInteger32()) {
646 : DCHECK(instr->left()->representation().Equals(instr->representation()));
647 : DCHECK(instr->right()->representation().Equals(instr->representation()));
648 37772 : 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 37772 : if (right_value->IsConstant()) {
655 32615 : HConstant* constant = HConstant::cast(right_value);
656 32615 : right = chunk_->DefineConstantOperand(constant);
657 32615 : 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 5157 : 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 37772 : if (op == Token::SHR && constant_value == 0) {
671 3633 : does_deopt = !instr->CheckFlag(HInstruction::kUint32);
672 : }
673 :
674 : LInstruction* result =
675 75544 : DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt));
676 75544 : return does_deopt ? AssignEnvironment(result) : result;
677 : } else {
678 1780 : return DoArithmeticT(op, instr);
679 : }
680 : }
681 :
682 :
683 85970 : 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 85970 : if (op == Token::MOD) {
689 4448 : LOperand* left = UseFixedDouble(instr->BetterLeftOperand(), xmm0);
690 2224 : LOperand* right = UseFixedDouble(instr->BetterRightOperand(), xmm1);
691 85970 : LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
692 2224 : return MarkAsCall(DefineFixedDouble(result, xmm0), instr);
693 : } else {
694 167492 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
695 83746 : LOperand* right = UseRegisterAtStart(instr->BetterRightOperand());
696 : LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
697 : return CpuFeatures::IsSupported(AVX) ? DefineAsRegister(result)
698 83746 : : DefineSameAsFirst(result);
699 : }
700 : }
701 :
702 :
703 47403 : 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 47403 : LOperand* context = UseFixed(instr->context(), rsi);
710 47403 : LOperand* left_operand = UseFixed(left, rdx);
711 47403 : LOperand* right_operand = UseFixed(right, rax);
712 : LArithmeticT* result =
713 47403 : new(zone()) LArithmeticT(op, context, left_operand, right_operand);
714 47403 : return MarkAsCall(DefineFixed(result, rax), instr);
715 : }
716 :
717 :
718 12002721 : void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
719 : DCHECK(is_building());
720 4493550 : current_block_ = block;
721 4493550 : next_block_ = next_block;
722 4493550 : if (block->IsStartBlock()) {
723 283187 : block->UpdateEnvironment(graph_->start_environment());
724 283235 : argument_count_ = 0;
725 4210363 : } 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 10549112 : 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 3766764 : if (pred->end()->SecondSuccessor() == NULL) {
734 : DCHECK(pred->end()->FirstSuccessor() == block);
735 : } else {
736 4967034 : if (pred->end()->FirstSuccessor()->block_id() > block->block_id() ||
737 1064185 : pred->end()->SecondSuccessor()->block_id() > block->block_id()) {
738 975717 : last_environment = last_environment->Copy();
739 : }
740 : }
741 3766744 : block->UpdateEnvironment(last_environment);
742 : DCHECK(pred->argument_count() >= 0);
743 3766733 : argument_count_ = pred->argument_count();
744 : } else {
745 : // We are at a state join => process phis.
746 887198 : 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 743550 : for (int i = 0; i < block->phis()->length(); ++i) {
750 299951 : HPhi* phi = block->phis()->at(i);
751 299951 : 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 443599 : block->UpdateEnvironment(last_environment);
762 : // Pick up the outgoing argument count of one of the predecessors.
763 443599 : argument_count_ = pred->argument_count();
764 : }
765 25123363 : HInstruction* current = block->first();
766 4493567 : int start = chunk_->instructions()->length();
767 34110497 : while (current != NULL && !is_aborted()) {
768 : // Code for constants in registers is generated lazily.
769 25123408 : if (!current->EmitAtUses()) {
770 20810103 : VisitInstruction(current);
771 : }
772 : current = current->next();
773 : }
774 4493522 : int end = chunk_->instructions()->length() - 1;
775 4493522 : if (end >= start) {
776 : block->set_first_instruction_index(start);
777 : block->set_last_instruction_index(end);
778 : }
779 4493522 : block->set_argument_count(argument_count_);
780 4493522 : next_block_ = NULL;
781 4493522 : current_block_ = NULL;
782 4493522 : }
783 :
784 :
785 24356433 : void LChunkBuilder::VisitInstruction(HInstruction* current) {
786 24356433 : HInstruction* old_current = current_instruction_;
787 24356433 : current_instruction_ = current;
788 :
789 : LInstruction* instr = NULL;
790 24356433 : if (current->CanReplaceWithDummyUses()) {
791 564147 : if (current->OperandCount() == 0) {
792 4897752 : instr = DefineAsRegister(new(zone()) LDummy());
793 : } else {
794 : DCHECK(!current->OperandAt(0)->IsControlInstruction());
795 : instr = DefineAsRegister(new(zone())
796 1114767 : LDummyUse(UseAny(current->OperandAt(0))));
797 : }
798 1762560 : for (int i = 1; i < current->OperandCount(); ++i) {
799 1198423 : if (current->OperandAt(i)->IsControlInstruction()) continue;
800 : LInstruction* dummy =
801 1198404 : new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
802 : dummy->set_hydrogen_value(current);
803 1198397 : chunk_->AddInstruction(dummy, current_block_);
804 : }
805 : } else {
806 : HBasicBlock* successor;
807 52078668 : if (current->IsControlInstruction() &&
808 27108375 : HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
809 3315595 : successor != NULL) {
810 3128438 : instr = new(zone()) LGoto(successor);
811 : } else {
812 20664306 : instr = current->CompileToLithium(this);
813 : }
814 : }
815 :
816 24356478 : argument_count_ += current->argument_delta();
817 : DCHECK(argument_count_ >= 0);
818 :
819 24356398 : if (instr != NULL) {
820 17997839 : AddInstruction(instr, current);
821 : }
822 :
823 24356526 : current_instruction_ = old_current;
824 24356526 : }
825 :
826 :
827 19356783 : 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 19356783 : if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
864 0 : instr = AssignPointerMap(instr);
865 : }
866 19356881 : if (FLAG_stress_environments && !instr->HasEnvironment()) {
867 : instr = AssignEnvironment(instr);
868 : }
869 19356881 : chunk_->AddInstruction(instr, current_block_);
870 :
871 19356856 : CreateLazyBailoutForCall(current_block_, instr, hydrogen_val);
872 19356912 : }
873 :
874 :
875 0 : LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
876 0 : return new(zone()) LGoto(instr->FirstSuccessor());
877 : }
878 :
879 :
880 259707 : LInstruction* LChunkBuilder::DoPrologue(HPrologue* instr) {
881 519417 : LInstruction* result = new (zone()) LPrologue();
882 519418 : if (info_->scope()->NeedsContext()) {
883 6497 : result = MarkAsCall(result, instr);
884 : }
885 259708 : return result;
886 : }
887 :
888 :
889 0 : LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
890 0 : return new(zone()) LDebugBreak();
891 : }
892 :
893 :
894 478954 : 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 478954 : if (expected == ToBooleanHint::kNone) expected = ToBooleanHint::kAny;
900 :
901 783318 : bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
902 783950 : type.IsJSArray() || type.IsHeapNumber() || type.IsString();
903 478954 : LInstruction* branch = new(zone()) LBranch(UseRegister(value));
904 1161891 : if (!easy_case && ((!(expected & ToBooleanHint::kSmallInteger) &&
905 143261 : (expected & ToBooleanHint::kNeedsMap)) ||
906 : expected != ToBooleanHint::kAny)) {
907 : branch = AssignEnvironment(branch);
908 : }
909 478954 : return branch;
910 : }
911 :
912 :
913 17765 : LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
914 : DCHECK(instr->value()->representation().IsTagged());
915 17765 : LOperand* value = UseRegisterAtStart(instr->value());
916 35530 : 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 759 : LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) {
927 1518 : info()->MarkAsRequiresFrame();
928 759 : 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 4465 : LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
943 4465 : LOperand* receiver = UseRegister(instr->receiver());
944 4465 : LOperand* function = UseRegisterAtStart(instr->function());
945 4465 : LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
946 8930 : 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 572679 : LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
964 : int argc = instr->OperandCount();
965 1931357 : for (int i = 0; i < argc; ++i) {
966 1358678 : LOperand* argument = UseOrConstant(instr->argument(i));
967 2717359 : AddInstruction(new(zone()) LPushArgument(argument), instr);
968 : }
969 572679 : 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 7136 : LInstruction* LChunkBuilder::DoInnerAllocatedObject(
982 : HInnerAllocatedObject* instr) {
983 7136 : LOperand* base_object = UseRegisterAtStart(instr->base_object());
984 7136 : LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
985 : return DefineAsRegister(
986 14272 : new(zone()) LInnerAllocatedObject(base_object, offset));
987 : }
988 :
989 :
990 26628 : LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
991 26628 : return instr->HasNoUses()
992 : ? NULL
993 48584 : : DefineAsRegister(new(zone()) LThisFunction);
994 : }
995 :
996 :
997 285550 : LInstruction* LChunkBuilder::DoContext(HContext* instr) {
998 285550 : if (instr->HasNoUses()) return NULL;
999 :
1000 547631 : if (info()->IsStub()) {
1001 23483 : return DefineFixed(new(zone()) LContext, rsi);
1002 : }
1003 :
1004 262071 : return DefineAsRegister(new(zone()) LContext);
1005 : }
1006 :
1007 :
1008 12327 : LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
1009 12327 : LOperand* context = UseFixed(instr->context(), rsi);
1010 24654 : return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
1011 : }
1012 :
1013 :
1014 851847 : LInstruction* LChunkBuilder::DoCallWithDescriptor(
1015 851844 : HCallWithDescriptor* instr) {
1016 : CallInterfaceDescriptor descriptor = instr->descriptor();
1017 : DCHECK_EQ(descriptor.GetParameterCount() +
1018 : LCallWithDescriptor::kImplicitRegisterParameterCount,
1019 : instr->OperandCount());
1020 :
1021 851847 : LOperand* target = UseRegisterOrConstantAtStart(instr->target());
1022 6481618 : ZoneList<LOperand*> ops(instr->OperandCount(), zone());
1023 : // Target
1024 : ops.Add(target, zone());
1025 : // Context
1026 851846 : LOperand* op = UseFixed(instr->OperandAt(1), rsi);
1027 : ops.Add(op, zone());
1028 : // Load register parameters.
1029 : int i = 0;
1030 7851322 : for (; i < descriptor.GetRegisterParameterCount(); i++) {
1031 : op = UseFixed(instr->OperandAt(
1032 : i + LCallWithDescriptor::kImplicitRegisterParameterCount),
1033 6147636 : descriptor.GetRegisterParameter(i));
1034 : ops.Add(op, zone());
1035 : }
1036 : // Push stack parameters.
1037 852671 : for (; i < descriptor.GetParameterCount(); i++) {
1038 : op = UseAny(instr->OperandAt(
1039 828 : i + LCallWithDescriptor::kImplicitRegisterParameterCount));
1040 414 : AddInstruction(new (zone()) LPushArgument(op), instr);
1041 : }
1042 :
1043 : LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
1044 1703688 : descriptor, ops, zone());
1045 851844 : if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
1046 : result->MarkAsSyntacticTailCall();
1047 : }
1048 851844 : return MarkAsCall(DefineFixed(result, rax), instr);
1049 : }
1050 :
1051 :
1052 258201 : LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
1053 129101 : LOperand* context = UseFixed(instr->context(), rsi);
1054 129102 : LOperand* function = UseFixed(instr->function(), rdi);
1055 129101 : LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
1056 129100 : if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
1057 : result->MarkAsSyntacticTailCall();
1058 : }
1059 129100 : return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
1060 : }
1061 :
1062 :
1063 26431 : LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
1064 26431 : switch (instr->op()) {
1065 : case kMathFloor:
1066 23397 : return DoMathFloor(instr);
1067 : case kMathRound:
1068 1374 : return DoMathRound(instr);
1069 : case kMathFround:
1070 630 : return DoMathFround(instr);
1071 : case kMathAbs:
1072 385 : 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 63 : 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 23397 : LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
1094 : DCHECK(instr->value()->representation().IsDouble());
1095 23397 : LOperand* input = UseRegisterAtStart(instr->value());
1096 23397 : if (instr->representation().IsInteger32()) {
1097 23397 : LMathFloorI* result = new (zone()) LMathFloorI(input);
1098 37532 : return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1099 : } else {
1100 : DCHECK(instr->representation().IsDouble());
1101 : LMathFloorD* result = new (zone()) LMathFloorD(input);
1102 4631 : return DefineAsRegister(result);
1103 : }
1104 : }
1105 :
1106 1374 : LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
1107 : DCHECK(instr->value()->representation().IsDouble());
1108 1374 : LOperand* input = UseRegister(instr->value());
1109 1374 : if (instr->representation().IsInteger32()) {
1110 : LOperand* temp = FixedTemp(xmm4);
1111 1374 : LMathRoundI* result = new (zone()) LMathRoundI(input, temp);
1112 1446 : return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
1113 : } else {
1114 : DCHECK(instr->representation().IsDouble());
1115 : LMathRoundD* result = new (zone()) LMathRoundD(input);
1116 651 : return DefineAsRegister(result);
1117 : }
1118 : }
1119 :
1120 630 : LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
1121 630 : LOperand* input = UseRegister(instr->value());
1122 630 : LMathFround* result = new (zone()) LMathFround(input);
1123 630 : return DefineAsRegister(result);
1124 : }
1125 :
1126 :
1127 385 : LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) {
1128 385 : LOperand* context = UseAny(instr->context());
1129 385 : LOperand* input = UseRegisterAtStart(instr->value());
1130 : LInstruction* result =
1131 770 : DefineSameAsFirst(new(zone()) LMathAbs(context, input));
1132 : Representation r = instr->value()->representation();
1133 572 : if (!r.IsDouble() && !r.IsSmiOrInteger32()) result = AssignPointerMap(result);
1134 385 : if (!r.IsDouble()) result = AssignEnvironment(result);
1135 385 : 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 63 : LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
1179 63 : LOperand* input = UseAtStart(instr->value());
1180 126 : 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 371 : LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
1192 371 : LOperand* context = UseFixed(instr->context(), rsi);
1193 371 : LOperand* constructor = UseFixed(instr->constructor(), rdi);
1194 371 : LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
1195 371 : return MarkAsCall(DefineFixed(result, rax), instr);
1196 : }
1197 :
1198 :
1199 104421 : LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
1200 104421 : LOperand* context = UseFixed(instr->context(), rsi);
1201 104421 : LCallRuntime* result = new(zone()) LCallRuntime(context);
1202 104422 : return MarkAsCall(DefineFixed(result, rax), instr);
1203 : }
1204 :
1205 :
1206 549 : LInstruction* LChunkBuilder::DoRor(HRor* instr) {
1207 549 : return DoShift(Token::ROR, instr);
1208 : }
1209 :
1210 :
1211 8407 : LInstruction* LChunkBuilder::DoShr(HShr* instr) {
1212 8407 : return DoShift(Token::SHR, instr);
1213 : }
1214 :
1215 :
1216 14061 : LInstruction* LChunkBuilder::DoSar(HSar* instr) {
1217 14061 : return DoShift(Token::SAR, instr);
1218 : }
1219 :
1220 :
1221 16535 : LInstruction* LChunkBuilder::DoShl(HShl* instr) {
1222 16535 : return DoShift(Token::SHL, instr);
1223 : }
1224 :
1225 :
1226 99556 : LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
1227 95067 : 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 181156 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1233 : LOperand* right;
1234 90578 : 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 89686 : right = UseOrConstantAtStart(instr->BetterRightOperand());
1239 : }
1240 181155 : return DefineSameAsFirst(new(zone()) LBitI(left, right));
1241 : } else {
1242 4489 : return DoArithmeticT(instr->op(), instr);
1243 : }
1244 : }
1245 :
1246 :
1247 542 : 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 542 : LOperand* dividend = UseRegister(instr->left());
1252 542 : int32_t divisor = instr->right()->GetInteger32Constant();
1253 542 : LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
1254 542 : dividend, divisor));
1255 1677 : if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1256 1071 : (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
1257 : (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
1258 128 : divisor != 1 && divisor != -1)) {
1259 : result = AssignEnvironment(result);
1260 : }
1261 542 : return result;
1262 : }
1263 :
1264 :
1265 1435 : 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 1435 : LOperand* dividend = UseRegister(instr->left());
1270 1435 : int32_t divisor = instr->right()->GetInteger32Constant();
1271 : LOperand* temp1 = FixedTemp(rax);
1272 : LOperand* temp2 = FixedTemp(rdx);
1273 1435 : LInstruction* result = DefineFixed(new(zone()) LDivByConstI(
1274 1435 : dividend, divisor, temp1, temp2), rdx);
1275 2870 : if (divisor == 0 ||
1276 2879 : (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1277 : !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
1278 : result = AssignEnvironment(result);
1279 : }
1280 1435 : return result;
1281 : }
1282 :
1283 :
1284 450 : 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 450 : LOperand* dividend = UseFixed(instr->left(), rax);
1289 450 : LOperand* divisor = UseRegister(instr->right());
1290 : LOperand* temp = FixedTemp(rdx);
1291 450 : LInstruction* result = DefineFixed(new(zone()) LDivI(
1292 450 : dividend, divisor, temp), rax);
1293 904 : if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1294 4 : instr->CheckFlag(HValue::kBailoutOnMinusZero) ||
1295 454 : instr->CheckFlag(HValue::kCanOverflow) ||
1296 : !instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
1297 : result = AssignEnvironment(result);
1298 : }
1299 450 : return result;
1300 : }
1301 :
1302 :
1303 39252 : LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
1304 39252 : if (instr->representation().IsSmiOrInteger32()) {
1305 2427 : if (instr->RightIsPowerOf2()) {
1306 542 : return DoDivByPowerOf2I(instr);
1307 1885 : } else if (instr->right()->IsConstant()) {
1308 1435 : return DoDivByConstI(instr);
1309 : } else {
1310 450 : return DoDivI(instr);
1311 : }
1312 36825 : } else if (instr->representation().IsDouble()) {
1313 19041 : return DoArithmeticD(Token::DIV, instr);
1314 : } else {
1315 17784 : return DoArithmeticT(Token::DIV, instr);
1316 : }
1317 : }
1318 :
1319 :
1320 512 : LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
1321 512 : LOperand* dividend = UseRegisterAtStart(instr->left());
1322 512 : int32_t divisor = instr->right()->GetInteger32Constant();
1323 512 : LInstruction* result = DefineSameAsFirst(new(zone()) LFlooringDivByPowerOf2I(
1324 512 : dividend, divisor));
1325 1779 : if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
1326 243 : (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
1327 : result = AssignEnvironment(result);
1328 : }
1329 512 : return result;
1330 : }
1331 :
1332 :
1333 1963 : 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 1963 : LOperand* dividend = UseRegister(instr->left());
1338 1963 : int32_t divisor = instr->right()->GetInteger32Constant();
1339 : LOperand* temp1 = FixedTemp(rax);
1340 : LOperand* temp2 = FixedTemp(rdx);
1341 : LOperand* temp3 =
1342 3946 : ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
1343 961 : (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
1344 3926 : NULL : TempRegister();
1345 : LInstruction* result =
1346 1963 : DefineFixed(new(zone()) LFlooringDivByConstI(dividend,
1347 : divisor,
1348 : temp1,
1349 : temp2,
1350 : temp3),
1351 1963 : rdx);
1352 5882 : if (divisor == 0 ||
1353 1955 : (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
1354 : result = AssignEnvironment(result);
1355 : }
1356 1963 : 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 2546 : LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
1379 2546 : if (instr->RightIsPowerOf2()) {
1380 512 : return DoFlooringDivByPowerOf2I(instr);
1381 2034 : } else if (instr->right()->IsConstant()) {
1382 1963 : return DoFlooringDivByConstI(instr);
1383 : } else {
1384 71 : return DoFlooringDivI(instr);
1385 : }
1386 : }
1387 :
1388 :
1389 1069 : 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 1069 : LOperand* dividend = UseRegisterAtStart(instr->left());
1394 1069 : int32_t divisor = instr->right()->GetInteger32Constant();
1395 1069 : LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
1396 1069 : dividend, divisor));
1397 3183 : if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
1398 : instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1399 : result = AssignEnvironment(result);
1400 : }
1401 1069 : return result;
1402 : }
1403 :
1404 :
1405 1601 : 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 1601 : LOperand* dividend = UseRegister(instr->left());
1410 1601 : int32_t divisor = instr->right()->GetInteger32Constant();
1411 : LOperand* temp1 = FixedTemp(rax);
1412 : LOperand* temp2 = FixedTemp(rdx);
1413 1601 : LInstruction* result = DefineFixed(new(zone()) LModByConstI(
1414 1601 : dividend, divisor, temp1, temp2), rax);
1415 3201 : if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1416 : result = AssignEnvironment(result);
1417 : }
1418 1601 : return result;
1419 : }
1420 :
1421 :
1422 402 : 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 402 : LOperand* dividend = UseFixed(instr->left(), rax);
1427 402 : LOperand* divisor = UseRegister(instr->right());
1428 : LOperand* temp = FixedTemp(rdx);
1429 402 : LInstruction* result = DefineFixed(new(zone()) LModI(
1430 402 : dividend, divisor, temp), rdx);
1431 812 : if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
1432 : instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
1433 : result = AssignEnvironment(result);
1434 : }
1435 402 : return result;
1436 : }
1437 :
1438 :
1439 5358 : LInstruction* LChunkBuilder::DoMod(HMod* instr) {
1440 5358 : if (instr->representation().IsSmiOrInteger32()) {
1441 3072 : if (instr->RightIsPowerOf2()) {
1442 1069 : return DoModByPowerOf2I(instr);
1443 2003 : } else if (instr->right()->IsConstant()) {
1444 1601 : return DoModByConstI(instr);
1445 : } else {
1446 402 : return DoModI(instr);
1447 : }
1448 2286 : } else if (instr->representation().IsDouble()) {
1449 2224 : return DoArithmeticD(Token::MOD, instr);
1450 : } else {
1451 62 : return DoArithmeticT(Token::MOD, instr);
1452 : }
1453 : }
1454 :
1455 :
1456 22860 : LInstruction* LChunkBuilder::DoMul(HMul* instr) {
1457 30468 : if (instr->representation().IsSmiOrInteger32()) {
1458 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1459 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1460 15216 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1461 : HValue* h_right = instr->BetterRightOperand();
1462 7608 : LOperand* right = UseOrConstant(h_right);
1463 7608 : LMulI* mul = new(zone()) LMulI(left, right);
1464 : int constant_value =
1465 7608 : 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 8382 : instr->CheckFlag(HValue::kCanOverflow) ||
1470 77 : (instr->CheckFlag(HValue::kBailoutOnMinusZero) &&
1471 29 : (!right->IsConstantOperand() || constant_value <= 0));
1472 7608 : if (needs_environment) {
1473 : AssignEnvironment(mul);
1474 : }
1475 7608 : return DefineSameAsFirst(mul);
1476 15252 : } else if (instr->representation().IsDouble()) {
1477 13166 : return DoArithmeticD(Token::MUL, instr);
1478 : } else {
1479 2086 : return DoArithmeticT(Token::MUL, instr);
1480 : }
1481 : }
1482 :
1483 :
1484 23599 : LInstruction* LChunkBuilder::DoSub(HSub* instr) {
1485 37182 : if (instr->representation().IsSmiOrInteger32()) {
1486 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1487 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1488 13583 : LOperand* left = UseRegisterAtStart(instr->left());
1489 : LOperand* right;
1490 13583 : if (SmiValuesAre32Bits() && instr->representation().IsSmi()) {
1491 : // We don't support tagged immediates, so we request it in a register.
1492 288 : right = UseRegisterAtStart(instr->right());
1493 : } else {
1494 13295 : right = UseOrConstantAtStart(instr->right());
1495 : }
1496 13583 : LSubI* sub = new(zone()) LSubI(left, right);
1497 13583 : LInstruction* result = DefineSameAsFirst(sub);
1498 13583 : if (instr->CheckFlag(HValue::kCanOverflow)) {
1499 : result = AssignEnvironment(result);
1500 : }
1501 13583 : return result;
1502 10016 : } else if (instr->representation().IsDouble()) {
1503 3093 : return DoArithmeticD(Token::SUB, instr);
1504 : } else {
1505 6923 : return DoArithmeticT(Token::SUB, instr);
1506 : }
1507 : }
1508 :
1509 :
1510 211758 : LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
1511 358516 : 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 146758 : bool use_lea = LAddI::UseLea(instr);
1517 : DCHECK(instr->left()->representation().Equals(instr->representation()));
1518 : DCHECK(instr->right()->representation().Equals(instr->representation()));
1519 293516 : LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
1520 : HValue* right_candidate = instr->BetterRightOperand();
1521 : LOperand* right;
1522 146758 : 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 740 : right = UseRegisterAtStart(right_candidate);
1526 : } else {
1527 : right = use_lea ? UseRegisterOrConstantAtStart(right_candidate)
1528 146018 : : UseOrConstantAtStart(right_candidate);
1529 : }
1530 149033 : LAddI* add = new(zone()) LAddI(left, right);
1531 : bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
1532 : LInstruction* result = use_lea ? DefineAsRegister(add)
1533 146758 : : DefineSameAsFirst(add);
1534 146758 : if (can_overflow) {
1535 : result = AssignEnvironment(result);
1536 : }
1537 146758 : return result;
1538 65000 : } else if (instr->representation().IsExternal()) {
1539 : DCHECK(instr->IsConsistentExternalRepresentation());
1540 : DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
1541 2275 : bool use_lea = LAddI::UseLea(instr);
1542 2275 : LOperand* left = UseRegisterAtStart(instr->left());
1543 : HValue* right_candidate = instr->right();
1544 : LOperand* right = use_lea
1545 : ? UseRegisterOrConstantAtStart(right_candidate)
1546 2275 : : UseOrConstantAtStart(right_candidate);
1547 : LAddI* add = new(zone()) LAddI(left, right);
1548 : LInstruction* result = use_lea
1549 : ? DefineAsRegister(add)
1550 2275 : : DefineSameAsFirst(add);
1551 2275 : return result;
1552 62725 : } else if (instr->representation().IsDouble()) {
1553 48446 : return DoArithmeticD(Token::ADD, instr);
1554 : } else {
1555 14279 : return DoArithmeticT(Token::ADD, instr);
1556 : }
1557 : return NULL;
1558 : }
1559 :
1560 :
1561 1580 : 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 1580 : if (instr->representation().IsSmi()) {
1567 0 : left = UseRegisterAtStart(instr->BetterLeftOperand());
1568 0 : right = UseAtStart(instr->BetterRightOperand());
1569 1580 : } else if (instr->representation().IsInteger32()) {
1570 424 : left = UseRegisterAtStart(instr->BetterLeftOperand());
1571 212 : right = UseOrConstantAtStart(instr->BetterRightOperand());
1572 : } else {
1573 : DCHECK(instr->representation().IsDouble());
1574 1368 : left = UseRegisterAtStart(instr->left());
1575 1368 : right = UseRegisterAtStart(instr->right());
1576 : }
1577 1580 : LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
1578 1580 : return DefineSameAsFirst(minmax);
1579 : }
1580 :
1581 :
1582 829 : 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 829 : LOperand* left = UseFixedDouble(instr->left(), xmm2);
1589 : LOperand* right =
1590 : exponent_type.IsDouble()
1591 : ? UseFixedDouble(instr->right(), xmm1)
1592 1658 : : UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
1593 829 : LPower* result = new(zone()) LPower(left, right);
1594 : return MarkAsCall(DefineFixedDouble(result, xmm3), instr,
1595 829 : CAN_DEOPTIMIZE_EAGERLY);
1596 : }
1597 :
1598 :
1599 200771 : LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
1600 : DCHECK(instr->left()->representation().IsTagged());
1601 : DCHECK(instr->right()->representation().IsTagged());
1602 200771 : LOperand* context = UseFixed(instr->context(), rsi);
1603 200771 : LOperand* left = UseFixed(instr->left(), rdx);
1604 200771 : LOperand* right = UseFixed(instr->right(), rax);
1605 200771 : LCmpT* result = new(zone()) LCmpT(context, left, right);
1606 200771 : return MarkAsCall(DefineFixed(result, rax), instr);
1607 : }
1608 :
1609 :
1610 165649 : LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
1611 : HCompareNumericAndBranch* instr) {
1612 : Representation r = instr->representation();
1613 165649 : if (r.IsSmiOrInteger32()) {
1614 : DCHECK(instr->left()->representation().Equals(r));
1615 : DCHECK(instr->right()->representation().Equals(r));
1616 147945 : LOperand* left = UseRegisterOrConstantAtStart(instr->left());
1617 147945 : LOperand* right = UseOrConstantAtStart(instr->right());
1618 313594 : 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 19675 : if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
1626 1731 : left = UseRegisterOrConstantAtStart(instr->left());
1627 1731 : right = UseRegisterOrConstantAtStart(instr->right());
1628 : } else {
1629 15973 : left = UseRegisterAtStart(instr->left());
1630 15973 : right = UseRegisterAtStart(instr->right());
1631 : }
1632 17704 : return new(zone()) LCompareNumericAndBranch(left, right);
1633 : }
1634 : }
1635 :
1636 :
1637 43295 : LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
1638 : HCompareObjectEqAndBranch* instr) {
1639 43295 : LOperand* left = UseRegisterAtStart(instr->left());
1640 43295 : LOperand* right = UseRegisterOrConstantAtStart(instr->right());
1641 86590 : 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 9188 : LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
1661 : DCHECK(instr->value()->representation().IsTagged());
1662 18376 : return new(zone()) LIsSmiAndBranch(Use(instr->value()));
1663 : }
1664 :
1665 :
1666 1251 : LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
1667 : HIsUndetectableAndBranch* instr) {
1668 : DCHECK(instr->value()->representation().IsTagged());
1669 1251 : LOperand* value = UseRegisterAtStart(instr->value());
1670 1251 : LOperand* temp = TempRegister();
1671 2502 : return new(zone()) LIsUndetectableAndBranch(value, temp);
1672 : }
1673 :
1674 :
1675 15171 : LInstruction* LChunkBuilder::DoStringCompareAndBranch(
1676 : HStringCompareAndBranch* instr) {
1677 :
1678 : DCHECK(instr->left()->representation().IsTagged());
1679 : DCHECK(instr->right()->representation().IsTagged());
1680 15171 : LOperand* context = UseFixed(instr->context(), rsi);
1681 15171 : LOperand* left = UseFixed(instr->left(), rdx);
1682 15171 : LOperand* right = UseFixed(instr->right(), rax);
1683 : LStringCompareAndBranch* result =
1684 15171 : new(zone()) LStringCompareAndBranch(context, left, right);
1685 :
1686 15171 : return MarkAsCall(result, instr);
1687 : }
1688 :
1689 :
1690 1974 : LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
1691 : HHasInstanceTypeAndBranch* instr) {
1692 : DCHECK(instr->value()->representation().IsTagged());
1693 1974 : LOperand* value = UseRegisterAtStart(instr->value());
1694 3948 : return new(zone()) LHasInstanceTypeAndBranch(value);
1695 : }
1696 :
1697 7686 : LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
1698 : HClassOfTestAndBranch* instr) {
1699 7686 : LOperand* value = UseRegister(instr->value());
1700 7686 : return new (zone())
1701 15372 : LClassOfTestAndBranch(value, TempRegister(), TempRegister());
1702 : }
1703 :
1704 14272 : LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
1705 14272 : LOperand* string = UseRegisterAtStart(instr->string());
1706 14272 : LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1707 28544 : return DefineAsRegister(new(zone()) LSeqStringGetChar(string, index));
1708 : }
1709 :
1710 :
1711 14272 : LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
1712 14272 : LOperand* string = UseRegisterAtStart(instr->string());
1713 : LOperand* index = FLAG_debug_code
1714 : ? UseRegisterAtStart(instr->index())
1715 28544 : : UseRegisterOrConstantAtStart(instr->index());
1716 : LOperand* value = FLAG_debug_code
1717 : ? UseRegisterAtStart(instr->value())
1718 28544 : : UseRegisterOrConstantAtStart(instr->value());
1719 14272 : LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), rsi) : NULL;
1720 14272 : LInstruction* result = new(zone()) LSeqStringSetChar(context, string,
1721 : index, value);
1722 14272 : if (FLAG_debug_code) {
1723 0 : result = MarkAsCall(result, instr);
1724 : }
1725 14272 : return result;
1726 : }
1727 :
1728 :
1729 63488 : LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
1730 63477 : if (!FLAG_debug_code && instr->skip_check()) return NULL;
1731 31744 : LOperand* index = UseRegisterOrConstantAtStart(instr->index());
1732 : LOperand* length = !index->IsConstantOperand()
1733 : ? UseOrConstantAtStart(instr->length())
1734 63488 : : UseAtStart(instr->length());
1735 31744 : LInstruction* result = new(zone()) LBoundsCheck(index, length);
1736 31755 : if (!FLAG_debug_code || !instr->skip_check()) {
1737 : result = AssignEnvironment(result);
1738 : }
1739 31744 : return result;
1740 : }
1741 :
1742 :
1743 15004 : 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 15004 : 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 342795 : LInstruction* LChunkBuilder::DoChange(HChange* instr) {
1764 : Representation from = instr->from();
1765 : Representation to = instr->to();
1766 23911 : HValue* val = instr->value();
1767 342795 : if (from.IsSmi()) {
1768 12253 : if (to.IsTagged()) {
1769 5639 : LOperand* value = UseRegister(val);
1770 524549 : return DefineSameAsFirst(new(zone()) LDummyUse(value));
1771 : }
1772 : from = Representation::Tagged();
1773 : }
1774 337156 : if (from.IsTagged()) {
1775 152026 : if (to.IsDouble()) {
1776 53976 : LOperand* value = UseRegister(val);
1777 53977 : LInstruction* result = DefineAsRegister(new(zone()) LNumberUntagD(value));
1778 53977 : if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1779 53977 : return result;
1780 98050 : } else if (to.IsSmi()) {
1781 22099 : LOperand* value = UseRegister(val);
1782 22099 : if (val->type().IsSmi()) {
1783 0 : return DefineSameAsFirst(new(zone()) LDummyUse(value));
1784 : }
1785 44198 : return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
1786 : } else {
1787 : DCHECK(to.IsInteger32());
1788 75951 : if (val->type().IsSmi() || val->representation().IsSmi()) {
1789 4477 : LOperand* value = UseRegister(val);
1790 4477 : return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
1791 : } else {
1792 71474 : LOperand* value = UseRegister(val);
1793 : bool truncating = instr->CanTruncateToInt32();
1794 71474 : LOperand* xmm_temp = truncating ? NULL : FixedTemp(xmm1);
1795 : LInstruction* result =
1796 71474 : DefineSameAsFirst(new(zone()) LTaggedToI(value, xmm_temp));
1797 71474 : if (!val->representation().IsSmi()) result = AssignEnvironment(result);
1798 71474 : return result;
1799 : }
1800 : }
1801 185130 : } else if (from.IsDouble()) {
1802 35969 : if (to.IsTagged()) {
1803 : info()->MarkAsDeferredCalling();
1804 26952 : LOperand* value = UseRegister(val);
1805 26953 : LOperand* temp = TempRegister();
1806 26952 : LUnallocated* result_temp = TempRegister();
1807 : LNumberTagD* result = new(zone()) LNumberTagD(value, temp);
1808 26953 : return AssignPointerMap(Define(result, result_temp));
1809 9017 : } else if (to.IsSmi()) {
1810 81 : LOperand* value = UseRegister(val);
1811 : return AssignEnvironment(
1812 162 : DefineAsRegister(new(zone()) LDoubleToSmi(value)));
1813 : } else {
1814 : DCHECK(to.IsInteger32());
1815 8936 : LOperand* value = UseRegister(val);
1816 8936 : LInstruction* result = DefineAsRegister(new(zone()) LDoubleToI(value));
1817 8936 : if (!instr->CanTruncateToInt32()) result = AssignEnvironment(result);
1818 8936 : return result;
1819 : }
1820 149161 : } else if (from.IsInteger32()) {
1821 : info()->MarkAsDeferredCalling();
1822 149161 : if (to.IsTagged()) {
1823 218608 : if (!instr->CheckFlag(HValue::kCanOverflow)) {
1824 91799 : LOperand* value = UseRegister(val);
1825 91799 : return DefineAsRegister(new(zone()) LSmiTag(value));
1826 779 : } else if (val->CheckFlag(HInstruction::kUint32)) {
1827 779 : LOperand* value = UseRegister(val);
1828 779 : LOperand* temp1 = TempRegister();
1829 : LOperand* temp2 = FixedTemp(xmm1);
1830 : LNumberTagU* result = new(zone()) LNumberTagU(value, temp1, temp2);
1831 779 : 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 56583 : } else if (to.IsSmi()) {
1840 33451 : LOperand* value = UseRegister(val);
1841 33451 : LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
1842 33452 : if (instr->CheckFlag(HValue::kCanOverflow)) {
1843 : result = AssignEnvironment(result);
1844 : }
1845 33452 : return result;
1846 : } else {
1847 : DCHECK(to.IsDouble());
1848 23132 : if (val->CheckFlag(HInstruction::kUint32)) {
1849 1300 : return DefineAsRegister(new(zone()) LUint32ToDouble(UseRegister(val)));
1850 : } else {
1851 22482 : LOperand* value = Use(val);
1852 22481 : return DefineAsRegister(new(zone()) LInteger32ToDouble(value));
1853 : }
1854 : }
1855 : }
1856 0 : UNREACHABLE();
1857 : return NULL;
1858 : }
1859 :
1860 :
1861 91013 : LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
1862 91013 : LOperand* value = UseRegisterAtStart(instr->value());
1863 91013 : LInstruction* result = new(zone()) LCheckNonSmi(value);
1864 91012 : if (!instr->value()->type().IsHeapObject()) {
1865 : result = AssignEnvironment(result);
1866 : }
1867 91014 : 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 2367 : LInstruction* LChunkBuilder::DoCheckArrayBufferNotNeutered(
1878 : HCheckArrayBufferNotNeutered* instr) {
1879 2367 : LOperand* view = UseRegisterAtStart(instr->value());
1880 : LCheckArrayBufferNotNeutered* result =
1881 2367 : new (zone()) LCheckArrayBufferNotNeutered(view);
1882 2367 : return AssignEnvironment(result);
1883 : }
1884 :
1885 :
1886 43089 : LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
1887 43089 : LOperand* value = UseRegisterAtStart(instr->value());
1888 43089 : LCheckInstanceType* result = new(zone()) LCheckInstanceType(value);
1889 43089 : return AssignEnvironment(result);
1890 : }
1891 :
1892 :
1893 36148 : LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
1894 36148 : LOperand* value = UseRegisterAtStart(instr->value());
1895 72296 : return AssignEnvironment(new(zone()) LCheckValue(value));
1896 : }
1897 :
1898 :
1899 269703 : LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
1900 389982 : if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
1901 75391 : LOperand* value = UseRegisterAtStart(instr->value());
1902 : LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value));
1903 75391 : if (instr->HasMigrationTarget()) {
1904 : info()->MarkAsDeferredCalling();
1905 1358 : result = AssignPointerMap(result);
1906 : }
1907 75391 : 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 365100 : LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
1931 767405 : LOperand* context = info()->IsStub() ? UseFixed(instr->context(), rsi) : NULL;
1932 365101 : LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
1933 : return new(zone()) LReturn(
1934 730205 : UseFixed(instr->value(), rax), context, parameter_count);
1935 : }
1936 :
1937 :
1938 3593347 : LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
1939 : Representation r = instr->representation();
1940 3593347 : if (r.IsSmi()) {
1941 4007233 : return DefineAsRegister(new(zone()) LConstantS);
1942 3179462 : } else if (r.IsInteger32()) {
1943 510148 : return DefineAsRegister(new(zone()) LConstantI);
1944 2669314 : } else if (r.IsDouble()) {
1945 44019 : return DefineAsRegister(new (zone()) LConstantD);
1946 2625295 : } else if (r.IsExternal()) {
1947 8077 : return DefineAsRegister(new(zone()) LConstantE);
1948 2617218 : } else if (r.IsTagged()) {
1949 2617216 : return DefineAsRegister(new(zone()) LConstantT);
1950 : } else {
1951 0 : UNREACHABLE();
1952 : return NULL;
1953 : }
1954 : }
1955 :
1956 :
1957 608190 : LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
1958 304095 : LOperand* context = UseRegisterAtStart(instr->value());
1959 : LInstruction* result =
1960 608190 : DefineAsRegister(new(zone()) LLoadContextSlot(context));
1961 304095 : if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1962 : result = AssignEnvironment(result);
1963 : }
1964 304095 : return result;
1965 : }
1966 :
1967 :
1968 140322 : LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
1969 : LOperand* context;
1970 : LOperand* value;
1971 : LOperand* temp;
1972 70161 : context = UseRegister(instr->context());
1973 70161 : if (instr->NeedsWriteBarrier()) {
1974 38597 : value = UseTempRegister(instr->value());
1975 38597 : temp = TempRegister();
1976 : } else {
1977 31564 : value = UseRegister(instr->value());
1978 : temp = NULL;
1979 : }
1980 70161 : LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
1981 70161 : if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
1982 : result = AssignEnvironment(result);
1983 : }
1984 70161 : return result;
1985 : }
1986 :
1987 :
1988 245076 : 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 245076 : if (instr->access().IsExternalMemory() &&
1992 490152 : instr->access().offset() == 0 &&
1993 245076 : (instr->access().representation().IsSmi() ||
1994 245076 : instr->access().representation().IsTagged() ||
1995 245076 : instr->access().representation().IsHeapObject() ||
1996 245076 : instr->access().representation().IsExternal())) {
1997 0 : LOperand* obj = UseRegisterOrConstantAtStart(instr->object());
1998 245078 : return DefineFixed(new(zone()) LLoadNamedField(obj), rax);
1999 : }
2000 245076 : LOperand* obj = UseRegisterAtStart(instr->object());
2001 245077 : 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 5282 : LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
2013 10564 : return DefineAsRegister(new(zone()) LLoadRoot);
2014 : }
2015 :
2016 :
2017 25090 : 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 25090 : BitVector* dehoisted_key_ids = chunk_->GetDehoistedKeyIds();
2024 12545 : if (dehoisted_key_ids->Contains(candidate->id())) return;
2025 : dehoisted_key_ids->Add(candidate->id());
2026 10801 : if (!candidate->IsPhi()) return;
2027 3418 : for (int i = 0; i < candidate->OperandCount(); ++i) {
2028 3418 : FindDehoistedKeyDefinitions(candidate->OperandAt(i));
2029 : }
2030 : }
2031 :
2032 :
2033 200577 : 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 51188 : 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 51188 : if ((kPointerSize == kInt64Size) && instr->IsDehoisted()) {
2053 7916 : FindDehoistedKeyDefinitions(instr->key());
2054 : }
2055 :
2056 51188 : if (!instr->is_fixed_typed_array()) {
2057 49161 : LOperand* obj = UseRegisterAtStart(instr->elements());
2058 103285 : 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 51188 : if (instr->is_fixed_typed_array()) {
2073 : // see LCodeGen::DoLoadKeyedExternalArray
2074 2231 : needs_environment = elements_kind == UINT32_ELEMENTS &&
2075 204 : !instr->CheckFlag(HInstruction::kUint32);
2076 : } else {
2077 : // see LCodeGen::DoLoadKeyedFixedDoubleArray and
2078 : // LCodeGen::DoLoadKeyedFixedArray
2079 : needs_environment =
2080 96174 : instr->RequiresHoleCheck() ||
2081 2938 : (instr->hole_mode() == CONVERT_HOLE_TO_UNDEFINED && info()->IsStub());
2082 : }
2083 :
2084 51188 : if (needs_environment) {
2085 : result = AssignEnvironment(result);
2086 : }
2087 51188 : return result;
2088 : }
2089 :
2090 :
2091 57451 : LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
2092 : ElementsKind elements_kind = instr->elements_kind();
2093 :
2094 28726 : if ((kPointerSize == kInt64Size) && instr->IsDehoisted()) {
2095 1211 : FindDehoistedKeyDefinitions(instr->key());
2096 : }
2097 :
2098 28725 : if (!instr->is_fixed_typed_array()) {
2099 : DCHECK(instr->elements()->representation().IsTagged());
2100 26933 : 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 26933 : if (value_representation.IsDouble()) {
2107 6672 : object = UseRegisterAtStart(instr->elements());
2108 6672 : val = UseRegisterAtStart(instr->value());
2109 6672 : key = UseRegisterOrConstantAtStart(instr->key());
2110 : } else {
2111 : DCHECK(value_representation.IsSmiOrTagged() ||
2112 : value_representation.IsInteger32());
2113 20261 : if (needs_write_barrier) {
2114 6617 : object = UseTempRegister(instr->elements());
2115 6617 : val = UseTempRegister(instr->value());
2116 6617 : key = UseTempRegister(instr->key());
2117 : } else {
2118 13644 : object = UseRegisterAtStart(instr->elements());
2119 13645 : val = UseRegisterOrConstantAtStart(instr->value());
2120 13645 : key = UseRegisterOrConstantAtStart(instr->key());
2121 : }
2122 : }
2123 :
2124 28725 : 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 1792 : bool val_is_temp_register = elements_kind == UINT8_CLAMPED_ELEMENTS ||
2134 1792 : elements_kind == FLOAT32_ELEMENTS;
2135 : LOperand* val = val_is_temp_register ? UseTempRegister(instr->value())
2136 3584 : : UseRegister(instr->value());
2137 : LOperand* key = NULL;
2138 : if (kPointerSize == kInt64Size) {
2139 1792 : 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 1792 : LOperand* backing_store = UseRegister(instr->elements());
2148 1792 : LOperand* backing_store_owner = UseAny(instr->backing_store_owner());
2149 1792 : return new (zone()) LStoreKeyed(backing_store, key, val, backing_store_owner);
2150 : }
2151 :
2152 :
2153 755 : LInstruction* LChunkBuilder::DoTransitionElementsKind(
2154 755 : HTransitionElementsKind* instr) {
2155 755 : if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
2156 350 : LOperand* object = UseRegister(instr->object());
2157 350 : LOperand* new_map_reg = TempRegister();
2158 350 : LOperand* temp_reg = TempRegister();
2159 755 : LTransitionElementsKind* result = new(zone()) LTransitionElementsKind(
2160 : object, NULL, new_map_reg, temp_reg);
2161 350 : return result;
2162 : } else {
2163 405 : LOperand* object = UseFixed(instr->object(), rax);
2164 405 : LOperand* context = UseFixed(instr->context(), rsi);
2165 : LTransitionElementsKind* result =
2166 : new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
2167 405 : return MarkAsCall(result, instr);
2168 : }
2169 : }
2170 :
2171 :
2172 38 : LInstruction* LChunkBuilder::DoTrapAllocationMemento(
2173 : HTrapAllocationMemento* instr) {
2174 38 : LOperand* object = UseRegister(instr->object());
2175 38 : LOperand* temp = TempRegister();
2176 : LTrapAllocationMemento* result =
2177 38 : new(zone()) LTrapAllocationMemento(object, temp);
2178 38 : return AssignEnvironment(result);
2179 : }
2180 :
2181 :
2182 2573 : LInstruction* LChunkBuilder::DoMaybeGrowElements(HMaybeGrowElements* instr) {
2183 5146 : info()->MarkAsDeferredCalling();
2184 2573 : LOperand* context = UseFixed(instr->context(), rsi);
2185 2573 : LOperand* object = Use(instr->object());
2186 2573 : LOperand* elements = Use(instr->elements());
2187 2573 : LOperand* key = UseRegisterOrConstant(instr->key());
2188 2573 : LOperand* current_capacity = UseRegisterOrConstant(instr->current_capacity());
2189 :
2190 : LMaybeGrowElements* result = new (zone())
2191 : LMaybeGrowElements(context, object, elements, key, current_capacity);
2192 2573 : DefineFixed(result, rax);
2193 2573 : return AssignPointerMap(AssignEnvironment(result));
2194 : }
2195 :
2196 :
2197 359243 : LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
2198 : bool is_in_object = instr->access().IsInobject();
2199 179621 : bool is_external_location = instr->access().IsExternalMemory() &&
2200 179621 : instr->access().offset() == 0;
2201 179621 : bool needs_write_barrier = instr->NeedsWriteBarrier();
2202 190288 : bool needs_write_barrier_for_map = instr->has_transition() &&
2203 : instr->NeedsWriteBarrierForMap();
2204 :
2205 : LOperand* obj;
2206 179622 : if (needs_write_barrier) {
2207 : obj = is_in_object
2208 : ? UseRegister(instr->object())
2209 30232 : : UseTempRegister(instr->object());
2210 164506 : } 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 329012 : : UseRegisterAtStart(instr->object());
2219 : }
2220 :
2221 103478 : bool can_be_constant = instr->value()->IsConstant() &&
2222 386029 : HConstant::cast(instr->value())->NotInNewSpace() &&
2223 : !instr->field_representation().IsDouble();
2224 :
2225 : LOperand* val;
2226 179622 : if (needs_write_barrier) {
2227 15115 : val = UseTempRegister(instr->value());
2228 164507 : } else if (is_external_location) {
2229 0 : val = UseFixed(instr->value(), rax);
2230 164507 : } else if (can_be_constant) {
2231 102385 : val = UseRegisterOrConstant(instr->value());
2232 62122 : } else if (instr->field_representation().IsDouble()) {
2233 262 : val = UseRegisterAtStart(instr->value());
2234 : } else {
2235 61860 : 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 343806 : LOperand* temp = (!is_in_object || needs_write_barrier ||
2241 197896 : needs_write_barrier_for_map) ? TempRegister() : NULL;
2242 :
2243 359238 : return new(zone()) LStoreNamedField(obj, val, temp);
2244 : }
2245 :
2246 :
2247 21248 : LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
2248 21248 : LOperand* context = UseFixed(instr->context(), rsi);
2249 21248 : LOperand* left = UseFixed(instr->left(), rdx);
2250 21248 : LOperand* right = UseFixed(instr->right(), rax);
2251 : return MarkAsCall(
2252 42496 : DefineFixed(new(zone()) LStringAdd(context, left, right), rax), instr);
2253 : }
2254 :
2255 :
2256 373 : LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
2257 373 : LOperand* string = UseTempRegister(instr->string());
2258 373 : LOperand* index = UseTempRegister(instr->index());
2259 373 : LOperand* context = UseAny(instr->context());
2260 : LStringCharCodeAt* result =
2261 373 : new(zone()) LStringCharCodeAt(context, string, index);
2262 373 : return AssignPointerMap(DefineAsRegister(result));
2263 : }
2264 :
2265 :
2266 470 : LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
2267 470 : LOperand* char_code = UseRegister(instr->value());
2268 470 : LOperand* context = UseAny(instr->context());
2269 : LStringCharFromCode* result =
2270 470 : new(zone()) LStringCharFromCode(context, char_code);
2271 470 : return AssignPointerMap(DefineAsRegister(result));
2272 : }
2273 :
2274 :
2275 51277 : LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
2276 : LOperand* size = instr->size()->IsConstant() ? UseConstant(instr->size())
2277 33297 : : UseRegister(instr->size());
2278 25639 : if (instr->IsAllocationFolded()) {
2279 4904 : LOperand* temp = TempRegister();
2280 46373 : LFastAllocate* result = new (zone()) LFastAllocate(size, temp);
2281 4903 : return DefineAsRegister(result);
2282 : } else {
2283 : info()->MarkAsDeferredCalling();
2284 20735 : LOperand* context = UseAny(instr->context());
2285 20735 : LOperand* temp = TempRegister();
2286 : LAllocate* result = new (zone()) LAllocate(context, size, temp);
2287 20735 : return AssignPointerMap(DefineAsRegister(result));
2288 : }
2289 : }
2290 :
2291 :
2292 2365 : LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
2293 : DCHECK(argument_count_ == 0);
2294 2365 : allocator_->MarkAsOsrEntry();
2295 2365 : current_block_->last_environment()->set_ast_id(instr->ast_id());
2296 4730 : return AssignEnvironment(new(zone()) LOsrEntry);
2297 : }
2298 :
2299 :
2300 1376474 : LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
2301 917650 : LParameter* result = new(zone()) LParameter;
2302 458824 : if (instr->kind() == HParameter::STACK_PARAMETER) {
2303 843446 : int spill_index = chunk()->GetParameterStackSlot(instr->index());
2304 421733 : return DefineAsSpilled(result, spill_index);
2305 : } else {
2306 : DCHECK(info()->IsStub());
2307 : CallInterfaceDescriptor descriptor = graph()->descriptor();
2308 37101 : int index = static_cast<int>(instr->index());
2309 37101 : Register reg = descriptor.GetRegisterParameter(index);
2310 37101 : return DefineFixed(result, reg);
2311 : }
2312 : }
2313 :
2314 :
2315 14075 : 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 14075 : if (instr->environment()->is_parameter_index(env_index)) {
2321 17774 : spill_index = chunk()->GetParameterStackSlot(env_index);
2322 : } else {
2323 10376 : spill_index = env_index - instr->environment()->first_local_index();
2324 10376 : if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
2325 0 : Retry(kTooManySpillSlotsNeededForOSR);
2326 : spill_index = 0;
2327 : }
2328 10376 : spill_index += StandardFrameConstants::kFixedSlotCount;
2329 : }
2330 14075 : return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
2331 : }
2332 :
2333 :
2334 366429 : 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 366429 : return NULL;
2340 : }
2341 :
2342 :
2343 10949 : LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
2344 10949 : instr->ReplayEnvironment(current_block_->last_environment());
2345 :
2346 : // There are no real uses of a captured object.
2347 10949 : return NULL;
2348 : }
2349 :
2350 :
2351 635 : LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
2352 1270 : info()->MarkAsRequiresFrame();
2353 635 : LOperand* args = UseRegister(instr->arguments());
2354 : LOperand* length;
2355 : LOperand* index;
2356 919 : if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
2357 184 : length = UseRegisterOrConstant(instr->length());
2358 184 : index = UseOrConstant(instr->index());
2359 : } else {
2360 451 : length = UseTempRegister(instr->length());
2361 451 : index = Use(instr->index());
2362 : }
2363 635 : return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
2364 : }
2365 :
2366 :
2367 38509 : LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
2368 38509 : LOperand* context = UseFixed(instr->context(), rsi);
2369 38509 : LOperand* value = UseFixed(instr->value(), rbx);
2370 38509 : LTypeof* result = new(zone()) LTypeof(context, value);
2371 38509 : return MarkAsCall(DefineFixed(result, rax), instr);
2372 : }
2373 :
2374 :
2375 56093 : LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
2376 112186 : return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value()));
2377 : }
2378 :
2379 :
2380 4726034 : LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
2381 4726034 : instr->ReplayEnvironment(current_block_->last_environment());
2382 4726048 : return NULL;
2383 : }
2384 :
2385 :
2386 581906 : LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
2387 581912 : info()->MarkAsDeferredCalling();
2388 290953 : if (instr->is_function_entry()) {
2389 259704 : LOperand* context = UseFixed(instr->context(), rsi);
2390 259709 : return MarkAsCall(new(zone()) LStackCheck(context), instr);
2391 : } else {
2392 : DCHECK(instr->is_backwards_branch());
2393 31249 : LOperand* context = UseAny(instr->context());
2394 : return AssignEnvironment(
2395 62498 : AssignPointerMap(new(zone()) LStackCheck(context)));
2396 : }
2397 : }
2398 :
2399 :
2400 427626 : LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
2401 106731 : HEnvironment* outer = current_block_->last_environment();
2402 : outer->set_ast_id(instr->ReturnId());
2403 106731 : HConstant* undefined = graph()->GetConstantUndefined();
2404 : HEnvironment* inner = outer->CopyForInlining(
2405 : instr->closure(), instr->arguments_count(), instr->function(), undefined,
2406 106731 : instr->inlining_kind(), instr->syntactic_tail_call_mode());
2407 : // Only replay binding of arguments object if it wasn't removed from graph.
2408 107082 : if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) {
2409 353 : inner->Bind(instr->arguments_var(), instr->arguments_object());
2410 : }
2411 : inner->BindContext(instr->closure_context());
2412 : inner->set_entry(instr);
2413 106730 : current_block_->UpdateEnvironment(inner);
2414 106730 : return NULL;
2415 : }
2416 :
2417 :
2418 557006 : LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
2419 : LInstruction* pop = NULL;
2420 :
2421 1114012 : HEnvironment* env = current_block_->last_environment();
2422 :
2423 557006 : if (env->entry()->arguments_pushed()) {
2424 246 : int argument_count = env->arguments_environment()->parameter_count();
2425 246 : pop = new(zone()) LDrop(argument_count);
2426 : DCHECK(instr->argument_delta() == -argument_count);
2427 : }
2428 :
2429 : HEnvironment* outer = current_block_->last_environment()->
2430 1114012 : DiscardInlined(false);
2431 557006 : current_block_->UpdateEnvironment(outer);
2432 :
2433 557006 : 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 1738 : LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
2446 1738 : LOperand* map = UseRegister(instr->map());
2447 : return AssignEnvironment(DefineAsRegister(
2448 5214 : 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
|