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 #if V8_TARGET_ARCH_X87 6 7 #include "src/crankshaft/x87/lithium-codegen-x87.h" 8 9 #include "src/base/bits.h" 10 #include "src/code-factory.h" 11 #include "src/code-stubs.h" 12 #include "src/codegen.h" 13 #include "src/crankshaft/hydrogen-osr.h" 14 #include "src/deoptimizer.h" 15 #include "src/ic/ic.h" 16 #include "src/ic/stub-cache.h" 17 #include "src/profiler/cpu-profiler.h" 18 #include "src/x87/frames-x87.h" 19 20 namespace v8 { 21 namespace internal { 22 23 24 // When invoking builtins, we need to record the safepoint in the middle of 25 // the invoke instruction sequence generated by the macro assembler. 26 class SafepointGenerator final : public CallWrapper { 27 public: 28 SafepointGenerator(LCodeGen* codegen, 29 LPointerMap* pointers, 30 Safepoint::DeoptMode mode) 31 : codegen_(codegen), 32 pointers_(pointers), 33 deopt_mode_(mode) {} 34 virtual ~SafepointGenerator() {} 35 36 void BeforeCall(int call_size) const override {} 37 38 void AfterCall() const override { 39 codegen_->RecordSafepoint(pointers_, deopt_mode_); 40 } 41 42 private: 43 LCodeGen* codegen_; 44 LPointerMap* pointers_; 45 Safepoint::DeoptMode deopt_mode_; 46 }; 47 48 49 #define __ masm()-> 50 51 bool LCodeGen::GenerateCode() { 52 LPhase phase("Z_Code generation", chunk()); 53 DCHECK(is_unused()); 54 status_ = GENERATING; 55 56 // Open a frame scope to indicate that there is a frame on the stack. The 57 // MANUAL indicates that the scope shouldn't actually generate code to set up 58 // the frame (that is done in GeneratePrologue). 59 FrameScope frame_scope(masm_, StackFrame::MANUAL); 60 61 support_aligned_spilled_doubles_ = info()->IsOptimizing(); 62 63 dynamic_frame_alignment_ = info()->IsOptimizing() && 64 ((chunk()->num_double_slots() > 2 && 65 !chunk()->graph()->is_recursive()) || 66 !info()->osr_ast_id().IsNone()); 67 68 return GeneratePrologue() && 69 GenerateBody() && 70 GenerateDeferredCode() && 71 GenerateJumpTable() && 72 GenerateSafepointTable(); 73 } 74 75 76 void LCodeGen::FinishCode(Handle<Code> code) { 77 DCHECK(is_done()); 78 code->set_stack_slots(GetStackSlotCount()); 79 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); 80 PopulateDeoptimizationData(code); 81 if (info()->ShouldEnsureSpaceForLazyDeopt()) { 82 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code); 83 } 84 } 85 86 87 #ifdef _MSC_VER 88 void LCodeGen::MakeSureStackPagesMapped(int offset) { 89 const int kPageSize = 4 * KB; 90 for (offset -= kPageSize; offset > 0; offset -= kPageSize) { 91 __ mov(Operand(esp, offset), eax); 92 } 93 } 94 #endif 95 96 97 bool LCodeGen::GeneratePrologue() { 98 DCHECK(is_generating()); 99 100 if (info()->IsOptimizing()) { 101 ProfileEntryHookStub::MaybeCallEntryHook(masm_); 102 103 #ifdef DEBUG 104 if (strlen(FLAG_stop_at) > 0 && 105 info_->literal()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { 106 __ int3(); 107 } 108 #endif 109 110 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) { 111 // Move state of dynamic frame alignment into edx. 112 __ Move(edx, Immediate(kNoAlignmentPadding)); 113 114 Label do_not_pad, align_loop; 115 STATIC_ASSERT(kDoubleSize == 2 * kPointerSize); 116 // Align esp + 4 to a multiple of 2 * kPointerSize. 117 __ test(esp, Immediate(kPointerSize)); 118 __ j(not_zero, &do_not_pad, Label::kNear); 119 __ push(Immediate(0)); 120 __ mov(ebx, esp); 121 __ mov(edx, Immediate(kAlignmentPaddingPushed)); 122 // Copy arguments, receiver, and return address. 123 __ mov(ecx, Immediate(scope()->num_parameters() + 2)); 124 125 __ bind(&align_loop); 126 __ mov(eax, Operand(ebx, 1 * kPointerSize)); 127 __ mov(Operand(ebx, 0), eax); 128 __ add(Operand(ebx), Immediate(kPointerSize)); 129 __ dec(ecx); 130 __ j(not_zero, &align_loop, Label::kNear); 131 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue)); 132 __ bind(&do_not_pad); 133 } 134 } 135 136 info()->set_prologue_offset(masm_->pc_offset()); 137 if (NeedsEagerFrame()) { 138 DCHECK(!frame_is_built_); 139 frame_is_built_ = true; 140 if (info()->IsStub()) { 141 __ StubPrologue(); 142 } else { 143 __ Prologue(info()->GeneratePreagedPrologue()); 144 } 145 } 146 147 if (info()->IsOptimizing() && 148 dynamic_frame_alignment_ && 149 FLAG_debug_code) { 150 __ test(esp, Immediate(kPointerSize)); 151 __ Assert(zero, kFrameIsExpectedToBeAligned); 152 } 153 154 // Reserve space for the stack slots needed by the code. 155 int slots = GetStackSlotCount(); 156 DCHECK(slots != 0 || !info()->IsOptimizing()); 157 if (slots > 0) { 158 if (slots == 1) { 159 if (dynamic_frame_alignment_) { 160 __ push(edx); 161 } else { 162 __ push(Immediate(kNoAlignmentPadding)); 163 } 164 } else { 165 if (FLAG_debug_code) { 166 __ sub(Operand(esp), Immediate(slots * kPointerSize)); 167 #ifdef _MSC_VER 168 MakeSureStackPagesMapped(slots * kPointerSize); 169 #endif 170 __ push(eax); 171 __ mov(Operand(eax), Immediate(slots)); 172 Label loop; 173 __ bind(&loop); 174 __ mov(MemOperand(esp, eax, times_4, 0), 175 Immediate(kSlotsZapValue)); 176 __ dec(eax); 177 __ j(not_zero, &loop); 178 __ pop(eax); 179 } else { 180 __ sub(Operand(esp), Immediate(slots * kPointerSize)); 181 #ifdef _MSC_VER 182 MakeSureStackPagesMapped(slots * kPointerSize); 183 #endif 184 } 185 186 if (support_aligned_spilled_doubles_) { 187 Comment(";;; Store dynamic frame alignment tag for spilled doubles"); 188 // Store dynamic frame alignment state in the first local. 189 int offset = JavaScriptFrameConstants::kDynamicAlignmentStateOffset; 190 if (dynamic_frame_alignment_) { 191 __ mov(Operand(ebp, offset), edx); 192 } else { 193 __ mov(Operand(ebp, offset), Immediate(kNoAlignmentPadding)); 194 } 195 } 196 } 197 } 198 199 // Initailize FPU state. 200 __ fninit(); 201 202 return !is_aborted(); 203 } 204 205 206 void LCodeGen::DoPrologue(LPrologue* instr) { 207 Comment(";;; Prologue begin"); 208 209 // Possibly allocate a local context. 210 if (info_->num_heap_slots() > 0) { 211 Comment(";;; Allocate local context"); 212 bool need_write_barrier = true; 213 // Argument to NewContext is the function, which is still in edi. 214 int slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 215 Safepoint::DeoptMode deopt_mode = Safepoint::kNoLazyDeopt; 216 if (info()->scope()->is_script_scope()) { 217 __ push(edi); 218 __ Push(info()->scope()->GetScopeInfo(info()->isolate())); 219 __ CallRuntime(Runtime::kNewScriptContext); 220 deopt_mode = Safepoint::kLazyDeopt; 221 } else if (slots <= FastNewContextStub::kMaximumSlots) { 222 FastNewContextStub stub(isolate(), slots); 223 __ CallStub(&stub); 224 // Result of FastNewContextStub is always in new space. 225 need_write_barrier = false; 226 } else { 227 __ push(edi); 228 __ CallRuntime(Runtime::kNewFunctionContext); 229 } 230 RecordSafepoint(deopt_mode); 231 232 // Context is returned in eax. It replaces the context passed to us. 233 // It's saved in the stack and kept live in esi. 234 __ mov(esi, eax); 235 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax); 236 237 // Copy parameters into context if necessary. 238 int num_parameters = scope()->num_parameters(); 239 int first_parameter = scope()->has_this_declaration() ? -1 : 0; 240 for (int i = first_parameter; i < num_parameters; i++) { 241 Variable* var = (i == -1) ? scope()->receiver() : scope()->parameter(i); 242 if (var->IsContextSlot()) { 243 int parameter_offset = StandardFrameConstants::kCallerSPOffset + 244 (num_parameters - 1 - i) * kPointerSize; 245 // Load parameter from stack. 246 __ mov(eax, Operand(ebp, parameter_offset)); 247 // Store it in the context. 248 int context_offset = Context::SlotOffset(var->index()); 249 __ mov(Operand(esi, context_offset), eax); 250 // Update the write barrier. This clobbers eax and ebx. 251 if (need_write_barrier) { 252 __ RecordWriteContextSlot(esi, context_offset, eax, ebx, 253 kDontSaveFPRegs); 254 } else if (FLAG_debug_code) { 255 Label done; 256 __ JumpIfInNewSpace(esi, eax, &done, Label::kNear); 257 __ Abort(kExpectedNewSpaceObject); 258 __ bind(&done); 259 } 260 } 261 } 262 Comment(";;; End allocate local context"); 263 } 264 265 Comment(";;; Prologue end"); 266 } 267 268 269 void LCodeGen::GenerateOsrPrologue() { 270 // Generate the OSR entry prologue at the first unknown OSR value, or if there 271 // are none, at the OSR entrypoint instruction. 272 if (osr_pc_offset_ >= 0) return; 273 274 osr_pc_offset_ = masm()->pc_offset(); 275 276 // Move state of dynamic frame alignment into edx. 277 __ Move(edx, Immediate(kNoAlignmentPadding)); 278 279 if (support_aligned_spilled_doubles_ && dynamic_frame_alignment_) { 280 Label do_not_pad, align_loop; 281 // Align ebp + 4 to a multiple of 2 * kPointerSize. 282 __ test(ebp, Immediate(kPointerSize)); 283 __ j(zero, &do_not_pad, Label::kNear); 284 __ push(Immediate(0)); 285 __ mov(ebx, esp); 286 __ mov(edx, Immediate(kAlignmentPaddingPushed)); 287 288 // Move all parts of the frame over one word. The frame consists of: 289 // unoptimized frame slots, alignment state, context, frame pointer, return 290 // address, receiver, and the arguments. 291 __ mov(ecx, Immediate(scope()->num_parameters() + 292 5 + graph()->osr()->UnoptimizedFrameSlots())); 293 294 __ bind(&align_loop); 295 __ mov(eax, Operand(ebx, 1 * kPointerSize)); 296 __ mov(Operand(ebx, 0), eax); 297 __ add(Operand(ebx), Immediate(kPointerSize)); 298 __ dec(ecx); 299 __ j(not_zero, &align_loop, Label::kNear); 300 __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue)); 301 __ sub(Operand(ebp), Immediate(kPointerSize)); 302 __ bind(&do_not_pad); 303 } 304 305 // Save the first local, which is overwritten by the alignment state. 306 Operand alignment_loc = MemOperand(ebp, -3 * kPointerSize); 307 __ push(alignment_loc); 308 309 // Set the dynamic frame alignment state. 310 __ mov(alignment_loc, edx); 311 312 // Adjust the frame size, subsuming the unoptimized frame into the 313 // optimized frame. 314 int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots(); 315 DCHECK(slots >= 1); 316 __ sub(esp, Immediate((slots - 1) * kPointerSize)); 317 318 // Initailize FPU state. 319 __ fninit(); 320 } 321 322 323 void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) { 324 if (instr->IsCall()) { 325 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 326 } 327 if (!instr->IsLazyBailout() && !instr->IsGap()) { 328 safepoints_.BumpLastLazySafepointIndex(); 329 } 330 FlushX87StackIfNecessary(instr); 331 } 332 333 334 void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) { 335 // When return from function call, FPU should be initialized again. 336 if (instr->IsCall() && instr->ClobbersDoubleRegisters(isolate())) { 337 bool double_result = instr->HasDoubleRegisterResult(); 338 if (double_result) { 339 __ lea(esp, Operand(esp, -kDoubleSize)); 340 __ fstp_d(Operand(esp, 0)); 341 } 342 __ fninit(); 343 if (double_result) { 344 __ fld_d(Operand(esp, 0)); 345 __ lea(esp, Operand(esp, kDoubleSize)); 346 } 347 } 348 if (instr->IsGoto()) { 349 x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr), this); 350 } else if (FLAG_debug_code && FLAG_enable_slow_asserts && 351 !instr->IsGap() && !instr->IsReturn()) { 352 if (instr->ClobbersDoubleRegisters(isolate())) { 353 if (instr->HasDoubleRegisterResult()) { 354 DCHECK_EQ(1, x87_stack_.depth()); 355 } else { 356 DCHECK_EQ(0, x87_stack_.depth()); 357 } 358 } 359 __ VerifyX87StackDepth(x87_stack_.depth()); 360 } 361 } 362 363 364 bool LCodeGen::GenerateJumpTable() { 365 if (!jump_table_.length()) return !is_aborted(); 366 367 Label needs_frame; 368 Comment(";;; -------------------- Jump table --------------------"); 369 370 for (int i = 0; i < jump_table_.length(); i++) { 371 Deoptimizer::JumpTableEntry* table_entry = &jump_table_[i]; 372 __ bind(&table_entry->label); 373 Address entry = table_entry->address; 374 DeoptComment(table_entry->deopt_info); 375 if (table_entry->needs_frame) { 376 DCHECK(!info()->saves_caller_doubles()); 377 __ push(Immediate(ExternalReference::ForDeoptEntry(entry))); 378 __ call(&needs_frame); 379 } else { 380 __ call(entry, RelocInfo::RUNTIME_ENTRY); 381 } 382 info()->LogDeoptCallPosition(masm()->pc_offset(), 383 table_entry->deopt_info.inlining_id); 384 } 385 if (needs_frame.is_linked()) { 386 __ bind(&needs_frame); 387 388 /* stack layout 389 4: entry address 390 3: return address <-- esp 391 2: garbage 392 1: garbage 393 0: garbage 394 */ 395 __ sub(esp, Immediate(kPointerSize)); // Reserve space for stub marker. 396 __ push(MemOperand(esp, kPointerSize)); // Copy return address. 397 __ push(MemOperand(esp, 3 * kPointerSize)); // Copy entry address. 398 399 /* stack layout 400 4: entry address 401 3: return address 402 2: garbage 403 1: return address 404 0: entry address <-- esp 405 */ 406 __ mov(MemOperand(esp, 4 * kPointerSize), ebp); // Save ebp. 407 408 // Copy context. 409 __ mov(ebp, MemOperand(ebp, StandardFrameConstants::kContextOffset)); 410 __ mov(MemOperand(esp, 3 * kPointerSize), ebp); 411 // Fill ebp with the right stack frame address. 412 __ lea(ebp, MemOperand(esp, 4 * kPointerSize)); 413 414 // This variant of deopt can only be used with stubs. Since we don't 415 // have a function pointer to install in the stack frame that we're 416 // building, install a special marker there instead. 417 DCHECK(info()->IsStub()); 418 __ mov(MemOperand(esp, 2 * kPointerSize), 419 Immediate(Smi::FromInt(StackFrame::STUB))); 420 421 /* stack layout 422 4: old ebp 423 3: context pointer 424 2: stub marker 425 1: return address 426 0: entry address <-- esp 427 */ 428 __ ret(0); // Call the continuation without clobbering registers. 429 } 430 return !is_aborted(); 431 } 432 433 434 bool LCodeGen::GenerateDeferredCode() { 435 DCHECK(is_generating()); 436 if (deferred_.length() > 0) { 437 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { 438 LDeferredCode* code = deferred_[i]; 439 X87Stack copy(code->x87_stack()); 440 x87_stack_ = copy; 441 442 HValue* value = 443 instructions_->at(code->instruction_index())->hydrogen_value(); 444 RecordAndWritePosition( 445 chunk()->graph()->SourcePositionToScriptPosition(value->position())); 446 447 Comment(";;; <@%d,#%d> " 448 "-------------------- Deferred %s --------------------", 449 code->instruction_index(), 450 code->instr()->hydrogen_value()->id(), 451 code->instr()->Mnemonic()); 452 __ bind(code->entry()); 453 if (NeedsDeferredFrame()) { 454 Comment(";;; Build frame"); 455 DCHECK(!frame_is_built_); 456 DCHECK(info()->IsStub()); 457 frame_is_built_ = true; 458 // Build the frame in such a way that esi isn't trashed. 459 __ push(ebp); // Caller's frame pointer. 460 __ push(Operand(ebp, StandardFrameConstants::kContextOffset)); 461 __ push(Immediate(Smi::FromInt(StackFrame::STUB))); 462 __ lea(ebp, Operand(esp, 2 * kPointerSize)); 463 Comment(";;; Deferred code"); 464 } 465 code->Generate(); 466 if (NeedsDeferredFrame()) { 467 __ bind(code->done()); 468 Comment(";;; Destroy frame"); 469 DCHECK(frame_is_built_); 470 frame_is_built_ = false; 471 __ mov(esp, ebp); 472 __ pop(ebp); 473 } 474 __ jmp(code->exit()); 475 } 476 } 477 478 // Deferred code is the last part of the instruction sequence. Mark 479 // the generated code as done unless we bailed out. 480 if (!is_aborted()) status_ = DONE; 481 return !is_aborted(); 482 } 483 484 485 bool LCodeGen::GenerateSafepointTable() { 486 DCHECK(is_done()); 487 if (info()->ShouldEnsureSpaceForLazyDeopt()) { 488 // For lazy deoptimization we need space to patch a call after every call. 489 // Ensure there is always space for such patching, even if the code ends 490 // in a call. 491 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size(); 492 while (masm()->pc_offset() < target_offset) { 493 masm()->nop(); 494 } 495 } 496 safepoints_.Emit(masm(), GetStackSlotCount()); 497 return !is_aborted(); 498 } 499 500 501 Register LCodeGen::ToRegister(int code) const { 502 return Register::from_code(code); 503 } 504 505 506 X87Register LCodeGen::ToX87Register(int code) const { 507 return X87Register::from_code(code); 508 } 509 510 511 void LCodeGen::X87LoadForUsage(X87Register reg) { 512 DCHECK(x87_stack_.Contains(reg)); 513 x87_stack_.Fxch(reg); 514 x87_stack_.pop(); 515 } 516 517 518 void LCodeGen::X87LoadForUsage(X87Register reg1, X87Register reg2) { 519 DCHECK(x87_stack_.Contains(reg1)); 520 DCHECK(x87_stack_.Contains(reg2)); 521 if (reg1.is(reg2) && x87_stack_.depth() == 1) { 522 __ fld(x87_stack_.st(reg1)); 523 x87_stack_.push(reg1); 524 x87_stack_.pop(); 525 x87_stack_.pop(); 526 } else { 527 x87_stack_.Fxch(reg1, 1); 528 x87_stack_.Fxch(reg2); 529 x87_stack_.pop(); 530 x87_stack_.pop(); 531 } 532 } 533 534 535 int LCodeGen::X87Stack::GetLayout() { 536 int layout = stack_depth_; 537 for (int i = 0; i < stack_depth_; i++) { 538 layout |= (stack_[stack_depth_ - 1 - i].code() << ((i + 1) * 3)); 539 } 540 541 return layout; 542 } 543 544 545 void LCodeGen::X87Stack::Fxch(X87Register reg, int other_slot) { 546 DCHECK(is_mutable_); 547 DCHECK(Contains(reg) && stack_depth_ > other_slot); 548 int i = ArrayIndex(reg); 549 int st = st2idx(i); 550 if (st != other_slot) { 551 int other_i = st2idx(other_slot); 552 X87Register other = stack_[other_i]; 553 stack_[other_i] = reg; 554 stack_[i] = other; 555 if (st == 0) { 556 __ fxch(other_slot); 557 } else if (other_slot == 0) { 558 __ fxch(st); 559 } else { 560 __ fxch(st); 561 __ fxch(other_slot); 562 __ fxch(st); 563 } 564 } 565 } 566 567 568 int LCodeGen::X87Stack::st2idx(int pos) { 569 return stack_depth_ - pos - 1; 570 } 571 572 573 int LCodeGen::X87Stack::ArrayIndex(X87Register reg) { 574 for (int i = 0; i < stack_depth_; i++) { 575 if (stack_[i].is(reg)) return i; 576 } 577 UNREACHABLE(); 578 return -1; 579 } 580 581 582 bool LCodeGen::X87Stack::Contains(X87Register reg) { 583 for (int i = 0; i < stack_depth_; i++) { 584 if (stack_[i].is(reg)) return true; 585 } 586 return false; 587 } 588 589 590 void LCodeGen::X87Stack::Free(X87Register reg) { 591 DCHECK(is_mutable_); 592 DCHECK(Contains(reg)); 593 int i = ArrayIndex(reg); 594 int st = st2idx(i); 595 if (st > 0) { 596 // keep track of how fstp(i) changes the order of elements 597 int tos_i = st2idx(0); 598 stack_[i] = stack_[tos_i]; 599 } 600 pop(); 601 __ fstp(st); 602 } 603 604 605 void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) { 606 if (x87_stack_.Contains(dst)) { 607 x87_stack_.Fxch(dst); 608 __ fstp(0); 609 } else { 610 x87_stack_.push(dst); 611 } 612 X87Fld(src, opts); 613 } 614 615 616 void LCodeGen::X87Mov(X87Register dst, X87Register src, X87OperandType opts) { 617 if (x87_stack_.Contains(dst)) { 618 x87_stack_.Fxch(dst); 619 __ fstp(0); 620 x87_stack_.pop(); 621 // Push ST(i) onto the FPU register stack 622 __ fld(x87_stack_.st(src)); 623 x87_stack_.push(dst); 624 } else { 625 // Push ST(i) onto the FPU register stack 626 __ fld(x87_stack_.st(src)); 627 x87_stack_.push(dst); 628 } 629 } 630 631 632 void LCodeGen::X87Fld(Operand src, X87OperandType opts) { 633 DCHECK(!src.is_reg_only()); 634 switch (opts) { 635 case kX87DoubleOperand: 636 __ fld_d(src); 637 break; 638 case kX87FloatOperand: 639 __ fld_s(src); 640 break; 641 case kX87IntOperand: 642 __ fild_s(src); 643 break; 644 default: 645 UNREACHABLE(); 646 } 647 } 648 649 650 void LCodeGen::X87Mov(Operand dst, X87Register src, X87OperandType opts) { 651 DCHECK(!dst.is_reg_only()); 652 x87_stack_.Fxch(src); 653 switch (opts) { 654 case kX87DoubleOperand: 655 __ fst_d(dst); 656 break; 657 case kX87FloatOperand: 658 __ fst_s(dst); 659 break; 660 case kX87IntOperand: 661 __ fist_s(dst); 662 break; 663 default: 664 UNREACHABLE(); 665 } 666 } 667 668 669 void LCodeGen::X87Stack::PrepareToWrite(X87Register reg) { 670 DCHECK(is_mutable_); 671 if (Contains(reg)) { 672 Free(reg); 673 } 674 // Mark this register as the next register to write to 675 stack_[stack_depth_] = reg; 676 } 677 678 679 void LCodeGen::X87Stack::CommitWrite(X87Register reg) { 680 DCHECK(is_mutable_); 681 // Assert the reg is prepared to write, but not on the virtual stack yet 682 DCHECK(!Contains(reg) && stack_[stack_depth_].is(reg) && 683 stack_depth_ < X87Register::kMaxNumAllocatableRegisters); 684 stack_depth_++; 685 } 686 687 688 void LCodeGen::X87PrepareBinaryOp( 689 X87Register left, X87Register right, X87Register result) { 690 // You need to use DefineSameAsFirst for x87 instructions 691 DCHECK(result.is(left)); 692 x87_stack_.Fxch(right, 1); 693 x87_stack_.Fxch(left); 694 } 695 696 697 void LCodeGen::X87Stack::FlushIfNecessary(LInstruction* instr, LCodeGen* cgen) { 698 if (stack_depth_ > 0 && instr->ClobbersDoubleRegisters(isolate())) { 699 bool double_inputs = instr->HasDoubleRegisterInput(); 700 701 // Flush stack from tos down, since FreeX87() will mess with tos 702 for (int i = stack_depth_-1; i >= 0; i--) { 703 X87Register reg = stack_[i]; 704 // Skip registers which contain the inputs for the next instruction 705 // when flushing the stack 706 if (double_inputs && instr->IsDoubleInput(reg, cgen)) { 707 continue; 708 } 709 Free(reg); 710 if (i < stack_depth_-1) i++; 711 } 712 } 713 if (instr->IsReturn()) { 714 while (stack_depth_ > 0) { 715 __ fstp(0); 716 stack_depth_--; 717 } 718 if (FLAG_debug_code && FLAG_enable_slow_asserts) __ VerifyX87StackDepth(0); 719 } 720 } 721 722 723 void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr, 724 LCodeGen* cgen) { 725 // For going to a joined block, an explicit LClobberDoubles is inserted before 726 // LGoto. Because all used x87 registers are spilled to stack slots. The 727 // ResolvePhis phase of register allocator could guarantee the two input's x87 728 // stacks have the same layout. So don't check stack_depth_ <= 1 here. 729 int goto_block_id = goto_instr->block_id(); 730 if (current_block_id + 1 != goto_block_id) { 731 // If we have a value on the x87 stack on leaving a block, it must be a 732 // phi input. If the next block we compile is not the join block, we have 733 // to discard the stack state. 734 // Before discarding the stack state, we need to save it if the "goto block" 735 // has unreachable last predecessor when FLAG_unreachable_code_elimination. 736 if (FLAG_unreachable_code_elimination) { 737 int length = goto_instr->block()->predecessors()->length(); 738 bool has_unreachable_last_predecessor = false; 739 for (int i = 0; i < length; i++) { 740 HBasicBlock* block = goto_instr->block()->predecessors()->at(i); 741 if (block->IsUnreachable() && 742 (block->block_id() + 1) == goto_block_id) { 743 has_unreachable_last_predecessor = true; 744 } 745 } 746 if (has_unreachable_last_predecessor) { 747 if (cgen->x87_stack_map_.find(goto_block_id) == 748 cgen->x87_stack_map_.end()) { 749 X87Stack* stack = new (cgen->zone()) X87Stack(*this); 750 cgen->x87_stack_map_.insert(std::make_pair(goto_block_id, stack)); 751 } 752 } 753 } 754 755 // Discard the stack state. 756 stack_depth_ = 0; 757 } 758 } 759 760 761 void LCodeGen::EmitFlushX87ForDeopt() { 762 // The deoptimizer does not support X87 Registers. But as long as we 763 // deopt from a stub its not a problem, since we will re-materialize the 764 // original stub inputs, which can't be double registers. 765 // DCHECK(info()->IsStub()); 766 if (FLAG_debug_code && FLAG_enable_slow_asserts) { 767 __ pushfd(); 768 __ VerifyX87StackDepth(x87_stack_.depth()); 769 __ popfd(); 770 } 771 772 // Flush X87 stack in the deoptimizer entry. 773 } 774 775 776 Register LCodeGen::ToRegister(LOperand* op) const { 777 DCHECK(op->IsRegister()); 778 return ToRegister(op->index()); 779 } 780 781 782 X87Register LCodeGen::ToX87Register(LOperand* op) const { 783 DCHECK(op->IsDoubleRegister()); 784 return ToX87Register(op->index()); 785 } 786 787 788 int32_t LCodeGen::ToInteger32(LConstantOperand* op) const { 789 return ToRepresentation(op, Representation::Integer32()); 790 } 791 792 793 int32_t LCodeGen::ToRepresentation(LConstantOperand* op, 794 const Representation& r) const { 795 HConstant* constant = chunk_->LookupConstant(op); 796 if (r.IsExternal()) { 797 return reinterpret_cast<int32_t>( 798 constant->ExternalReferenceValue().address()); 799 } 800 int32_t value = constant->Integer32Value(); 801 if (r.IsInteger32()) return value; 802 DCHECK(r.IsSmiOrTagged()); 803 return reinterpret_cast<int32_t>(Smi::FromInt(value)); 804 } 805 806 807 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { 808 HConstant* constant = chunk_->LookupConstant(op); 809 DCHECK(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged()); 810 return constant->handle(isolate()); 811 } 812 813 814 double LCodeGen::ToDouble(LConstantOperand* op) const { 815 HConstant* constant = chunk_->LookupConstant(op); 816 DCHECK(constant->HasDoubleValue()); 817 return constant->DoubleValue(); 818 } 819 820 821 ExternalReference LCodeGen::ToExternalReference(LConstantOperand* op) const { 822 HConstant* constant = chunk_->LookupConstant(op); 823 DCHECK(constant->HasExternalReferenceValue()); 824 return constant->ExternalReferenceValue(); 825 } 826 827 828 bool LCodeGen::IsInteger32(LConstantOperand* op) const { 829 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32(); 830 } 831 832 833 bool LCodeGen::IsSmi(LConstantOperand* op) const { 834 return chunk_->LookupLiteralRepresentation(op).IsSmi(); 835 } 836 837 838 static int ArgumentsOffsetWithoutFrame(int index) { 839 DCHECK(index < 0); 840 return -(index + 1) * kPointerSize + kPCOnStackSize; 841 } 842 843 844 Operand LCodeGen::ToOperand(LOperand* op) const { 845 if (op->IsRegister()) return Operand(ToRegister(op)); 846 DCHECK(!op->IsDoubleRegister()); 847 DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot()); 848 if (NeedsEagerFrame()) { 849 return Operand(ebp, StackSlotOffset(op->index())); 850 } else { 851 // Retrieve parameter without eager stack-frame relative to the 852 // stack-pointer. 853 return Operand(esp, ArgumentsOffsetWithoutFrame(op->index())); 854 } 855 } 856 857 858 Operand LCodeGen::HighOperand(LOperand* op) { 859 DCHECK(op->IsDoubleStackSlot()); 860 if (NeedsEagerFrame()) { 861 return Operand(ebp, StackSlotOffset(op->index()) + kPointerSize); 862 } else { 863 // Retrieve parameter without eager stack-frame relative to the 864 // stack-pointer. 865 return Operand( 866 esp, ArgumentsOffsetWithoutFrame(op->index()) + kPointerSize); 867 } 868 } 869 870 871 void LCodeGen::WriteTranslation(LEnvironment* environment, 872 Translation* translation) { 873 if (environment == NULL) return; 874 875 // The translation includes one command per value in the environment. 876 int translation_size = environment->translation_size(); 877 878 WriteTranslation(environment->outer(), translation); 879 WriteTranslationFrame(environment, translation); 880 881 int object_index = 0; 882 int dematerialized_index = 0; 883 for (int i = 0; i < translation_size; ++i) { 884 LOperand* value = environment->values()->at(i); 885 AddToTranslation(environment, 886 translation, 887 value, 888 environment->HasTaggedValueAt(i), 889 environment->HasUint32ValueAt(i), 890 &object_index, 891 &dematerialized_index); 892 } 893 } 894 895 896 void LCodeGen::AddToTranslation(LEnvironment* environment, 897 Translation* translation, 898 LOperand* op, 899 bool is_tagged, 900 bool is_uint32, 901 int* object_index_pointer, 902 int* dematerialized_index_pointer) { 903 if (op == LEnvironment::materialization_marker()) { 904 int object_index = (*object_index_pointer)++; 905 if (environment->ObjectIsDuplicateAt(object_index)) { 906 int dupe_of = environment->ObjectDuplicateOfAt(object_index); 907 translation->DuplicateObject(dupe_of); 908 return; 909 } 910 int object_length = environment->ObjectLengthAt(object_index); 911 if (environment->ObjectIsArgumentsAt(object_index)) { 912 translation->BeginArgumentsObject(object_length); 913 } else { 914 translation->BeginCapturedObject(object_length); 915 } 916 int dematerialized_index = *dematerialized_index_pointer; 917 int env_offset = environment->translation_size() + dematerialized_index; 918 *dematerialized_index_pointer += object_length; 919 for (int i = 0; i < object_length; ++i) { 920 LOperand* value = environment->values()->at(env_offset + i); 921 AddToTranslation(environment, 922 translation, 923 value, 924 environment->HasTaggedValueAt(env_offset + i), 925 environment->HasUint32ValueAt(env_offset + i), 926 object_index_pointer, 927 dematerialized_index_pointer); 928 } 929 return; 930 } 931 932 if (op->IsStackSlot()) { 933 int index = op->index(); 934 if (index >= 0) { 935 index += StandardFrameConstants::kFixedFrameSize / kPointerSize; 936 } 937 if (is_tagged) { 938 translation->StoreStackSlot(index); 939 } else if (is_uint32) { 940 translation->StoreUint32StackSlot(index); 941 } else { 942 translation->StoreInt32StackSlot(index); 943 } 944 } else if (op->IsDoubleStackSlot()) { 945 int index = op->index(); 946 if (index >= 0) { 947 index += StandardFrameConstants::kFixedFrameSize / kPointerSize; 948 } 949 translation->StoreDoubleStackSlot(index); 950 } else if (op->IsRegister()) { 951 Register reg = ToRegister(op); 952 if (is_tagged) { 953 translation->StoreRegister(reg); 954 } else if (is_uint32) { 955 translation->StoreUint32Register(reg); 956 } else { 957 translation->StoreInt32Register(reg); 958 } 959 } else if (op->IsDoubleRegister()) { 960 X87Register reg = ToX87Register(op); 961 translation->StoreDoubleRegister(reg); 962 } else if (op->IsConstantOperand()) { 963 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op)); 964 int src_index = DefineDeoptimizationLiteral(constant->handle(isolate())); 965 translation->StoreLiteral(src_index); 966 } else { 967 UNREACHABLE(); 968 } 969 } 970 971 972 void LCodeGen::CallCodeGeneric(Handle<Code> code, 973 RelocInfo::Mode mode, 974 LInstruction* instr, 975 SafepointMode safepoint_mode) { 976 DCHECK(instr != NULL); 977 __ call(code, mode); 978 RecordSafepointWithLazyDeopt(instr, safepoint_mode); 979 980 // Signal that we don't inline smi code before these stubs in the 981 // optimizing code generator. 982 if (code->kind() == Code::BINARY_OP_IC || 983 code->kind() == Code::COMPARE_IC) { 984 __ nop(); 985 } 986 } 987 988 989 void LCodeGen::CallCode(Handle<Code> code, 990 RelocInfo::Mode mode, 991 LInstruction* instr) { 992 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); 993 } 994 995 996 void LCodeGen::CallRuntime(const Runtime::Function* fun, int argc, 997 LInstruction* instr, SaveFPRegsMode save_doubles) { 998 DCHECK(instr != NULL); 999 DCHECK(instr->HasPointerMap()); 1000 1001 __ CallRuntime(fun, argc, save_doubles); 1002 1003 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); 1004 1005 DCHECK(info()->is_calling()); 1006 } 1007 1008 1009 void LCodeGen::LoadContextFromDeferred(LOperand* context) { 1010 if (context->IsRegister()) { 1011 if (!ToRegister(context).is(esi)) { 1012 __ mov(esi, ToRegister(context)); 1013 } 1014 } else if (context->IsStackSlot()) { 1015 __ mov(esi, ToOperand(context)); 1016 } else if (context->IsConstantOperand()) { 1017 HConstant* constant = 1018 chunk_->LookupConstant(LConstantOperand::cast(context)); 1019 __ LoadObject(esi, Handle<Object>::cast(constant->handle(isolate()))); 1020 } else { 1021 UNREACHABLE(); 1022 } 1023 } 1024 1025 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, 1026 int argc, 1027 LInstruction* instr, 1028 LOperand* context) { 1029 LoadContextFromDeferred(context); 1030 1031 __ CallRuntimeSaveDoubles(id); 1032 RecordSafepointWithRegisters( 1033 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); 1034 1035 DCHECK(info()->is_calling()); 1036 } 1037 1038 1039 void LCodeGen::RegisterEnvironmentForDeoptimization( 1040 LEnvironment* environment, Safepoint::DeoptMode mode) { 1041 environment->set_has_been_used(); 1042 if (!environment->HasBeenRegistered()) { 1043 // Physical stack frame layout: 1044 // -x ............. -4 0 ..................................... y 1045 // [incoming arguments] [spill slots] [pushed outgoing arguments] 1046 1047 // Layout of the environment: 1048 // 0 ..................................................... size-1 1049 // [parameters] [locals] [expression stack including arguments] 1050 1051 // Layout of the translation: 1052 // 0 ........................................................ size - 1 + 4 1053 // [expression stack including arguments] [locals] [4 words] [parameters] 1054 // |>------------ translation_size ------------<| 1055 1056 int frame_count = 0; 1057 int jsframe_count = 0; 1058 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { 1059 ++frame_count; 1060 if (e->frame_type() == JS_FUNCTION) { 1061 ++jsframe_count; 1062 } 1063 } 1064 Translation translation(&translations_, frame_count, jsframe_count, zone()); 1065 WriteTranslation(environment, &translation); 1066 int deoptimization_index = deoptimizations_.length(); 1067 int pc_offset = masm()->pc_offset(); 1068 environment->Register(deoptimization_index, 1069 translation.index(), 1070 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); 1071 deoptimizations_.Add(environment, zone()); 1072 } 1073 } 1074 1075 1076 void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr, 1077 Deoptimizer::DeoptReason deopt_reason, 1078 Deoptimizer::BailoutType bailout_type) { 1079 LEnvironment* environment = instr->environment(); 1080 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 1081 DCHECK(environment->HasBeenRegistered()); 1082 int id = environment->deoptimization_index(); 1083 Address entry = 1084 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); 1085 if (entry == NULL) { 1086 Abort(kBailoutWasNotPrepared); 1087 return; 1088 } 1089 1090 if (DeoptEveryNTimes()) { 1091 ExternalReference count = ExternalReference::stress_deopt_count(isolate()); 1092 Label no_deopt; 1093 __ pushfd(); 1094 __ push(eax); 1095 __ mov(eax, Operand::StaticVariable(count)); 1096 __ sub(eax, Immediate(1)); 1097 __ j(not_zero, &no_deopt, Label::kNear); 1098 if (FLAG_trap_on_deopt) __ int3(); 1099 __ mov(eax, Immediate(FLAG_deopt_every_n_times)); 1100 __ mov(Operand::StaticVariable(count), eax); 1101 __ pop(eax); 1102 __ popfd(); 1103 DCHECK(frame_is_built_); 1104 // Put the x87 stack layout in TOS. 1105 if (x87_stack_.depth() > 0) EmitFlushX87ForDeopt(); 1106 __ push(Immediate(x87_stack_.GetLayout())); 1107 __ fild_s(MemOperand(esp, 0)); 1108 // Don't touch eflags. 1109 __ lea(esp, Operand(esp, kPointerSize)); 1110 __ call(entry, RelocInfo::RUNTIME_ENTRY); 1111 __ bind(&no_deopt); 1112 __ mov(Operand::StaticVariable(count), eax); 1113 __ pop(eax); 1114 __ popfd(); 1115 } 1116 1117 // Put the x87 stack layout in TOS, so that we can save x87 fp registers in 1118 // the correct location. 1119 { 1120 Label done; 1121 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear); 1122 if (x87_stack_.depth() > 0) EmitFlushX87ForDeopt(); 1123 1124 int x87_stack_layout = x87_stack_.GetLayout(); 1125 __ push(Immediate(x87_stack_layout)); 1126 __ fild_s(MemOperand(esp, 0)); 1127 // Don't touch eflags. 1128 __ lea(esp, Operand(esp, kPointerSize)); 1129 __ bind(&done); 1130 } 1131 1132 if (info()->ShouldTrapOnDeopt()) { 1133 Label done; 1134 if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear); 1135 __ int3(); 1136 __ bind(&done); 1137 } 1138 1139 Deoptimizer::DeoptInfo deopt_info = MakeDeoptInfo(instr, deopt_reason); 1140 1141 DCHECK(info()->IsStub() || frame_is_built_); 1142 if (cc == no_condition && frame_is_built_) { 1143 DeoptComment(deopt_info); 1144 __ call(entry, RelocInfo::RUNTIME_ENTRY); 1145 info()->LogDeoptCallPosition(masm()->pc_offset(), deopt_info.inlining_id); 1146 } else { 1147 Deoptimizer::JumpTableEntry table_entry(entry, deopt_info, bailout_type, 1148 !frame_is_built_); 1149 // We often have several deopts to the same entry, reuse the last 1150 // jump entry if this is the case. 1151 if (FLAG_trace_deopt || isolate()->cpu_profiler()->is_profiling() || 1152 jump_table_.is_empty() || 1153 !table_entry.IsEquivalentTo(jump_table_.last())) { 1154 jump_table_.Add(table_entry, zone()); 1155 } 1156 if (cc == no_condition) { 1157 __ jmp(&jump_table_.last().label); 1158 } else { 1159 __ j(cc, &jump_table_.last().label); 1160 } 1161 } 1162 } 1163 1164 1165 void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr, 1166 Deoptimizer::DeoptReason deopt_reason) { 1167 Deoptimizer::BailoutType bailout_type = info()->IsStub() 1168 ? Deoptimizer::LAZY 1169 : Deoptimizer::EAGER; 1170 DeoptimizeIf(cc, instr, deopt_reason, bailout_type); 1171 } 1172 1173 1174 void LCodeGen::RecordSafepointWithLazyDeopt( 1175 LInstruction* instr, SafepointMode safepoint_mode) { 1176 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { 1177 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); 1178 } else { 1179 DCHECK(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 1180 RecordSafepointWithRegisters( 1181 instr->pointer_map(), 0, Safepoint::kLazyDeopt); 1182 } 1183 } 1184 1185 1186 void LCodeGen::RecordSafepoint( 1187 LPointerMap* pointers, 1188 Safepoint::Kind kind, 1189 int arguments, 1190 Safepoint::DeoptMode deopt_mode) { 1191 DCHECK(kind == expected_safepoint_kind_); 1192 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); 1193 Safepoint safepoint = 1194 safepoints_.DefineSafepoint(masm(), kind, arguments, deopt_mode); 1195 for (int i = 0; i < operands->length(); i++) { 1196 LOperand* pointer = operands->at(i); 1197 if (pointer->IsStackSlot()) { 1198 safepoint.DefinePointerSlot(pointer->index(), zone()); 1199 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { 1200 safepoint.DefinePointerRegister(ToRegister(pointer), zone()); 1201 } 1202 } 1203 } 1204 1205 1206 void LCodeGen::RecordSafepoint(LPointerMap* pointers, 1207 Safepoint::DeoptMode mode) { 1208 RecordSafepoint(pointers, Safepoint::kSimple, 0, mode); 1209 } 1210 1211 1212 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) { 1213 LPointerMap empty_pointers(zone()); 1214 RecordSafepoint(&empty_pointers, mode); 1215 } 1216 1217 1218 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, 1219 int arguments, 1220 Safepoint::DeoptMode mode) { 1221 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, mode); 1222 } 1223 1224 1225 void LCodeGen::RecordAndWritePosition(int position) { 1226 if (position == RelocInfo::kNoPosition) return; 1227 masm()->positions_recorder()->RecordPosition(position); 1228 masm()->positions_recorder()->WriteRecordedPositions(); 1229 } 1230 1231 1232 static const char* LabelType(LLabel* label) { 1233 if (label->is_loop_header()) return " (loop header)"; 1234 if (label->is_osr_entry()) return " (OSR entry)"; 1235 return ""; 1236 } 1237 1238 1239 void LCodeGen::DoLabel(LLabel* label) { 1240 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------", 1241 current_instruction_, 1242 label->hydrogen_value()->id(), 1243 label->block_id(), 1244 LabelType(label)); 1245 __ bind(label->label()); 1246 current_block_ = label->block_id(); 1247 if (label->block()->predecessors()->length() > 1) { 1248 // A join block's x87 stack is that of its last visited predecessor. 1249 // If the last visited predecessor block is unreachable, the stack state 1250 // will be wrong. In such case, use the x87 stack of reachable predecessor. 1251 X87StackMap::const_iterator it = x87_stack_map_.find(current_block_); 1252 // Restore x87 stack. 1253 if (it != x87_stack_map_.end()) { 1254 x87_stack_ = *(it->second); 1255 } 1256 } 1257 DoGap(label); 1258 } 1259 1260 1261 void LCodeGen::DoParallelMove(LParallelMove* move) { 1262 resolver_.Resolve(move); 1263 } 1264 1265 1266 void LCodeGen::DoGap(LGap* gap) { 1267 for (int i = LGap::FIRST_INNER_POSITION; 1268 i <= LGap::LAST_INNER_POSITION; 1269 i++) { 1270 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); 1271 LParallelMove* move = gap->GetParallelMove(inner_pos); 1272 if (move != NULL) DoParallelMove(move); 1273 } 1274 } 1275 1276 1277 void LCodeGen::DoInstructionGap(LInstructionGap* instr) { 1278 DoGap(instr); 1279 } 1280 1281 1282 void LCodeGen::DoParameter(LParameter* instr) { 1283 // Nothing to do. 1284 } 1285 1286 1287 void LCodeGen::DoCallStub(LCallStub* instr) { 1288 DCHECK(ToRegister(instr->context()).is(esi)); 1289 DCHECK(ToRegister(instr->result()).is(eax)); 1290 switch (instr->hydrogen()->major_key()) { 1291 case CodeStub::RegExpExec: { 1292 RegExpExecStub stub(isolate()); 1293 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 1294 break; 1295 } 1296 case CodeStub::SubString: { 1297 SubStringStub stub(isolate()); 1298 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 1299 break; 1300 } 1301 default: 1302 UNREACHABLE(); 1303 } 1304 } 1305 1306 1307 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { 1308 GenerateOsrPrologue(); 1309 } 1310 1311 1312 void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) { 1313 Register dividend = ToRegister(instr->dividend()); 1314 int32_t divisor = instr->divisor(); 1315 DCHECK(dividend.is(ToRegister(instr->result()))); 1316 1317 // Theoretically, a variation of the branch-free code for integer division by 1318 // a power of 2 (calculating the remainder via an additional multiplication 1319 // (which gets simplified to an 'and') and subtraction) should be faster, and 1320 // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to 1321 // indicate that positive dividends are heavily favored, so the branching 1322 // version performs better. 1323 HMod* hmod = instr->hydrogen(); 1324 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); 1325 Label dividend_is_not_negative, done; 1326 if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) { 1327 __ test(dividend, dividend); 1328 __ j(not_sign, ÷nd_is_not_negative, Label::kNear); 1329 // Note that this is correct even for kMinInt operands. 1330 __ neg(dividend); 1331 __ and_(dividend, mask); 1332 __ neg(dividend); 1333 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1334 DeoptimizeIf(zero, instr, Deoptimizer::kMinusZero); 1335 } 1336 __ jmp(&done, Label::kNear); 1337 } 1338 1339 __ bind(÷nd_is_not_negative); 1340 __ and_(dividend, mask); 1341 __ bind(&done); 1342 } 1343 1344 1345 void LCodeGen::DoModByConstI(LModByConstI* instr) { 1346 Register dividend = ToRegister(instr->dividend()); 1347 int32_t divisor = instr->divisor(); 1348 DCHECK(ToRegister(instr->result()).is(eax)); 1349 1350 if (divisor == 0) { 1351 DeoptimizeIf(no_condition, instr, Deoptimizer::kDivisionByZero); 1352 return; 1353 } 1354 1355 __ TruncatingDiv(dividend, Abs(divisor)); 1356 __ imul(edx, edx, Abs(divisor)); 1357 __ mov(eax, dividend); 1358 __ sub(eax, edx); 1359 1360 // Check for negative zero. 1361 HMod* hmod = instr->hydrogen(); 1362 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1363 Label remainder_not_zero; 1364 __ j(not_zero, &remainder_not_zero, Label::kNear); 1365 __ cmp(dividend, Immediate(0)); 1366 DeoptimizeIf(less, instr, Deoptimizer::kMinusZero); 1367 __ bind(&remainder_not_zero); 1368 } 1369 } 1370 1371 1372 void LCodeGen::DoModI(LModI* instr) { 1373 HMod* hmod = instr->hydrogen(); 1374 1375 Register left_reg = ToRegister(instr->left()); 1376 DCHECK(left_reg.is(eax)); 1377 Register right_reg = ToRegister(instr->right()); 1378 DCHECK(!right_reg.is(eax)); 1379 DCHECK(!right_reg.is(edx)); 1380 Register result_reg = ToRegister(instr->result()); 1381 DCHECK(result_reg.is(edx)); 1382 1383 Label done; 1384 // Check for x % 0, idiv would signal a divide error. We have to 1385 // deopt in this case because we can't return a NaN. 1386 if (hmod->CheckFlag(HValue::kCanBeDivByZero)) { 1387 __ test(right_reg, Operand(right_reg)); 1388 DeoptimizeIf(zero, instr, Deoptimizer::kDivisionByZero); 1389 } 1390 1391 // Check for kMinInt % -1, idiv would signal a divide error. We 1392 // have to deopt if we care about -0, because we can't return that. 1393 if (hmod->CheckFlag(HValue::kCanOverflow)) { 1394 Label no_overflow_possible; 1395 __ cmp(left_reg, kMinInt); 1396 __ j(not_equal, &no_overflow_possible, Label::kNear); 1397 __ cmp(right_reg, -1); 1398 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1399 DeoptimizeIf(equal, instr, Deoptimizer::kMinusZero); 1400 } else { 1401 __ j(not_equal, &no_overflow_possible, Label::kNear); 1402 __ Move(result_reg, Immediate(0)); 1403 __ jmp(&done, Label::kNear); 1404 } 1405 __ bind(&no_overflow_possible); 1406 } 1407 1408 // Sign extend dividend in eax into edx:eax. 1409 __ cdq(); 1410 1411 // If we care about -0, test if the dividend is <0 and the result is 0. 1412 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1413 Label positive_left; 1414 __ test(left_reg, Operand(left_reg)); 1415 __ j(not_sign, &positive_left, Label::kNear); 1416 __ idiv(right_reg); 1417 __ test(result_reg, Operand(result_reg)); 1418 DeoptimizeIf(zero, instr, Deoptimizer::kMinusZero); 1419 __ jmp(&done, Label::kNear); 1420 __ bind(&positive_left); 1421 } 1422 __ idiv(right_reg); 1423 __ bind(&done); 1424 } 1425 1426 1427 void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) { 1428 Register dividend = ToRegister(instr->dividend()); 1429 int32_t divisor = instr->divisor(); 1430 Register result = ToRegister(instr->result()); 1431 DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor))); 1432 DCHECK(!result.is(dividend)); 1433 1434 // Check for (0 / -x) that will produce negative zero. 1435 HDiv* hdiv = instr->hydrogen(); 1436 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { 1437 __ test(dividend, dividend); 1438 DeoptimizeIf(zero, instr, Deoptimizer::kMinusZero); 1439 } 1440 // Check for (kMinInt / -1). 1441 if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) { 1442 __ cmp(dividend, kMinInt); 1443 DeoptimizeIf(zero, instr, Deoptimizer::kOverflow); 1444 } 1445 // Deoptimize if remainder will not be 0. 1446 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) && 1447 divisor != 1 && divisor != -1) { 1448 int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1); 1449 __ test(dividend, Immediate(mask)); 1450 DeoptimizeIf(not_zero, instr, Deoptimizer::kLostPrecision); 1451 } 1452 __ Move(result, dividend); 1453 int32_t shift = WhichPowerOf2Abs(divisor); 1454 if (shift > 0) { 1455 // The arithmetic shift is always OK, the 'if' is an optimization only. 1456 if (shift > 1) __ sar(result, 31); 1457 __ shr(result, 32 - shift); 1458 __ add(result, dividend); 1459 __ sar(result, shift); 1460 } 1461 if (divisor < 0) __ neg(result); 1462 } 1463 1464 1465 void LCodeGen::DoDivByConstI(LDivByConstI* instr) { 1466 Register dividend = ToRegister(instr->dividend()); 1467 int32_t divisor = instr->divisor(); 1468 DCHECK(ToRegister(instr->result()).is(edx)); 1469 1470 if (divisor == 0) { 1471 DeoptimizeIf(no_condition, instr, Deoptimizer::kDivisionByZero); 1472 return; 1473 } 1474 1475 // Check for (0 / -x) that will produce negative zero. 1476 HDiv* hdiv = instr->hydrogen(); 1477 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { 1478 __ test(dividend, dividend); 1479 DeoptimizeIf(zero, instr, Deoptimizer::kMinusZero); 1480 } 1481 1482 __ TruncatingDiv(dividend, Abs(divisor)); 1483 if (divisor < 0) __ neg(edx); 1484 1485 if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { 1486 __ mov(eax, edx); 1487 __ imul(eax, eax, divisor); 1488 __ sub(eax, dividend); 1489 DeoptimizeIf(not_equal, instr, Deoptimizer::kLostPrecision); 1490 } 1491 } 1492 1493 1494 // TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI. 1495 void LCodeGen::DoDivI(LDivI* instr) { 1496 HBinaryOperation* hdiv = instr->hydrogen(); 1497 Register dividend = ToRegister(instr->dividend()); 1498 Register divisor = ToRegister(instr->divisor()); 1499 Register remainder = ToRegister(instr->temp()); 1500 DCHECK(dividend.is(eax)); 1501 DCHECK(remainder.is(edx)); 1502 DCHECK(ToRegister(instr->result()).is(eax)); 1503 DCHECK(!divisor.is(eax)); 1504 DCHECK(!divisor.is(edx)); 1505 1506 // Check for x / 0. 1507 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { 1508 __ test(divisor, divisor); 1509 DeoptimizeIf(zero, instr, Deoptimizer::kDivisionByZero); 1510 } 1511 1512 // Check for (0 / -x) that will produce negative zero. 1513 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { 1514 Label dividend_not_zero; 1515 __ test(dividend, dividend); 1516 __ j(not_zero, ÷nd_not_zero, Label::kNear); 1517 __ test(divisor, divisor); 1518 DeoptimizeIf(sign, instr, Deoptimizer::kMinusZero); 1519 __ bind(÷nd_not_zero); 1520 } 1521 1522 // Check for (kMinInt / -1). 1523 if (hdiv->CheckFlag(HValue::kCanOverflow)) { 1524 Label dividend_not_min_int; 1525 __ cmp(dividend, kMinInt); 1526 __ j(not_zero, ÷nd_not_min_int, Label::kNear); 1527 __ cmp(divisor, -1); 1528 DeoptimizeIf(zero, instr, Deoptimizer::kOverflow); 1529 __ bind(÷nd_not_min_int); 1530 } 1531 1532 // Sign extend to edx (= remainder). 1533 __ cdq(); 1534 __ idiv(divisor); 1535 1536 if (!hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) { 1537 // Deoptimize if remainder is not 0. 1538 __ test(remainder, remainder); 1539 DeoptimizeIf(not_zero, instr, Deoptimizer::kLostPrecision); 1540 } 1541 } 1542 1543 1544 void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) { 1545 Register dividend = ToRegister(instr->dividend()); 1546 int32_t divisor = instr->divisor(); 1547 DCHECK(dividend.is(ToRegister(instr->result()))); 1548 1549 // If the divisor is positive, things are easy: There can be no deopts and we 1550 // can simply do an arithmetic right shift. 1551 if (divisor == 1) return; 1552 int32_t shift = WhichPowerOf2Abs(divisor); 1553 if (divisor > 1) { 1554 __ sar(dividend, shift); 1555 return; 1556 } 1557 1558 // If the divisor is negative, we have to negate and handle edge cases. 1559 __ neg(dividend); 1560 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1561 DeoptimizeIf(zero, instr, Deoptimizer::kMinusZero); 1562 } 1563 1564 // Dividing by -1 is basically negation, unless we overflow. 1565 if (divisor == -1) { 1566 if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { 1567 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 1568 } 1569 return; 1570 } 1571 1572 // If the negation could not overflow, simply shifting is OK. 1573 if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) { 1574 __ sar(dividend, shift); 1575 return; 1576 } 1577 1578 Label not_kmin_int, done; 1579 __ j(no_overflow, ¬_kmin_int, Label::kNear); 1580 __ mov(dividend, Immediate(kMinInt / divisor)); 1581 __ jmp(&done, Label::kNear); 1582 __ bind(¬_kmin_int); 1583 __ sar(dividend, shift); 1584 __ bind(&done); 1585 } 1586 1587 1588 void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) { 1589 Register dividend = ToRegister(instr->dividend()); 1590 int32_t divisor = instr->divisor(); 1591 DCHECK(ToRegister(instr->result()).is(edx)); 1592 1593 if (divisor == 0) { 1594 DeoptimizeIf(no_condition, instr, Deoptimizer::kDivisionByZero); 1595 return; 1596 } 1597 1598 // Check for (0 / -x) that will produce negative zero. 1599 HMathFloorOfDiv* hdiv = instr->hydrogen(); 1600 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) { 1601 __ test(dividend, dividend); 1602 DeoptimizeIf(zero, instr, Deoptimizer::kMinusZero); 1603 } 1604 1605 // Easy case: We need no dynamic check for the dividend and the flooring 1606 // division is the same as the truncating division. 1607 if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) || 1608 (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) { 1609 __ TruncatingDiv(dividend, Abs(divisor)); 1610 if (divisor < 0) __ neg(edx); 1611 return; 1612 } 1613 1614 // In the general case we may need to adjust before and after the truncating 1615 // division to get a flooring division. 1616 Register temp = ToRegister(instr->temp3()); 1617 DCHECK(!temp.is(dividend) && !temp.is(eax) && !temp.is(edx)); 1618 Label needs_adjustment, done; 1619 __ cmp(dividend, Immediate(0)); 1620 __ j(divisor > 0 ? less : greater, &needs_adjustment, Label::kNear); 1621 __ TruncatingDiv(dividend, Abs(divisor)); 1622 if (divisor < 0) __ neg(edx); 1623 __ jmp(&done, Label::kNear); 1624 __ bind(&needs_adjustment); 1625 __ lea(temp, Operand(dividend, divisor > 0 ? 1 : -1)); 1626 __ TruncatingDiv(temp, Abs(divisor)); 1627 if (divisor < 0) __ neg(edx); 1628 __ dec(edx); 1629 __ bind(&done); 1630 } 1631 1632 1633 // TODO(svenpanne) Refactor this to avoid code duplication with DoDivI. 1634 void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) { 1635 HBinaryOperation* hdiv = instr->hydrogen(); 1636 Register dividend = ToRegister(instr->dividend()); 1637 Register divisor = ToRegister(instr->divisor()); 1638 Register remainder = ToRegister(instr->temp()); 1639 Register result = ToRegister(instr->result()); 1640 DCHECK(dividend.is(eax)); 1641 DCHECK(remainder.is(edx)); 1642 DCHECK(result.is(eax)); 1643 DCHECK(!divisor.is(eax)); 1644 DCHECK(!divisor.is(edx)); 1645 1646 // Check for x / 0. 1647 if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) { 1648 __ test(divisor, divisor); 1649 DeoptimizeIf(zero, instr, Deoptimizer::kDivisionByZero); 1650 } 1651 1652 // Check for (0 / -x) that will produce negative zero. 1653 if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) { 1654 Label dividend_not_zero; 1655 __ test(dividend, dividend); 1656 __ j(not_zero, ÷nd_not_zero, Label::kNear); 1657 __ test(divisor, divisor); 1658 DeoptimizeIf(sign, instr, Deoptimizer::kMinusZero); 1659 __ bind(÷nd_not_zero); 1660 } 1661 1662 // Check for (kMinInt / -1). 1663 if (hdiv->CheckFlag(HValue::kCanOverflow)) { 1664 Label dividend_not_min_int; 1665 __ cmp(dividend, kMinInt); 1666 __ j(not_zero, ÷nd_not_min_int, Label::kNear); 1667 __ cmp(divisor, -1); 1668 DeoptimizeIf(zero, instr, Deoptimizer::kOverflow); 1669 __ bind(÷nd_not_min_int); 1670 } 1671 1672 // Sign extend to edx (= remainder). 1673 __ cdq(); 1674 __ idiv(divisor); 1675 1676 Label done; 1677 __ test(remainder, remainder); 1678 __ j(zero, &done, Label::kNear); 1679 __ xor_(remainder, divisor); 1680 __ sar(remainder, 31); 1681 __ add(result, remainder); 1682 __ bind(&done); 1683 } 1684 1685 1686 void LCodeGen::DoMulI(LMulI* instr) { 1687 Register left = ToRegister(instr->left()); 1688 LOperand* right = instr->right(); 1689 1690 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1691 __ mov(ToRegister(instr->temp()), left); 1692 } 1693 1694 if (right->IsConstantOperand()) { 1695 // Try strength reductions on the multiplication. 1696 // All replacement instructions are at most as long as the imul 1697 // and have better latency. 1698 int constant = ToInteger32(LConstantOperand::cast(right)); 1699 if (constant == -1) { 1700 __ neg(left); 1701 } else if (constant == 0) { 1702 __ xor_(left, Operand(left)); 1703 } else if (constant == 2) { 1704 __ add(left, Operand(left)); 1705 } else if (!instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1706 // If we know that the multiplication can't overflow, it's safe to 1707 // use instructions that don't set the overflow flag for the 1708 // multiplication. 1709 switch (constant) { 1710 case 1: 1711 // Do nothing. 1712 break; 1713 case 3: 1714 __ lea(left, Operand(left, left, times_2, 0)); 1715 break; 1716 case 4: 1717 __ shl(left, 2); 1718 break; 1719 case 5: 1720 __ lea(left, Operand(left, left, times_4, 0)); 1721 break; 1722 case 8: 1723 __ shl(left, 3); 1724 break; 1725 case 9: 1726 __ lea(left, Operand(left, left, times_8, 0)); 1727 break; 1728 case 16: 1729 __ shl(left, 4); 1730 break; 1731 default: 1732 __ imul(left, left, constant); 1733 break; 1734 } 1735 } else { 1736 __ imul(left, left, constant); 1737 } 1738 } else { 1739 if (instr->hydrogen()->representation().IsSmi()) { 1740 __ SmiUntag(left); 1741 } 1742 __ imul(left, ToOperand(right)); 1743 } 1744 1745 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1746 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 1747 } 1748 1749 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1750 // Bail out if the result is supposed to be negative zero. 1751 Label done; 1752 __ test(left, Operand(left)); 1753 __ j(not_zero, &done); 1754 if (right->IsConstantOperand()) { 1755 if (ToInteger32(LConstantOperand::cast(right)) < 0) { 1756 DeoptimizeIf(no_condition, instr, Deoptimizer::kMinusZero); 1757 } else if (ToInteger32(LConstantOperand::cast(right)) == 0) { 1758 __ cmp(ToRegister(instr->temp()), Immediate(0)); 1759 DeoptimizeIf(less, instr, Deoptimizer::kMinusZero); 1760 } 1761 } else { 1762 // Test the non-zero operand for negative sign. 1763 __ or_(ToRegister(instr->temp()), ToOperand(right)); 1764 DeoptimizeIf(sign, instr, Deoptimizer::kMinusZero); 1765 } 1766 __ bind(&done); 1767 } 1768 } 1769 1770 1771 void LCodeGen::DoBitI(LBitI* instr) { 1772 LOperand* left = instr->left(); 1773 LOperand* right = instr->right(); 1774 DCHECK(left->Equals(instr->result())); 1775 DCHECK(left->IsRegister()); 1776 1777 if (right->IsConstantOperand()) { 1778 int32_t right_operand = 1779 ToRepresentation(LConstantOperand::cast(right), 1780 instr->hydrogen()->representation()); 1781 switch (instr->op()) { 1782 case Token::BIT_AND: 1783 __ and_(ToRegister(left), right_operand); 1784 break; 1785 case Token::BIT_OR: 1786 __ or_(ToRegister(left), right_operand); 1787 break; 1788 case Token::BIT_XOR: 1789 if (right_operand == int32_t(~0)) { 1790 __ not_(ToRegister(left)); 1791 } else { 1792 __ xor_(ToRegister(left), right_operand); 1793 } 1794 break; 1795 default: 1796 UNREACHABLE(); 1797 break; 1798 } 1799 } else { 1800 switch (instr->op()) { 1801 case Token::BIT_AND: 1802 __ and_(ToRegister(left), ToOperand(right)); 1803 break; 1804 case Token::BIT_OR: 1805 __ or_(ToRegister(left), ToOperand(right)); 1806 break; 1807 case Token::BIT_XOR: 1808 __ xor_(ToRegister(left), ToOperand(right)); 1809 break; 1810 default: 1811 UNREACHABLE(); 1812 break; 1813 } 1814 } 1815 } 1816 1817 1818 void LCodeGen::DoShiftI(LShiftI* instr) { 1819 LOperand* left = instr->left(); 1820 LOperand* right = instr->right(); 1821 DCHECK(left->Equals(instr->result())); 1822 DCHECK(left->IsRegister()); 1823 if (right->IsRegister()) { 1824 DCHECK(ToRegister(right).is(ecx)); 1825 1826 switch (instr->op()) { 1827 case Token::ROR: 1828 __ ror_cl(ToRegister(left)); 1829 break; 1830 case Token::SAR: 1831 __ sar_cl(ToRegister(left)); 1832 break; 1833 case Token::SHR: 1834 __ shr_cl(ToRegister(left)); 1835 if (instr->can_deopt()) { 1836 __ test(ToRegister(left), ToRegister(left)); 1837 DeoptimizeIf(sign, instr, Deoptimizer::kNegativeValue); 1838 } 1839 break; 1840 case Token::SHL: 1841 __ shl_cl(ToRegister(left)); 1842 break; 1843 default: 1844 UNREACHABLE(); 1845 break; 1846 } 1847 } else { 1848 int value = ToInteger32(LConstantOperand::cast(right)); 1849 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); 1850 switch (instr->op()) { 1851 case Token::ROR: 1852 if (shift_count == 0 && instr->can_deopt()) { 1853 __ test(ToRegister(left), ToRegister(left)); 1854 DeoptimizeIf(sign, instr, Deoptimizer::kNegativeValue); 1855 } else { 1856 __ ror(ToRegister(left), shift_count); 1857 } 1858 break; 1859 case Token::SAR: 1860 if (shift_count != 0) { 1861 __ sar(ToRegister(left), shift_count); 1862 } 1863 break; 1864 case Token::SHR: 1865 if (shift_count != 0) { 1866 __ shr(ToRegister(left), shift_count); 1867 } else if (instr->can_deopt()) { 1868 __ test(ToRegister(left), ToRegister(left)); 1869 DeoptimizeIf(sign, instr, Deoptimizer::kNegativeValue); 1870 } 1871 break; 1872 case Token::SHL: 1873 if (shift_count != 0) { 1874 if (instr->hydrogen_value()->representation().IsSmi() && 1875 instr->can_deopt()) { 1876 if (shift_count != 1) { 1877 __ shl(ToRegister(left), shift_count - 1); 1878 } 1879 __ SmiTag(ToRegister(left)); 1880 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 1881 } else { 1882 __ shl(ToRegister(left), shift_count); 1883 } 1884 } 1885 break; 1886 default: 1887 UNREACHABLE(); 1888 break; 1889 } 1890 } 1891 } 1892 1893 1894 void LCodeGen::DoSubI(LSubI* instr) { 1895 LOperand* left = instr->left(); 1896 LOperand* right = instr->right(); 1897 DCHECK(left->Equals(instr->result())); 1898 1899 if (right->IsConstantOperand()) { 1900 __ sub(ToOperand(left), 1901 ToImmediate(right, instr->hydrogen()->representation())); 1902 } else { 1903 __ sub(ToRegister(left), ToOperand(right)); 1904 } 1905 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1906 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 1907 } 1908 } 1909 1910 1911 void LCodeGen::DoConstantI(LConstantI* instr) { 1912 __ Move(ToRegister(instr->result()), Immediate(instr->value())); 1913 } 1914 1915 1916 void LCodeGen::DoConstantS(LConstantS* instr) { 1917 __ Move(ToRegister(instr->result()), Immediate(instr->value())); 1918 } 1919 1920 1921 void LCodeGen::DoConstantD(LConstantD* instr) { 1922 uint64_t const bits = instr->bits(); 1923 uint32_t const lower = static_cast<uint32_t>(bits); 1924 uint32_t const upper = static_cast<uint32_t>(bits >> 32); 1925 DCHECK(instr->result()->IsDoubleRegister()); 1926 1927 __ push(Immediate(upper)); 1928 __ push(Immediate(lower)); 1929 X87Register reg = ToX87Register(instr->result()); 1930 X87Mov(reg, Operand(esp, 0)); 1931 __ add(Operand(esp), Immediate(kDoubleSize)); 1932 } 1933 1934 1935 void LCodeGen::DoConstantE(LConstantE* instr) { 1936 __ lea(ToRegister(instr->result()), Operand::StaticVariable(instr->value())); 1937 } 1938 1939 1940 void LCodeGen::DoConstantT(LConstantT* instr) { 1941 Register reg = ToRegister(instr->result()); 1942 Handle<Object> object = instr->value(isolate()); 1943 AllowDeferredHandleDereference smi_check; 1944 __ LoadObject(reg, object); 1945 } 1946 1947 1948 void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { 1949 Register result = ToRegister(instr->result()); 1950 Register map = ToRegister(instr->value()); 1951 __ EnumLength(result, map); 1952 } 1953 1954 1955 Operand LCodeGen::BuildSeqStringOperand(Register string, 1956 LOperand* index, 1957 String::Encoding encoding) { 1958 if (index->IsConstantOperand()) { 1959 int offset = ToRepresentation(LConstantOperand::cast(index), 1960 Representation::Integer32()); 1961 if (encoding == String::TWO_BYTE_ENCODING) { 1962 offset *= kUC16Size; 1963 } 1964 STATIC_ASSERT(kCharSize == 1); 1965 return FieldOperand(string, SeqString::kHeaderSize + offset); 1966 } 1967 return FieldOperand( 1968 string, ToRegister(index), 1969 encoding == String::ONE_BYTE_ENCODING ? times_1 : times_2, 1970 SeqString::kHeaderSize); 1971 } 1972 1973 1974 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) { 1975 String::Encoding encoding = instr->hydrogen()->encoding(); 1976 Register result = ToRegister(instr->result()); 1977 Register string = ToRegister(instr->string()); 1978 1979 if (FLAG_debug_code) { 1980 __ push(string); 1981 __ mov(string, FieldOperand(string, HeapObject::kMapOffset)); 1982 __ movzx_b(string, FieldOperand(string, Map::kInstanceTypeOffset)); 1983 1984 __ and_(string, Immediate(kStringRepresentationMask | kStringEncodingMask)); 1985 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; 1986 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; 1987 __ cmp(string, Immediate(encoding == String::ONE_BYTE_ENCODING 1988 ? one_byte_seq_type : two_byte_seq_type)); 1989 __ Check(equal, kUnexpectedStringType); 1990 __ pop(string); 1991 } 1992 1993 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding); 1994 if (encoding == String::ONE_BYTE_ENCODING) { 1995 __ movzx_b(result, operand); 1996 } else { 1997 __ movzx_w(result, operand); 1998 } 1999 } 2000 2001 2002 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { 2003 String::Encoding encoding = instr->hydrogen()->encoding(); 2004 Register string = ToRegister(instr->string()); 2005 2006 if (FLAG_debug_code) { 2007 Register value = ToRegister(instr->value()); 2008 Register index = ToRegister(instr->index()); 2009 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; 2010 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; 2011 int encoding_mask = 2012 instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING 2013 ? one_byte_seq_type : two_byte_seq_type; 2014 __ EmitSeqStringSetCharCheck(string, index, value, encoding_mask); 2015 } 2016 2017 Operand operand = BuildSeqStringOperand(string, instr->index(), encoding); 2018 if (instr->value()->IsConstantOperand()) { 2019 int value = ToRepresentation(LConstantOperand::cast(instr->value()), 2020 Representation::Integer32()); 2021 DCHECK_LE(0, value); 2022 if (encoding == String::ONE_BYTE_ENCODING) { 2023 DCHECK_LE(value, String::kMaxOneByteCharCode); 2024 __ mov_b(operand, static_cast<int8_t>(value)); 2025 } else { 2026 DCHECK_LE(value, String::kMaxUtf16CodeUnit); 2027 __ mov_w(operand, static_cast<int16_t>(value)); 2028 } 2029 } else { 2030 Register value = ToRegister(instr->value()); 2031 if (encoding == String::ONE_BYTE_ENCODING) { 2032 __ mov_b(operand, value); 2033 } else { 2034 __ mov_w(operand, value); 2035 } 2036 } 2037 } 2038 2039 2040 void LCodeGen::DoAddI(LAddI* instr) { 2041 LOperand* left = instr->left(); 2042 LOperand* right = instr->right(); 2043 2044 if (LAddI::UseLea(instr->hydrogen()) && !left->Equals(instr->result())) { 2045 if (right->IsConstantOperand()) { 2046 int32_t offset = ToRepresentation(LConstantOperand::cast(right), 2047 instr->hydrogen()->representation()); 2048 __ lea(ToRegister(instr->result()), MemOperand(ToRegister(left), offset)); 2049 } else { 2050 Operand address(ToRegister(left), ToRegister(right), times_1, 0); 2051 __ lea(ToRegister(instr->result()), address); 2052 } 2053 } else { 2054 if (right->IsConstantOperand()) { 2055 __ add(ToOperand(left), 2056 ToImmediate(right, instr->hydrogen()->representation())); 2057 } else { 2058 __ add(ToRegister(left), ToOperand(right)); 2059 } 2060 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 2061 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 2062 } 2063 } 2064 } 2065 2066 2067 void LCodeGen::DoMathMinMax(LMathMinMax* instr) { 2068 LOperand* left = instr->left(); 2069 LOperand* right = instr->right(); 2070 DCHECK(left->Equals(instr->result())); 2071 HMathMinMax::Operation operation = instr->hydrogen()->operation(); 2072 if (instr->hydrogen()->representation().IsSmiOrInteger32()) { 2073 Label return_left; 2074 Condition condition = (operation == HMathMinMax::kMathMin) 2075 ? less_equal 2076 : greater_equal; 2077 if (right->IsConstantOperand()) { 2078 Operand left_op = ToOperand(left); 2079 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->right()), 2080 instr->hydrogen()->representation()); 2081 __ cmp(left_op, immediate); 2082 __ j(condition, &return_left, Label::kNear); 2083 __ mov(left_op, immediate); 2084 } else { 2085 Register left_reg = ToRegister(left); 2086 Operand right_op = ToOperand(right); 2087 __ cmp(left_reg, right_op); 2088 __ j(condition, &return_left, Label::kNear); 2089 __ mov(left_reg, right_op); 2090 } 2091 __ bind(&return_left); 2092 } else { 2093 DCHECK(instr->hydrogen()->representation().IsDouble()); 2094 Label check_nan_left, check_zero, return_left, return_right; 2095 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above; 2096 X87Register left_reg = ToX87Register(left); 2097 X87Register right_reg = ToX87Register(right); 2098 2099 X87PrepareBinaryOp(left_reg, right_reg, ToX87Register(instr->result())); 2100 __ fld(1); 2101 __ fld(1); 2102 __ FCmp(); 2103 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. 2104 __ j(equal, &check_zero, Label::kNear); // left == right. 2105 __ j(condition, &return_left, Label::kNear); 2106 __ jmp(&return_right, Label::kNear); 2107 2108 __ bind(&check_zero); 2109 __ fld(0); 2110 __ fldz(); 2111 __ FCmp(); 2112 __ j(not_equal, &return_left, Label::kNear); // left == right != 0. 2113 // At this point, both left and right are either 0 or -0. 2114 if (operation == HMathMinMax::kMathMin) { 2115 // Push st0 and st1 to stack, then pop them to temp registers and OR them, 2116 // load it to left. 2117 Register scratch_reg = ToRegister(instr->temp()); 2118 __ fld(1); 2119 __ fld(1); 2120 __ sub(esp, Immediate(2 * kPointerSize)); 2121 __ fstp_s(MemOperand(esp, 0)); 2122 __ fstp_s(MemOperand(esp, kPointerSize)); 2123 __ pop(scratch_reg); 2124 __ xor_(MemOperand(esp, 0), scratch_reg); 2125 X87Mov(left_reg, MemOperand(esp, 0), kX87FloatOperand); 2126 __ pop(scratch_reg); // restore esp 2127 } else { 2128 // Since we operate on +0 and/or -0, addsd and andsd have the same effect. 2129 X87Fxch(left_reg); 2130 __ fadd(1); 2131 } 2132 __ jmp(&return_left, Label::kNear); 2133 2134 __ bind(&check_nan_left); 2135 __ fld(0); 2136 __ fld(0); 2137 __ FCmp(); // NaN check. 2138 __ j(parity_even, &return_left, Label::kNear); // left == NaN. 2139 2140 __ bind(&return_right); 2141 X87Fxch(left_reg); 2142 X87Mov(left_reg, right_reg); 2143 2144 __ bind(&return_left); 2145 } 2146 } 2147 2148 2149 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { 2150 X87Register left = ToX87Register(instr->left()); 2151 X87Register right = ToX87Register(instr->right()); 2152 X87Register result = ToX87Register(instr->result()); 2153 if (instr->op() != Token::MOD) { 2154 X87PrepareBinaryOp(left, right, result); 2155 } 2156 // Set the precision control to double-precision. 2157 __ X87SetFPUCW(0x027F); 2158 switch (instr->op()) { 2159 case Token::ADD: 2160 __ fadd_i(1); 2161 break; 2162 case Token::SUB: 2163 __ fsub_i(1); 2164 break; 2165 case Token::MUL: 2166 __ fmul_i(1); 2167 break; 2168 case Token::DIV: 2169 __ fdiv_i(1); 2170 break; 2171 case Token::MOD: { 2172 // Pass two doubles as arguments on the stack. 2173 __ PrepareCallCFunction(4, eax); 2174 X87Mov(Operand(esp, 1 * kDoubleSize), right); 2175 X87Mov(Operand(esp, 0), left); 2176 X87Free(right); 2177 DCHECK(left.is(result)); 2178 X87PrepareToWrite(result); 2179 __ CallCFunction( 2180 ExternalReference::mod_two_doubles_operation(isolate()), 2181 4); 2182 2183 // Return value is in st(0) on ia32. 2184 X87CommitWrite(result); 2185 break; 2186 } 2187 default: 2188 UNREACHABLE(); 2189 break; 2190 } 2191 2192 // Restore the default value of control word. 2193 __ X87SetFPUCW(0x037F); 2194 } 2195 2196 2197 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { 2198 DCHECK(ToRegister(instr->context()).is(esi)); 2199 DCHECK(ToRegister(instr->left()).is(edx)); 2200 DCHECK(ToRegister(instr->right()).is(eax)); 2201 DCHECK(ToRegister(instr->result()).is(eax)); 2202 2203 Handle<Code> code = 2204 CodeFactory::BinaryOpIC(isolate(), instr->op(), instr->strength()).code(); 2205 CallCode(code, RelocInfo::CODE_TARGET, instr); 2206 } 2207 2208 2209 template<class InstrType> 2210 void LCodeGen::EmitBranch(InstrType instr, Condition cc) { 2211 int left_block = instr->TrueDestination(chunk_); 2212 int right_block = instr->FalseDestination(chunk_); 2213 2214 int next_block = GetNextEmittedBlock(); 2215 2216 if (right_block == left_block || cc == no_condition) { 2217 EmitGoto(left_block); 2218 } else if (left_block == next_block) { 2219 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); 2220 } else if (right_block == next_block) { 2221 __ j(cc, chunk_->GetAssemblyLabel(left_block)); 2222 } else { 2223 __ j(cc, chunk_->GetAssemblyLabel(left_block)); 2224 __ jmp(chunk_->GetAssemblyLabel(right_block)); 2225 } 2226 } 2227 2228 2229 template <class InstrType> 2230 void LCodeGen::EmitTrueBranch(InstrType instr, Condition cc) { 2231 int true_block = instr->TrueDestination(chunk_); 2232 if (cc == no_condition) { 2233 __ jmp(chunk_->GetAssemblyLabel(true_block)); 2234 } else { 2235 __ j(cc, chunk_->GetAssemblyLabel(true_block)); 2236 } 2237 } 2238 2239 2240 template<class InstrType> 2241 void LCodeGen::EmitFalseBranch(InstrType instr, Condition cc) { 2242 int false_block = instr->FalseDestination(chunk_); 2243 if (cc == no_condition) { 2244 __ jmp(chunk_->GetAssemblyLabel(false_block)); 2245 } else { 2246 __ j(cc, chunk_->GetAssemblyLabel(false_block)); 2247 } 2248 } 2249 2250 2251 void LCodeGen::DoBranch(LBranch* instr) { 2252 Representation r = instr->hydrogen()->value()->representation(); 2253 if (r.IsSmiOrInteger32()) { 2254 Register reg = ToRegister(instr->value()); 2255 __ test(reg, Operand(reg)); 2256 EmitBranch(instr, not_zero); 2257 } else if (r.IsDouble()) { 2258 X87Register reg = ToX87Register(instr->value()); 2259 X87LoadForUsage(reg); 2260 __ fldz(); 2261 __ FCmp(); 2262 EmitBranch(instr, not_zero); 2263 } else { 2264 DCHECK(r.IsTagged()); 2265 Register reg = ToRegister(instr->value()); 2266 HType type = instr->hydrogen()->value()->type(); 2267 if (type.IsBoolean()) { 2268 DCHECK(!info()->IsStub()); 2269 __ cmp(reg, factory()->true_value()); 2270 EmitBranch(instr, equal); 2271 } else if (type.IsSmi()) { 2272 DCHECK(!info()->IsStub()); 2273 __ test(reg, Operand(reg)); 2274 EmitBranch(instr, not_equal); 2275 } else if (type.IsJSArray()) { 2276 DCHECK(!info()->IsStub()); 2277 EmitBranch(instr, no_condition); 2278 } else if (type.IsHeapNumber()) { 2279 UNREACHABLE(); 2280 } else if (type.IsString()) { 2281 DCHECK(!info()->IsStub()); 2282 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); 2283 EmitBranch(instr, not_equal); 2284 } else { 2285 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); 2286 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); 2287 2288 if (expected.Contains(ToBooleanStub::UNDEFINED)) { 2289 // undefined -> false. 2290 __ cmp(reg, factory()->undefined_value()); 2291 __ j(equal, instr->FalseLabel(chunk_)); 2292 } 2293 if (expected.Contains(ToBooleanStub::BOOLEAN)) { 2294 // true -> true. 2295 __ cmp(reg, factory()->true_value()); 2296 __ j(equal, instr->TrueLabel(chunk_)); 2297 // false -> false. 2298 __ cmp(reg, factory()->false_value()); 2299 __ j(equal, instr->FalseLabel(chunk_)); 2300 } 2301 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { 2302 // 'null' -> false. 2303 __ cmp(reg, factory()->null_value()); 2304 __ j(equal, instr->FalseLabel(chunk_)); 2305 } 2306 2307 if (expected.Contains(ToBooleanStub::SMI)) { 2308 // Smis: 0 -> false, all other -> true. 2309 __ test(reg, Operand(reg)); 2310 __ j(equal, instr->FalseLabel(chunk_)); 2311 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); 2312 } else if (expected.NeedsMap()) { 2313 // If we need a map later and have a Smi -> deopt. 2314 __ test(reg, Immediate(kSmiTagMask)); 2315 DeoptimizeIf(zero, instr, Deoptimizer::kSmi); 2316 } 2317 2318 Register map = no_reg; // Keep the compiler happy. 2319 if (expected.NeedsMap()) { 2320 map = ToRegister(instr->temp()); 2321 DCHECK(!map.is(reg)); 2322 __ mov(map, FieldOperand(reg, HeapObject::kMapOffset)); 2323 2324 if (expected.CanBeUndetectable()) { 2325 // Undetectable -> false. 2326 __ test_b(FieldOperand(map, Map::kBitFieldOffset), 2327 1 << Map::kIsUndetectable); 2328 __ j(not_zero, instr->FalseLabel(chunk_)); 2329 } 2330 } 2331 2332 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { 2333 // spec object -> true. 2334 __ CmpInstanceType(map, FIRST_JS_RECEIVER_TYPE); 2335 __ j(above_equal, instr->TrueLabel(chunk_)); 2336 } 2337 2338 if (expected.Contains(ToBooleanStub::STRING)) { 2339 // String value -> false iff empty. 2340 Label not_string; 2341 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 2342 __ j(above_equal, ¬_string, Label::kNear); 2343 __ cmp(FieldOperand(reg, String::kLengthOffset), Immediate(0)); 2344 __ j(not_zero, instr->TrueLabel(chunk_)); 2345 __ jmp(instr->FalseLabel(chunk_)); 2346 __ bind(¬_string); 2347 } 2348 2349 if (expected.Contains(ToBooleanStub::SYMBOL)) { 2350 // Symbol value -> true. 2351 __ CmpInstanceType(map, SYMBOL_TYPE); 2352 __ j(equal, instr->TrueLabel(chunk_)); 2353 } 2354 2355 if (expected.Contains(ToBooleanStub::SIMD_VALUE)) { 2356 // SIMD value -> true. 2357 __ CmpInstanceType(map, SIMD128_VALUE_TYPE); 2358 __ j(equal, instr->TrueLabel(chunk_)); 2359 } 2360 2361 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { 2362 // heap number -> false iff +0, -0, or NaN. 2363 Label not_heap_number; 2364 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), 2365 factory()->heap_number_map()); 2366 __ j(not_equal, ¬_heap_number, Label::kNear); 2367 __ fldz(); 2368 __ fld_d(FieldOperand(reg, HeapNumber::kValueOffset)); 2369 __ FCmp(); 2370 __ j(zero, instr->FalseLabel(chunk_)); 2371 __ jmp(instr->TrueLabel(chunk_)); 2372 __ bind(¬_heap_number); 2373 } 2374 2375 if (!expected.IsGeneric()) { 2376 // We've seen something for the first time -> deopt. 2377 // This can only happen if we are not generic already. 2378 DeoptimizeIf(no_condition, instr, Deoptimizer::kUnexpectedObject); 2379 } 2380 } 2381 } 2382 } 2383 2384 2385 void LCodeGen::EmitGoto(int block) { 2386 if (!IsNextEmittedBlock(block)) { 2387 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); 2388 } 2389 } 2390 2391 2392 void LCodeGen::DoClobberDoubles(LClobberDoubles* instr) { 2393 } 2394 2395 2396 void LCodeGen::DoGoto(LGoto* instr) { 2397 EmitGoto(instr->block_id()); 2398 } 2399 2400 2401 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { 2402 Condition cond = no_condition; 2403 switch (op) { 2404 case Token::EQ: 2405 case Token::EQ_STRICT: 2406 cond = equal; 2407 break; 2408 case Token::NE: 2409 case Token::NE_STRICT: 2410 cond = not_equal; 2411 break; 2412 case Token::LT: 2413 cond = is_unsigned ? below : less; 2414 break; 2415 case Token::GT: 2416 cond = is_unsigned ? above : greater; 2417 break; 2418 case Token::LTE: 2419 cond = is_unsigned ? below_equal : less_equal; 2420 break; 2421 case Token::GTE: 2422 cond = is_unsigned ? above_equal : greater_equal; 2423 break; 2424 case Token::IN: 2425 case Token::INSTANCEOF: 2426 default: 2427 UNREACHABLE(); 2428 } 2429 return cond; 2430 } 2431 2432 2433 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) { 2434 LOperand* left = instr->left(); 2435 LOperand* right = instr->right(); 2436 bool is_unsigned = 2437 instr->is_double() || 2438 instr->hydrogen()->left()->CheckFlag(HInstruction::kUint32) || 2439 instr->hydrogen()->right()->CheckFlag(HInstruction::kUint32); 2440 Condition cc = TokenToCondition(instr->op(), is_unsigned); 2441 2442 if (left->IsConstantOperand() && right->IsConstantOperand()) { 2443 // We can statically evaluate the comparison. 2444 double left_val = ToDouble(LConstantOperand::cast(left)); 2445 double right_val = ToDouble(LConstantOperand::cast(right)); 2446 int next_block = EvalComparison(instr->op(), left_val, right_val) ? 2447 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_); 2448 EmitGoto(next_block); 2449 } else { 2450 if (instr->is_double()) { 2451 X87LoadForUsage(ToX87Register(right), ToX87Register(left)); 2452 __ FCmp(); 2453 // Don't base result on EFLAGS when a NaN is involved. Instead 2454 // jump to the false block. 2455 __ j(parity_even, instr->FalseLabel(chunk_)); 2456 } else { 2457 if (right->IsConstantOperand()) { 2458 __ cmp(ToOperand(left), 2459 ToImmediate(right, instr->hydrogen()->representation())); 2460 } else if (left->IsConstantOperand()) { 2461 __ cmp(ToOperand(right), 2462 ToImmediate(left, instr->hydrogen()->representation())); 2463 // We commuted the operands, so commute the condition. 2464 cc = CommuteCondition(cc); 2465 } else { 2466 __ cmp(ToRegister(left), ToOperand(right)); 2467 } 2468 } 2469 EmitBranch(instr, cc); 2470 } 2471 } 2472 2473 2474 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { 2475 Register left = ToRegister(instr->left()); 2476 2477 if (instr->right()->IsConstantOperand()) { 2478 Handle<Object> right = ToHandle(LConstantOperand::cast(instr->right())); 2479 __ CmpObject(left, right); 2480 } else { 2481 Operand right = ToOperand(instr->right()); 2482 __ cmp(left, right); 2483 } 2484 EmitBranch(instr, equal); 2485 } 2486 2487 2488 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { 2489 if (instr->hydrogen()->representation().IsTagged()) { 2490 Register input_reg = ToRegister(instr->object()); 2491 __ cmp(input_reg, factory()->the_hole_value()); 2492 EmitBranch(instr, equal); 2493 return; 2494 } 2495 2496 // Put the value to the top of stack 2497 X87Register src = ToX87Register(instr->object()); 2498 X87LoadForUsage(src); 2499 __ fld(0); 2500 __ fld(0); 2501 __ FCmp(); 2502 Label ok; 2503 __ j(parity_even, &ok, Label::kNear); 2504 __ fstp(0); 2505 EmitFalseBranch(instr, no_condition); 2506 __ bind(&ok); 2507 2508 2509 __ sub(esp, Immediate(kDoubleSize)); 2510 __ fstp_d(MemOperand(esp, 0)); 2511 2512 __ add(esp, Immediate(kDoubleSize)); 2513 int offset = sizeof(kHoleNanUpper32); 2514 // x87 converts sNaN(0xfff7fffffff7ffff) to QNaN(0xfffffffffff7ffff), 2515 // so we check the upper with 0xffffffff for hole as a temporary fix. 2516 __ cmp(MemOperand(esp, -offset), Immediate(0xffffffff)); 2517 EmitBranch(instr, equal); 2518 } 2519 2520 2521 void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) { 2522 Representation rep = instr->hydrogen()->value()->representation(); 2523 DCHECK(!rep.IsInteger32()); 2524 2525 if (rep.IsDouble()) { 2526 X87Register input = ToX87Register(instr->value()); 2527 X87LoadForUsage(input); 2528 __ FXamMinusZero(); 2529 EmitBranch(instr, equal); 2530 } else { 2531 Register value = ToRegister(instr->value()); 2532 Handle<Map> map = masm()->isolate()->factory()->heap_number_map(); 2533 __ CheckMap(value, map, instr->FalseLabel(chunk()), DO_SMI_CHECK); 2534 __ cmp(FieldOperand(value, HeapNumber::kExponentOffset), 2535 Immediate(0x1)); 2536 EmitFalseBranch(instr, no_overflow); 2537 __ cmp(FieldOperand(value, HeapNumber::kMantissaOffset), 2538 Immediate(0x00000000)); 2539 EmitBranch(instr, equal); 2540 } 2541 } 2542 2543 2544 Condition LCodeGen::EmitIsString(Register input, 2545 Register temp1, 2546 Label* is_not_string, 2547 SmiCheck check_needed = INLINE_SMI_CHECK) { 2548 if (check_needed == INLINE_SMI_CHECK) { 2549 __ JumpIfSmi(input, is_not_string); 2550 } 2551 2552 Condition cond = masm_->IsObjectStringType(input, temp1, temp1); 2553 2554 return cond; 2555 } 2556 2557 2558 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { 2559 Register reg = ToRegister(instr->value()); 2560 Register temp = ToRegister(instr->temp()); 2561 2562 SmiCheck check_needed = 2563 instr->hydrogen()->value()->type().IsHeapObject() 2564 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 2565 2566 Condition true_cond = EmitIsString( 2567 reg, temp, instr->FalseLabel(chunk_), check_needed); 2568 2569 EmitBranch(instr, true_cond); 2570 } 2571 2572 2573 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { 2574 Operand input = ToOperand(instr->value()); 2575 2576 __ test(input, Immediate(kSmiTagMask)); 2577 EmitBranch(instr, zero); 2578 } 2579 2580 2581 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { 2582 Register input = ToRegister(instr->value()); 2583 Register temp = ToRegister(instr->temp()); 2584 2585 if (!instr->hydrogen()->value()->type().IsHeapObject()) { 2586 STATIC_ASSERT(kSmiTag == 0); 2587 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); 2588 } 2589 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); 2590 __ test_b(FieldOperand(temp, Map::kBitFieldOffset), 2591 1 << Map::kIsUndetectable); 2592 EmitBranch(instr, not_zero); 2593 } 2594 2595 2596 static Condition ComputeCompareCondition(Token::Value op) { 2597 switch (op) { 2598 case Token::EQ_STRICT: 2599 case Token::EQ: 2600 return equal; 2601 case Token::LT: 2602 return less; 2603 case Token::GT: 2604 return greater; 2605 case Token::LTE: 2606 return less_equal; 2607 case Token::GTE: 2608 return greater_equal; 2609 default: 2610 UNREACHABLE(); 2611 return no_condition; 2612 } 2613 } 2614 2615 2616 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { 2617 DCHECK(ToRegister(instr->context()).is(esi)); 2618 DCHECK(ToRegister(instr->left()).is(edx)); 2619 DCHECK(ToRegister(instr->right()).is(eax)); 2620 2621 Handle<Code> code = CodeFactory::StringCompare(isolate()).code(); 2622 CallCode(code, RelocInfo::CODE_TARGET, instr); 2623 __ test(eax, eax); 2624 2625 EmitBranch(instr, ComputeCompareCondition(instr->op())); 2626 } 2627 2628 2629 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { 2630 InstanceType from = instr->from(); 2631 InstanceType to = instr->to(); 2632 if (from == FIRST_TYPE) return to; 2633 DCHECK(from == to || to == LAST_TYPE); 2634 return from; 2635 } 2636 2637 2638 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { 2639 InstanceType from = instr->from(); 2640 InstanceType to = instr->to(); 2641 if (from == to) return equal; 2642 if (to == LAST_TYPE) return above_equal; 2643 if (from == FIRST_TYPE) return below_equal; 2644 UNREACHABLE(); 2645 return equal; 2646 } 2647 2648 2649 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { 2650 Register input = ToRegister(instr->value()); 2651 Register temp = ToRegister(instr->temp()); 2652 2653 if (!instr->hydrogen()->value()->type().IsHeapObject()) { 2654 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); 2655 } 2656 2657 __ CmpObjectType(input, TestType(instr->hydrogen()), temp); 2658 EmitBranch(instr, BranchCondition(instr->hydrogen())); 2659 } 2660 2661 2662 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { 2663 Register input = ToRegister(instr->value()); 2664 Register result = ToRegister(instr->result()); 2665 2666 __ AssertString(input); 2667 2668 __ mov(result, FieldOperand(input, String::kHashFieldOffset)); 2669 __ IndexFromHash(result, result); 2670 } 2671 2672 2673 void LCodeGen::DoHasCachedArrayIndexAndBranch( 2674 LHasCachedArrayIndexAndBranch* instr) { 2675 Register input = ToRegister(instr->value()); 2676 2677 __ test(FieldOperand(input, String::kHashFieldOffset), 2678 Immediate(String::kContainsCachedArrayIndexMask)); 2679 EmitBranch(instr, equal); 2680 } 2681 2682 2683 // Branches to a label or falls through with the answer in the z flag. Trashes 2684 // the temp registers, but not the input. 2685 void LCodeGen::EmitClassOfTest(Label* is_true, 2686 Label* is_false, 2687 Handle<String>class_name, 2688 Register input, 2689 Register temp, 2690 Register temp2) { 2691 DCHECK(!input.is(temp)); 2692 DCHECK(!input.is(temp2)); 2693 DCHECK(!temp.is(temp2)); 2694 __ JumpIfSmi(input, is_false); 2695 2696 __ CmpObjectType(input, JS_FUNCTION_TYPE, temp); 2697 if (String::Equals(isolate()->factory()->Function_string(), class_name)) { 2698 __ j(equal, is_true); 2699 } else { 2700 __ j(equal, is_false); 2701 } 2702 2703 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. 2704 // Check if the constructor in the map is a function. 2705 __ GetMapConstructor(temp, temp, temp2); 2706 // Objects with a non-function constructor have class 'Object'. 2707 __ CmpInstanceType(temp2, JS_FUNCTION_TYPE); 2708 if (String::Equals(class_name, isolate()->factory()->Object_string())) { 2709 __ j(not_equal, is_true); 2710 } else { 2711 __ j(not_equal, is_false); 2712 } 2713 2714 // temp now contains the constructor function. Grab the 2715 // instance class name from there. 2716 __ mov(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); 2717 __ mov(temp, FieldOperand(temp, 2718 SharedFunctionInfo::kInstanceClassNameOffset)); 2719 // The class name we are testing against is internalized since it's a literal. 2720 // The name in the constructor is internalized because of the way the context 2721 // is booted. This routine isn't expected to work for random API-created 2722 // classes and it doesn't have to because you can't access it with natives 2723 // syntax. Since both sides are internalized it is sufficient to use an 2724 // identity comparison. 2725 __ cmp(temp, class_name); 2726 // End with the answer in the z flag. 2727 } 2728 2729 2730 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { 2731 Register input = ToRegister(instr->value()); 2732 Register temp = ToRegister(instr->temp()); 2733 Register temp2 = ToRegister(instr->temp2()); 2734 2735 Handle<String> class_name = instr->hydrogen()->class_name(); 2736 2737 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), 2738 class_name, input, temp, temp2); 2739 2740 EmitBranch(instr, equal); 2741 } 2742 2743 2744 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { 2745 Register reg = ToRegister(instr->value()); 2746 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); 2747 EmitBranch(instr, equal); 2748 } 2749 2750 2751 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { 2752 DCHECK(ToRegister(instr->context()).is(esi)); 2753 DCHECK(ToRegister(instr->left()).is(InstanceOfDescriptor::LeftRegister())); 2754 DCHECK(ToRegister(instr->right()).is(InstanceOfDescriptor::RightRegister())); 2755 DCHECK(ToRegister(instr->result()).is(eax)); 2756 InstanceOfStub stub(isolate()); 2757 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 2758 } 2759 2760 2761 void LCodeGen::DoHasInPrototypeChainAndBranch( 2762 LHasInPrototypeChainAndBranch* instr) { 2763 Register const object = ToRegister(instr->object()); 2764 Register const object_map = ToRegister(instr->scratch()); 2765 Register const object_prototype = object_map; 2766 Register const prototype = ToRegister(instr->prototype()); 2767 2768 // The {object} must be a spec object. It's sufficient to know that {object} 2769 // is not a smi, since all other non-spec objects have {null} prototypes and 2770 // will be ruled out below. 2771 if (instr->hydrogen()->ObjectNeedsSmiCheck()) { 2772 __ test(object, Immediate(kSmiTagMask)); 2773 EmitFalseBranch(instr, zero); 2774 } 2775 2776 // Loop through the {object}s prototype chain looking for the {prototype}. 2777 __ mov(object_map, FieldOperand(object, HeapObject::kMapOffset)); 2778 Label loop; 2779 __ bind(&loop); 2780 2781 // Deoptimize if the object needs to be access checked. 2782 __ test_b(FieldOperand(object_map, Map::kBitFieldOffset), 2783 1 << Map::kIsAccessCheckNeeded); 2784 DeoptimizeIf(not_zero, instr, Deoptimizer::kAccessCheck); 2785 // Deoptimize for proxies. 2786 __ CmpInstanceType(object_map, JS_PROXY_TYPE); 2787 DeoptimizeIf(equal, instr, Deoptimizer::kProxy); 2788 2789 __ mov(object_prototype, FieldOperand(object_map, Map::kPrototypeOffset)); 2790 __ cmp(object_prototype, prototype); 2791 EmitTrueBranch(instr, equal); 2792 __ cmp(object_prototype, factory()->null_value()); 2793 EmitFalseBranch(instr, equal); 2794 __ mov(object_map, FieldOperand(object_prototype, HeapObject::kMapOffset)); 2795 __ jmp(&loop); 2796 } 2797 2798 2799 void LCodeGen::DoCmpT(LCmpT* instr) { 2800 Token::Value op = instr->op(); 2801 2802 Handle<Code> ic = 2803 CodeFactory::CompareIC(isolate(), op, instr->strength()).code(); 2804 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2805 2806 Condition condition = ComputeCompareCondition(op); 2807 Label true_value, done; 2808 __ test(eax, Operand(eax)); 2809 __ j(condition, &true_value, Label::kNear); 2810 __ mov(ToRegister(instr->result()), factory()->false_value()); 2811 __ jmp(&done, Label::kNear); 2812 __ bind(&true_value); 2813 __ mov(ToRegister(instr->result()), factory()->true_value()); 2814 __ bind(&done); 2815 } 2816 2817 2818 void LCodeGen::EmitReturn(LReturn* instr, bool dynamic_frame_alignment) { 2819 int extra_value_count = dynamic_frame_alignment ? 2 : 1; 2820 2821 if (instr->has_constant_parameter_count()) { 2822 int parameter_count = ToInteger32(instr->constant_parameter_count()); 2823 if (dynamic_frame_alignment && FLAG_debug_code) { 2824 __ cmp(Operand(esp, 2825 (parameter_count + extra_value_count) * kPointerSize), 2826 Immediate(kAlignmentZapValue)); 2827 __ Assert(equal, kExpectedAlignmentMarker); 2828 } 2829 __ Ret((parameter_count + extra_value_count) * kPointerSize, ecx); 2830 } else { 2831 DCHECK(info()->IsStub()); // Functions would need to drop one more value. 2832 Register reg = ToRegister(instr->parameter_count()); 2833 // The argument count parameter is a smi 2834 __ SmiUntag(reg); 2835 Register return_addr_reg = reg.is(ecx) ? ebx : ecx; 2836 if (dynamic_frame_alignment && FLAG_debug_code) { 2837 DCHECK(extra_value_count == 2); 2838 __ cmp(Operand(esp, reg, times_pointer_size, 2839 extra_value_count * kPointerSize), 2840 Immediate(kAlignmentZapValue)); 2841 __ Assert(equal, kExpectedAlignmentMarker); 2842 } 2843 2844 // emit code to restore stack based on instr->parameter_count() 2845 __ pop(return_addr_reg); // save return address 2846 if (dynamic_frame_alignment) { 2847 __ inc(reg); // 1 more for alignment 2848 } 2849 __ shl(reg, kPointerSizeLog2); 2850 __ add(esp, reg); 2851 __ jmp(return_addr_reg); 2852 } 2853 } 2854 2855 2856 void LCodeGen::DoReturn(LReturn* instr) { 2857 if (FLAG_trace && info()->IsOptimizing()) { 2858 // Preserve the return value on the stack and rely on the runtime call 2859 // to return the value in the same register. We're leaving the code 2860 // managed by the register allocator and tearing down the frame, it's 2861 // safe to write to the context register. 2862 __ push(eax); 2863 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 2864 __ CallRuntime(Runtime::kTraceExit); 2865 } 2866 if (dynamic_frame_alignment_) { 2867 // Fetch the state of the dynamic frame alignment. 2868 __ mov(edx, Operand(ebp, 2869 JavaScriptFrameConstants::kDynamicAlignmentStateOffset)); 2870 } 2871 if (NeedsEagerFrame()) { 2872 __ mov(esp, ebp); 2873 __ pop(ebp); 2874 } 2875 if (dynamic_frame_alignment_) { 2876 Label no_padding; 2877 __ cmp(edx, Immediate(kNoAlignmentPadding)); 2878 __ j(equal, &no_padding, Label::kNear); 2879 2880 EmitReturn(instr, true); 2881 __ bind(&no_padding); 2882 } 2883 2884 EmitReturn(instr, false); 2885 } 2886 2887 2888 template <class T> 2889 void LCodeGen::EmitVectorLoadICRegisters(T* instr) { 2890 Register vector_register = ToRegister(instr->temp_vector()); 2891 Register slot_register = LoadWithVectorDescriptor::SlotRegister(); 2892 DCHECK(vector_register.is(LoadWithVectorDescriptor::VectorRegister())); 2893 DCHECK(slot_register.is(eax)); 2894 2895 AllowDeferredHandleDereference vector_structure_check; 2896 Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector(); 2897 __ mov(vector_register, vector); 2898 // No need to allocate this register. 2899 FeedbackVectorSlot slot = instr->hydrogen()->slot(); 2900 int index = vector->GetIndex(slot); 2901 __ mov(slot_register, Immediate(Smi::FromInt(index))); 2902 } 2903 2904 2905 template <class T> 2906 void LCodeGen::EmitVectorStoreICRegisters(T* instr) { 2907 Register vector_register = ToRegister(instr->temp_vector()); 2908 Register slot_register = ToRegister(instr->temp_slot()); 2909 2910 AllowDeferredHandleDereference vector_structure_check; 2911 Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector(); 2912 __ mov(vector_register, vector); 2913 FeedbackVectorSlot slot = instr->hydrogen()->slot(); 2914 int index = vector->GetIndex(slot); 2915 __ mov(slot_register, Immediate(Smi::FromInt(index))); 2916 } 2917 2918 2919 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { 2920 DCHECK(ToRegister(instr->context()).is(esi)); 2921 DCHECK(ToRegister(instr->global_object()) 2922 .is(LoadDescriptor::ReceiverRegister())); 2923 DCHECK(ToRegister(instr->result()).is(eax)); 2924 2925 __ mov(LoadDescriptor::NameRegister(), instr->name()); 2926 EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr); 2927 Handle<Code> ic = 2928 CodeFactory::LoadICInOptimizedCode(isolate(), instr->typeof_mode(), 2929 SLOPPY, PREMONOMORPHIC).code(); 2930 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2931 } 2932 2933 2934 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { 2935 Register context = ToRegister(instr->context()); 2936 Register result = ToRegister(instr->result()); 2937 __ mov(result, ContextOperand(context, instr->slot_index())); 2938 2939 if (instr->hydrogen()->RequiresHoleCheck()) { 2940 __ cmp(result, factory()->the_hole_value()); 2941 if (instr->hydrogen()->DeoptimizesOnHole()) { 2942 DeoptimizeIf(equal, instr, Deoptimizer::kHole); 2943 } else { 2944 Label is_not_hole; 2945 __ j(not_equal, &is_not_hole, Label::kNear); 2946 __ mov(result, factory()->undefined_value()); 2947 __ bind(&is_not_hole); 2948 } 2949 } 2950 } 2951 2952 2953 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { 2954 Register context = ToRegister(instr->context()); 2955 Register value = ToRegister(instr->value()); 2956 2957 Label skip_assignment; 2958 2959 Operand target = ContextOperand(context, instr->slot_index()); 2960 if (instr->hydrogen()->RequiresHoleCheck()) { 2961 __ cmp(target, factory()->the_hole_value()); 2962 if (instr->hydrogen()->DeoptimizesOnHole()) { 2963 DeoptimizeIf(equal, instr, Deoptimizer::kHole); 2964 } else { 2965 __ j(not_equal, &skip_assignment, Label::kNear); 2966 } 2967 } 2968 2969 __ mov(target, value); 2970 if (instr->hydrogen()->NeedsWriteBarrier()) { 2971 SmiCheck check_needed = 2972 instr->hydrogen()->value()->type().IsHeapObject() 2973 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 2974 Register temp = ToRegister(instr->temp()); 2975 int offset = Context::SlotOffset(instr->slot_index()); 2976 __ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs, 2977 EMIT_REMEMBERED_SET, check_needed); 2978 } 2979 2980 __ bind(&skip_assignment); 2981 } 2982 2983 2984 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { 2985 HObjectAccess access = instr->hydrogen()->access(); 2986 int offset = access.offset(); 2987 2988 if (access.IsExternalMemory()) { 2989 Register result = ToRegister(instr->result()); 2990 MemOperand operand = instr->object()->IsConstantOperand() 2991 ? MemOperand::StaticVariable(ToExternalReference( 2992 LConstantOperand::cast(instr->object()))) 2993 : MemOperand(ToRegister(instr->object()), offset); 2994 __ Load(result, operand, access.representation()); 2995 return; 2996 } 2997 2998 Register object = ToRegister(instr->object()); 2999 if (instr->hydrogen()->representation().IsDouble()) { 3000 X87Mov(ToX87Register(instr->result()), FieldOperand(object, offset)); 3001 return; 3002 } 3003 3004 Register result = ToRegister(instr->result()); 3005 if (!access.IsInobject()) { 3006 __ mov(result, FieldOperand(object, JSObject::kPropertiesOffset)); 3007 object = result; 3008 } 3009 __ Load(result, FieldOperand(object, offset), access.representation()); 3010 } 3011 3012 3013 void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { 3014 DCHECK(!operand->IsDoubleRegister()); 3015 if (operand->IsConstantOperand()) { 3016 Handle<Object> object = ToHandle(LConstantOperand::cast(operand)); 3017 AllowDeferredHandleDereference smi_check; 3018 if (object->IsSmi()) { 3019 __ Push(Handle<Smi>::cast(object)); 3020 } else { 3021 __ PushHeapObject(Handle<HeapObject>::cast(object)); 3022 } 3023 } else if (operand->IsRegister()) { 3024 __ push(ToRegister(operand)); 3025 } else { 3026 __ push(ToOperand(operand)); 3027 } 3028 } 3029 3030 3031 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { 3032 DCHECK(ToRegister(instr->context()).is(esi)); 3033 DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister())); 3034 DCHECK(ToRegister(instr->result()).is(eax)); 3035 3036 __ mov(LoadDescriptor::NameRegister(), instr->name()); 3037 EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr); 3038 Handle<Code> ic = 3039 CodeFactory::LoadICInOptimizedCode( 3040 isolate(), NOT_INSIDE_TYPEOF, instr->hydrogen()->language_mode(), 3041 instr->hydrogen()->initialization_state()).code(); 3042 CallCode(ic, RelocInfo::CODE_TARGET, instr); 3043 } 3044 3045 3046 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { 3047 Register function = ToRegister(instr->function()); 3048 Register temp = ToRegister(instr->temp()); 3049 Register result = ToRegister(instr->result()); 3050 3051 // Get the prototype or initial map from the function. 3052 __ mov(result, 3053 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 3054 3055 // Check that the function has a prototype or an initial map. 3056 __ cmp(Operand(result), Immediate(factory()->the_hole_value())); 3057 DeoptimizeIf(equal, instr, Deoptimizer::kHole); 3058 3059 // If the function does not have an initial map, we're done. 3060 Label done; 3061 __ CmpObjectType(result, MAP_TYPE, temp); 3062 __ j(not_equal, &done, Label::kNear); 3063 3064 // Get the prototype from the initial map. 3065 __ mov(result, FieldOperand(result, Map::kPrototypeOffset)); 3066 3067 // All done. 3068 __ bind(&done); 3069 } 3070 3071 3072 void LCodeGen::DoLoadRoot(LLoadRoot* instr) { 3073 Register result = ToRegister(instr->result()); 3074 __ LoadRoot(result, instr->index()); 3075 } 3076 3077 3078 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { 3079 Register arguments = ToRegister(instr->arguments()); 3080 Register result = ToRegister(instr->result()); 3081 if (instr->length()->IsConstantOperand() && 3082 instr->index()->IsConstantOperand()) { 3083 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); 3084 int const_length = ToInteger32(LConstantOperand::cast(instr->length())); 3085 int index = (const_length - const_index) + 1; 3086 __ mov(result, Operand(arguments, index * kPointerSize)); 3087 } else { 3088 Register length = ToRegister(instr->length()); 3089 Operand index = ToOperand(instr->index()); 3090 // There are two words between the frame pointer and the last argument. 3091 // Subtracting from length accounts for one of them add one more. 3092 __ sub(length, index); 3093 __ mov(result, Operand(arguments, length, times_4, kPointerSize)); 3094 } 3095 } 3096 3097 3098 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { 3099 ElementsKind elements_kind = instr->elements_kind(); 3100 LOperand* key = instr->key(); 3101 if (!key->IsConstantOperand() && 3102 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), 3103 elements_kind)) { 3104 __ SmiUntag(ToRegister(key)); 3105 } 3106 Operand operand(BuildFastArrayOperand( 3107 instr->elements(), 3108 key, 3109 instr->hydrogen()->key()->representation(), 3110 elements_kind, 3111 instr->base_offset())); 3112 if (elements_kind == FLOAT32_ELEMENTS) { 3113 X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand); 3114 } else if (elements_kind == FLOAT64_ELEMENTS) { 3115 X87Mov(ToX87Register(instr->result()), operand); 3116 } else { 3117 Register result(ToRegister(instr->result())); 3118 switch (elements_kind) { 3119 case INT8_ELEMENTS: 3120 __ movsx_b(result, operand); 3121 break; 3122 case UINT8_ELEMENTS: 3123 case UINT8_CLAMPED_ELEMENTS: 3124 __ movzx_b(result, operand); 3125 break; 3126 case INT16_ELEMENTS: 3127 __ movsx_w(result, operand); 3128 break; 3129 case UINT16_ELEMENTS: 3130 __ movzx_w(result, operand); 3131 break; 3132 case INT32_ELEMENTS: 3133 __ mov(result, operand); 3134 break; 3135 case UINT32_ELEMENTS: 3136 __ mov(result, operand); 3137 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { 3138 __ test(result, Operand(result)); 3139 DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue); 3140 } 3141 break; 3142 case FLOAT32_ELEMENTS: 3143 case FLOAT64_ELEMENTS: 3144 case FAST_SMI_ELEMENTS: 3145 case FAST_ELEMENTS: 3146 case FAST_DOUBLE_ELEMENTS: 3147 case FAST_HOLEY_SMI_ELEMENTS: 3148 case FAST_HOLEY_ELEMENTS: 3149 case FAST_HOLEY_DOUBLE_ELEMENTS: 3150 case DICTIONARY_ELEMENTS: 3151 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 3152 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 3153 UNREACHABLE(); 3154 break; 3155 } 3156 } 3157 } 3158 3159 3160 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { 3161 if (instr->hydrogen()->RequiresHoleCheck()) { 3162 Operand hole_check_operand = BuildFastArrayOperand( 3163 instr->elements(), instr->key(), 3164 instr->hydrogen()->key()->representation(), 3165 FAST_DOUBLE_ELEMENTS, 3166 instr->base_offset() + sizeof(kHoleNanLower32)); 3167 __ cmp(hole_check_operand, Immediate(kHoleNanUpper32)); 3168 DeoptimizeIf(equal, instr, Deoptimizer::kHole); 3169 } 3170 3171 Operand double_load_operand = BuildFastArrayOperand( 3172 instr->elements(), 3173 instr->key(), 3174 instr->hydrogen()->key()->representation(), 3175 FAST_DOUBLE_ELEMENTS, 3176 instr->base_offset()); 3177 X87Mov(ToX87Register(instr->result()), double_load_operand); 3178 } 3179 3180 3181 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { 3182 Register result = ToRegister(instr->result()); 3183 3184 // Load the result. 3185 __ mov(result, 3186 BuildFastArrayOperand(instr->elements(), instr->key(), 3187 instr->hydrogen()->key()->representation(), 3188 FAST_ELEMENTS, instr->base_offset())); 3189 3190 // Check for the hole value. 3191 if (instr->hydrogen()->RequiresHoleCheck()) { 3192 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { 3193 __ test(result, Immediate(kSmiTagMask)); 3194 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotASmi); 3195 } else { 3196 __ cmp(result, factory()->the_hole_value()); 3197 DeoptimizeIf(equal, instr, Deoptimizer::kHole); 3198 } 3199 } else if (instr->hydrogen()->hole_mode() == CONVERT_HOLE_TO_UNDEFINED) { 3200 DCHECK(instr->hydrogen()->elements_kind() == FAST_HOLEY_ELEMENTS); 3201 Label done; 3202 __ cmp(result, factory()->the_hole_value()); 3203 __ j(not_equal, &done); 3204 if (info()->IsStub()) { 3205 // A stub can safely convert the hole to undefined only if the array 3206 // protector cell contains (Smi) Isolate::kArrayProtectorValid. Otherwise 3207 // it needs to bail out. 3208 __ mov(result, isolate()->factory()->array_protector()); 3209 __ cmp(FieldOperand(result, PropertyCell::kValueOffset), 3210 Immediate(Smi::FromInt(Isolate::kArrayProtectorValid))); 3211 DeoptimizeIf(not_equal, instr, Deoptimizer::kHole); 3212 } 3213 __ mov(result, isolate()->factory()->undefined_value()); 3214 __ bind(&done); 3215 } 3216 } 3217 3218 3219 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { 3220 if (instr->is_fixed_typed_array()) { 3221 DoLoadKeyedExternalArray(instr); 3222 } else if (instr->hydrogen()->representation().IsDouble()) { 3223 DoLoadKeyedFixedDoubleArray(instr); 3224 } else { 3225 DoLoadKeyedFixedArray(instr); 3226 } 3227 } 3228 3229 3230 Operand LCodeGen::BuildFastArrayOperand( 3231 LOperand* elements_pointer, 3232 LOperand* key, 3233 Representation key_representation, 3234 ElementsKind elements_kind, 3235 uint32_t base_offset) { 3236 Register elements_pointer_reg = ToRegister(elements_pointer); 3237 int element_shift_size = ElementsKindToShiftSize(elements_kind); 3238 int shift_size = element_shift_size; 3239 if (key->IsConstantOperand()) { 3240 int constant_value = ToInteger32(LConstantOperand::cast(key)); 3241 if (constant_value & 0xF0000000) { 3242 Abort(kArrayIndexConstantValueTooBig); 3243 } 3244 return Operand(elements_pointer_reg, 3245 ((constant_value) << shift_size) 3246 + base_offset); 3247 } else { 3248 // Take the tag bit into account while computing the shift size. 3249 if (key_representation.IsSmi() && (shift_size >= 1)) { 3250 shift_size -= kSmiTagSize; 3251 } 3252 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); 3253 return Operand(elements_pointer_reg, 3254 ToRegister(key), 3255 scale_factor, 3256 base_offset); 3257 } 3258 } 3259 3260 3261 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { 3262 DCHECK(ToRegister(instr->context()).is(esi)); 3263 DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister())); 3264 DCHECK(ToRegister(instr->key()).is(LoadDescriptor::NameRegister())); 3265 3266 if (instr->hydrogen()->HasVectorAndSlot()) { 3267 EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr); 3268 } 3269 3270 Handle<Code> ic = CodeFactory::KeyedLoadICInOptimizedCode( 3271 isolate(), instr->hydrogen()->language_mode(), 3272 instr->hydrogen()->initialization_state()).code(); 3273 CallCode(ic, RelocInfo::CODE_TARGET, instr); 3274 } 3275 3276 3277 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { 3278 Register result = ToRegister(instr->result()); 3279 3280 if (instr->hydrogen()->from_inlined()) { 3281 __ lea(result, Operand(esp, -2 * kPointerSize)); 3282 } else { 3283 // Check for arguments adapter frame. 3284 Label done, adapted; 3285 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3286 __ mov(result, Operand(result, StandardFrameConstants::kContextOffset)); 3287 __ cmp(Operand(result), 3288 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3289 __ j(equal, &adapted, Label::kNear); 3290 3291 // No arguments adaptor frame. 3292 __ mov(result, Operand(ebp)); 3293 __ jmp(&done, Label::kNear); 3294 3295 // Arguments adaptor frame present. 3296 __ bind(&adapted); 3297 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3298 3299 // Result is the frame pointer for the frame if not adapted and for the real 3300 // frame below the adaptor frame if adapted. 3301 __ bind(&done); 3302 } 3303 } 3304 3305 3306 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { 3307 Operand elem = ToOperand(instr->elements()); 3308 Register result = ToRegister(instr->result()); 3309 3310 Label done; 3311 3312 // If no arguments adaptor frame the number of arguments is fixed. 3313 __ cmp(ebp, elem); 3314 __ mov(result, Immediate(scope()->num_parameters())); 3315 __ j(equal, &done, Label::kNear); 3316 3317 // Arguments adaptor frame present. Get argument length from there. 3318 __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3319 __ mov(result, Operand(result, 3320 ArgumentsAdaptorFrameConstants::kLengthOffset)); 3321 __ SmiUntag(result); 3322 3323 // Argument length is in result register. 3324 __ bind(&done); 3325 } 3326 3327 3328 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { 3329 Register receiver = ToRegister(instr->receiver()); 3330 Register function = ToRegister(instr->function()); 3331 3332 // If the receiver is null or undefined, we have to pass the global 3333 // object as a receiver to normal functions. Values have to be 3334 // passed unchanged to builtins and strict-mode functions. 3335 Label receiver_ok, global_object; 3336 Register scratch = ToRegister(instr->temp()); 3337 3338 if (!instr->hydrogen()->known_function()) { 3339 // Do not transform the receiver to object for strict mode 3340 // functions. 3341 __ mov(scratch, 3342 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); 3343 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kStrictModeByteOffset), 3344 1 << SharedFunctionInfo::kStrictModeBitWithinByte); 3345 __ j(not_equal, &receiver_ok); 3346 3347 // Do not transform the receiver to object for builtins. 3348 __ test_b(FieldOperand(scratch, SharedFunctionInfo::kNativeByteOffset), 3349 1 << SharedFunctionInfo::kNativeBitWithinByte); 3350 __ j(not_equal, &receiver_ok); 3351 } 3352 3353 // Normal function. Replace undefined or null with global receiver. 3354 __ cmp(receiver, factory()->null_value()); 3355 __ j(equal, &global_object); 3356 __ cmp(receiver, factory()->undefined_value()); 3357 __ j(equal, &global_object); 3358 3359 // The receiver should be a JS object. 3360 __ test(receiver, Immediate(kSmiTagMask)); 3361 DeoptimizeIf(equal, instr, Deoptimizer::kSmi); 3362 __ CmpObjectType(receiver, FIRST_JS_RECEIVER_TYPE, scratch); 3363 DeoptimizeIf(below, instr, Deoptimizer::kNotAJavaScriptObject); 3364 3365 __ jmp(&receiver_ok, Label::kNear); 3366 __ bind(&global_object); 3367 __ mov(receiver, FieldOperand(function, JSFunction::kContextOffset)); 3368 __ mov(receiver, ContextOperand(receiver, Context::NATIVE_CONTEXT_INDEX)); 3369 __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_PROXY_INDEX)); 3370 __ bind(&receiver_ok); 3371 } 3372 3373 3374 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { 3375 Register receiver = ToRegister(instr->receiver()); 3376 Register function = ToRegister(instr->function()); 3377 Register length = ToRegister(instr->length()); 3378 Register elements = ToRegister(instr->elements()); 3379 DCHECK(receiver.is(eax)); // Used for parameter count. 3380 DCHECK(function.is(edi)); // Required by InvokeFunction. 3381 DCHECK(ToRegister(instr->result()).is(eax)); 3382 3383 // Copy the arguments to this function possibly from the 3384 // adaptor frame below it. 3385 const uint32_t kArgumentsLimit = 1 * KB; 3386 __ cmp(length, kArgumentsLimit); 3387 DeoptimizeIf(above, instr, Deoptimizer::kTooManyArguments); 3388 3389 __ push(receiver); 3390 __ mov(receiver, length); 3391 3392 // Loop through the arguments pushing them onto the execution 3393 // stack. 3394 Label invoke, loop; 3395 // length is a small non-negative integer, due to the test above. 3396 __ test(length, Operand(length)); 3397 __ j(zero, &invoke, Label::kNear); 3398 __ bind(&loop); 3399 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); 3400 __ dec(length); 3401 __ j(not_zero, &loop); 3402 3403 // Invoke the function. 3404 __ bind(&invoke); 3405 DCHECK(instr->HasPointerMap()); 3406 LPointerMap* pointers = instr->pointer_map(); 3407 SafepointGenerator safepoint_generator( 3408 this, pointers, Safepoint::kLazyDeopt); 3409 ParameterCount actual(eax); 3410 __ InvokeFunction(function, no_reg, actual, CALL_FUNCTION, 3411 safepoint_generator); 3412 } 3413 3414 3415 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { 3416 __ int3(); 3417 } 3418 3419 3420 void LCodeGen::DoPushArgument(LPushArgument* instr) { 3421 LOperand* argument = instr->value(); 3422 EmitPushTaggedOperand(argument); 3423 } 3424 3425 3426 void LCodeGen::DoDrop(LDrop* instr) { 3427 __ Drop(instr->count()); 3428 } 3429 3430 3431 void LCodeGen::DoThisFunction(LThisFunction* instr) { 3432 Register result = ToRegister(instr->result()); 3433 __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 3434 } 3435 3436 3437 void LCodeGen::DoContext(LContext* instr) { 3438 Register result = ToRegister(instr->result()); 3439 if (info()->IsOptimizing()) { 3440 __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset)); 3441 } else { 3442 // If there is no frame, the context must be in esi. 3443 DCHECK(result.is(esi)); 3444 } 3445 } 3446 3447 3448 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { 3449 DCHECK(ToRegister(instr->context()).is(esi)); 3450 __ push(Immediate(instr->hydrogen()->pairs())); 3451 __ push(Immediate(Smi::FromInt(instr->hydrogen()->flags()))); 3452 CallRuntime(Runtime::kDeclareGlobals, instr); 3453 } 3454 3455 3456 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 3457 int formal_parameter_count, int arity, 3458 LInstruction* instr) { 3459 bool dont_adapt_arguments = 3460 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; 3461 bool can_invoke_directly = 3462 dont_adapt_arguments || formal_parameter_count == arity; 3463 3464 Register function_reg = edi; 3465 3466 if (can_invoke_directly) { 3467 // Change context. 3468 __ mov(esi, FieldOperand(function_reg, JSFunction::kContextOffset)); 3469 3470 // Always initialize new target and number of actual arguments. 3471 __ mov(edx, factory()->undefined_value()); 3472 __ mov(eax, arity); 3473 3474 // Invoke function directly. 3475 if (function.is_identical_to(info()->closure())) { 3476 __ CallSelf(); 3477 } else { 3478 __ call(FieldOperand(function_reg, JSFunction::kCodeEntryOffset)); 3479 } 3480 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); 3481 } else { 3482 // We need to adapt arguments. 3483 LPointerMap* pointers = instr->pointer_map(); 3484 SafepointGenerator generator( 3485 this, pointers, Safepoint::kLazyDeopt); 3486 ParameterCount count(arity); 3487 ParameterCount expected(formal_parameter_count); 3488 __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator); 3489 } 3490 } 3491 3492 3493 void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) { 3494 DCHECK(ToRegister(instr->result()).is(eax)); 3495 3496 if (instr->hydrogen()->IsTailCall()) { 3497 if (NeedsEagerFrame()) __ leave(); 3498 3499 if (instr->target()->IsConstantOperand()) { 3500 LConstantOperand* target = LConstantOperand::cast(instr->target()); 3501 Handle<Code> code = Handle<Code>::cast(ToHandle(target)); 3502 __ jmp(code, RelocInfo::CODE_TARGET); 3503 } else { 3504 DCHECK(instr->target()->IsRegister()); 3505 Register target = ToRegister(instr->target()); 3506 __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag)); 3507 __ jmp(target); 3508 } 3509 } else { 3510 LPointerMap* pointers = instr->pointer_map(); 3511 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); 3512 3513 if (instr->target()->IsConstantOperand()) { 3514 LConstantOperand* target = LConstantOperand::cast(instr->target()); 3515 Handle<Code> code = Handle<Code>::cast(ToHandle(target)); 3516 generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET)); 3517 __ call(code, RelocInfo::CODE_TARGET); 3518 } else { 3519 DCHECK(instr->target()->IsRegister()); 3520 Register target = ToRegister(instr->target()); 3521 generator.BeforeCall(__ CallSize(Operand(target))); 3522 __ add(target, Immediate(Code::kHeaderSize - kHeapObjectTag)); 3523 __ call(target); 3524 } 3525 generator.AfterCall(); 3526 } 3527 } 3528 3529 3530 void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) { 3531 DCHECK(ToRegister(instr->function()).is(edi)); 3532 DCHECK(ToRegister(instr->result()).is(eax)); 3533 3534 // Change context. 3535 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 3536 3537 // Always initialize new target and number of actual arguments. 3538 __ mov(edx, factory()->undefined_value()); 3539 __ mov(eax, instr->arity()); 3540 3541 bool is_self_call = false; 3542 if (instr->hydrogen()->function()->IsConstant()) { 3543 HConstant* fun_const = HConstant::cast(instr->hydrogen()->function()); 3544 Handle<JSFunction> jsfun = 3545 Handle<JSFunction>::cast(fun_const->handle(isolate())); 3546 is_self_call = jsfun.is_identical_to(info()->closure()); 3547 } 3548 3549 if (is_self_call) { 3550 __ CallSelf(); 3551 } else { 3552 __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset)); 3553 } 3554 3555 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); 3556 } 3557 3558 3559 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { 3560 Register input_reg = ToRegister(instr->value()); 3561 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), 3562 factory()->heap_number_map()); 3563 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); 3564 3565 Label slow, allocated, done; 3566 Register tmp = input_reg.is(eax) ? ecx : eax; 3567 Register tmp2 = tmp.is(ecx) ? edx : input_reg.is(ecx) ? edx : ecx; 3568 3569 // Preserve the value of all registers. 3570 PushSafepointRegistersScope scope(this); 3571 3572 __ mov(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 3573 // Check the sign of the argument. If the argument is positive, just 3574 // return it. We do not need to patch the stack since |input| and 3575 // |result| are the same register and |input| will be restored 3576 // unchanged by popping safepoint registers. 3577 __ test(tmp, Immediate(HeapNumber::kSignMask)); 3578 __ j(zero, &done, Label::kNear); 3579 3580 __ AllocateHeapNumber(tmp, tmp2, no_reg, &slow); 3581 __ jmp(&allocated, Label::kNear); 3582 3583 // Slow case: Call the runtime system to do the number allocation. 3584 __ bind(&slow); 3585 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, 3586 instr, instr->context()); 3587 // Set the pointer to the new heap number in tmp. 3588 if (!tmp.is(eax)) __ mov(tmp, eax); 3589 // Restore input_reg after call to runtime. 3590 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); 3591 3592 __ bind(&allocated); 3593 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 3594 __ and_(tmp2, ~HeapNumber::kSignMask); 3595 __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2); 3596 __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); 3597 __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2); 3598 __ StoreToSafepointRegisterSlot(input_reg, tmp); 3599 3600 __ bind(&done); 3601 } 3602 3603 3604 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { 3605 Register input_reg = ToRegister(instr->value()); 3606 __ test(input_reg, Operand(input_reg)); 3607 Label is_positive; 3608 __ j(not_sign, &is_positive, Label::kNear); 3609 __ neg(input_reg); // Sets flags. 3610 DeoptimizeIf(negative, instr, Deoptimizer::kOverflow); 3611 __ bind(&is_positive); 3612 } 3613 3614 3615 void LCodeGen::DoMathAbs(LMathAbs* instr) { 3616 // Class for deferred case. 3617 class DeferredMathAbsTaggedHeapNumber final : public LDeferredCode { 3618 public: 3619 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, 3620 LMathAbs* instr, 3621 const X87Stack& x87_stack) 3622 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 3623 void Generate() override { 3624 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); 3625 } 3626 LInstruction* instr() override { return instr_; } 3627 3628 private: 3629 LMathAbs* instr_; 3630 }; 3631 3632 DCHECK(instr->value()->Equals(instr->result())); 3633 Representation r = instr->hydrogen()->value()->representation(); 3634 3635 if (r.IsDouble()) { 3636 X87Register value = ToX87Register(instr->value()); 3637 X87Fxch(value); 3638 __ fabs(); 3639 } else if (r.IsSmiOrInteger32()) { 3640 EmitIntegerMathAbs(instr); 3641 } else { // Tagged case. 3642 DeferredMathAbsTaggedHeapNumber* deferred = 3643 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr, x87_stack_); 3644 Register input_reg = ToRegister(instr->value()); 3645 // Smi check. 3646 __ JumpIfNotSmi(input_reg, deferred->entry()); 3647 EmitIntegerMathAbs(instr); 3648 __ bind(deferred->exit()); 3649 } 3650 } 3651 3652 3653 void LCodeGen::DoMathFloor(LMathFloor* instr) { 3654 Register output_reg = ToRegister(instr->result()); 3655 X87Register input_reg = ToX87Register(instr->value()); 3656 X87Fxch(input_reg); 3657 3658 Label not_minus_zero, done; 3659 // Deoptimize on unordered. 3660 __ fldz(); 3661 __ fld(1); 3662 __ FCmp(); 3663 DeoptimizeIf(parity_even, instr, Deoptimizer::kNaN); 3664 __ j(below, ¬_minus_zero, Label::kNear); 3665 3666 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3667 // Check for negative zero. 3668 __ j(not_equal, ¬_minus_zero, Label::kNear); 3669 // +- 0.0. 3670 __ fld(0); 3671 __ FXamSign(); 3672 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); 3673 __ Move(output_reg, Immediate(0)); 3674 __ jmp(&done, Label::kFar); 3675 } 3676 3677 // Positive input. 3678 // rc=01B, round down. 3679 __ bind(¬_minus_zero); 3680 __ fnclex(); 3681 __ X87SetRC(0x0400); 3682 __ sub(esp, Immediate(kPointerSize)); 3683 __ fist_s(Operand(esp, 0)); 3684 __ pop(output_reg); 3685 __ X87CheckIA(); 3686 DeoptimizeIf(equal, instr, Deoptimizer::kOverflow); 3687 __ fnclex(); 3688 __ X87SetRC(0x0000); 3689 __ bind(&done); 3690 } 3691 3692 3693 void LCodeGen::DoMathRound(LMathRound* instr) { 3694 X87Register input_reg = ToX87Register(instr->value()); 3695 Register result = ToRegister(instr->result()); 3696 X87Fxch(input_reg); 3697 Label below_one_half, below_minus_one_half, done; 3698 3699 ExternalReference one_half = ExternalReference::address_of_one_half(); 3700 ExternalReference minus_one_half = 3701 ExternalReference::address_of_minus_one_half(); 3702 3703 __ fld_d(Operand::StaticVariable(one_half)); 3704 __ fld(1); 3705 __ FCmp(); 3706 __ j(carry, &below_one_half); 3707 3708 // Use rounds towards zero, since 0.5 <= x, we use floor(0.5 + x) 3709 __ fld(0); 3710 __ fadd_d(Operand::StaticVariable(one_half)); 3711 // rc=11B, round toward zero. 3712 __ X87SetRC(0x0c00); 3713 __ sub(esp, Immediate(kPointerSize)); 3714 // Clear exception bits. 3715 __ fnclex(); 3716 __ fistp_s(MemOperand(esp, 0)); 3717 // Check overflow. 3718 __ X87CheckIA(); 3719 __ pop(result); 3720 DeoptimizeIf(equal, instr, Deoptimizer::kConversionOverflow); 3721 __ fnclex(); 3722 // Restore round mode. 3723 __ X87SetRC(0x0000); 3724 __ jmp(&done); 3725 3726 __ bind(&below_one_half); 3727 __ fld_d(Operand::StaticVariable(minus_one_half)); 3728 __ fld(1); 3729 __ FCmp(); 3730 __ j(carry, &below_minus_one_half); 3731 // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if 3732 // we can ignore the difference between a result of -0 and +0. 3733 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3734 // If the sign is positive, we return +0. 3735 __ fld(0); 3736 __ FXamSign(); 3737 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); 3738 } 3739 __ Move(result, Immediate(0)); 3740 __ jmp(&done); 3741 3742 __ bind(&below_minus_one_half); 3743 __ fld(0); 3744 __ fadd_d(Operand::StaticVariable(one_half)); 3745 // rc=01B, round down. 3746 __ X87SetRC(0x0400); 3747 __ sub(esp, Immediate(kPointerSize)); 3748 // Clear exception bits. 3749 __ fnclex(); 3750 __ fistp_s(MemOperand(esp, 0)); 3751 // Check overflow. 3752 __ X87CheckIA(); 3753 __ pop(result); 3754 DeoptimizeIf(equal, instr, Deoptimizer::kConversionOverflow); 3755 __ fnclex(); 3756 // Restore round mode. 3757 __ X87SetRC(0x0000); 3758 3759 __ bind(&done); 3760 } 3761 3762 3763 void LCodeGen::DoMathFround(LMathFround* instr) { 3764 X87Register input_reg = ToX87Register(instr->value()); 3765 X87Fxch(input_reg); 3766 __ sub(esp, Immediate(kPointerSize)); 3767 __ fstp_s(MemOperand(esp, 0)); 3768 X87Fld(MemOperand(esp, 0), kX87FloatOperand); 3769 __ add(esp, Immediate(kPointerSize)); 3770 } 3771 3772 3773 void LCodeGen::DoMathSqrt(LMathSqrt* instr) { 3774 X87Register input_reg = ToX87Register(instr->value()); 3775 __ X87SetFPUCW(0x027F); 3776 X87Fxch(input_reg); 3777 __ fsqrt(); 3778 __ X87SetFPUCW(0x037F); 3779 } 3780 3781 3782 void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) { 3783 X87Register input_reg = ToX87Register(instr->value()); 3784 DCHECK(ToX87Register(instr->result()).is(input_reg)); 3785 X87Fxch(input_reg); 3786 // Note that according to ECMA-262 15.8.2.13: 3787 // Math.pow(-Infinity, 0.5) == Infinity 3788 // Math.sqrt(-Infinity) == NaN 3789 Label done, sqrt; 3790 // Check base for -Infinity. C3 == 0, C2 == 1, C1 == 1 and C0 == 1 3791 __ fxam(); 3792 __ push(eax); 3793 __ fnstsw_ax(); 3794 __ and_(eax, Immediate(0x4700)); 3795 __ cmp(eax, Immediate(0x0700)); 3796 __ j(not_equal, &sqrt, Label::kNear); 3797 // If input is -Infinity, return Infinity. 3798 __ fchs(); 3799 __ jmp(&done, Label::kNear); 3800 3801 // Square root. 3802 __ bind(&sqrt); 3803 __ fldz(); 3804 __ faddp(); // Convert -0 to +0. 3805 __ fsqrt(); 3806 __ bind(&done); 3807 __ pop(eax); 3808 } 3809 3810 3811 void LCodeGen::DoPower(LPower* instr) { 3812 Representation exponent_type = instr->hydrogen()->right()->representation(); 3813 X87Register result = ToX87Register(instr->result()); 3814 // Having marked this as a call, we can use any registers. 3815 X87Register base = ToX87Register(instr->left()); 3816 ExternalReference one_half = ExternalReference::address_of_one_half(); 3817 3818 if (exponent_type.IsSmi()) { 3819 Register exponent = ToRegister(instr->right()); 3820 X87LoadForUsage(base); 3821 __ SmiUntag(exponent); 3822 __ push(exponent); 3823 __ fild_s(MemOperand(esp, 0)); 3824 __ pop(exponent); 3825 } else if (exponent_type.IsTagged()) { 3826 Register exponent = ToRegister(instr->right()); 3827 Register temp = exponent.is(ecx) ? eax : ecx; 3828 Label no_deopt, done; 3829 X87LoadForUsage(base); 3830 __ JumpIfSmi(exponent, &no_deopt); 3831 __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, temp); 3832 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); 3833 // Heap number(double) 3834 __ fld_d(FieldOperand(exponent, HeapNumber::kValueOffset)); 3835 __ jmp(&done); 3836 // SMI 3837 __ bind(&no_deopt); 3838 __ SmiUntag(exponent); 3839 __ push(exponent); 3840 __ fild_s(MemOperand(esp, 0)); 3841 __ pop(exponent); 3842 __ bind(&done); 3843 } else if (exponent_type.IsInteger32()) { 3844 Register exponent = ToRegister(instr->right()); 3845 X87LoadForUsage(base); 3846 __ push(exponent); 3847 __ fild_s(MemOperand(esp, 0)); 3848 __ pop(exponent); 3849 } else { 3850 DCHECK(exponent_type.IsDouble()); 3851 X87Register exponent_double = ToX87Register(instr->right()); 3852 X87LoadForUsage(base, exponent_double); 3853 } 3854 3855 // FP data stack {base, exponent(TOS)}. 3856 // Handle (exponent==+-0.5 && base == -0). 3857 Label not_plus_0; 3858 __ fld(0); 3859 __ fabs(); 3860 X87Fld(Operand::StaticVariable(one_half), kX87DoubleOperand); 3861 __ FCmp(); 3862 __ j(parity_even, ¬_plus_0, Label::kNear); // NaN. 3863 __ j(not_equal, ¬_plus_0, Label::kNear); 3864 __ fldz(); 3865 // FP data stack {base, exponent(TOS), zero}. 3866 __ faddp(2); 3867 __ bind(¬_plus_0); 3868 3869 { 3870 __ PrepareCallCFunction(4, eax); 3871 __ fstp_d(MemOperand(esp, kDoubleSize)); // Exponent value. 3872 __ fstp_d(MemOperand(esp, 0)); // Base value. 3873 X87PrepareToWrite(result); 3874 __ CallCFunction(ExternalReference::power_double_double_function(isolate()), 3875 4); 3876 // Return value is in st(0) on ia32. 3877 X87CommitWrite(result); 3878 } 3879 } 3880 3881 3882 void LCodeGen::DoMathLog(LMathLog* instr) { 3883 DCHECK(instr->value()->Equals(instr->result())); 3884 X87Register input_reg = ToX87Register(instr->value()); 3885 X87Fxch(input_reg); 3886 3887 Label positive, done, zero, nan_result; 3888 __ fldz(); 3889 __ fld(1); 3890 __ FCmp(); 3891 __ j(below, &nan_result, Label::kNear); 3892 __ j(equal, &zero, Label::kNear); 3893 // Positive input. 3894 // {input, ln2}. 3895 __ fldln2(); 3896 // {ln2, input}. 3897 __ fxch(); 3898 // {result}. 3899 __ fyl2x(); 3900 __ jmp(&done, Label::kNear); 3901 3902 __ bind(&nan_result); 3903 X87PrepareToWrite(input_reg); 3904 __ push(Immediate(0xffffffff)); 3905 __ push(Immediate(0x7fffffff)); 3906 __ fld_d(MemOperand(esp, 0)); 3907 __ lea(esp, Operand(esp, kDoubleSize)); 3908 X87CommitWrite(input_reg); 3909 __ jmp(&done, Label::kNear); 3910 3911 __ bind(&zero); 3912 ExternalReference ninf = ExternalReference::address_of_negative_infinity(); 3913 X87PrepareToWrite(input_reg); 3914 __ fld_d(Operand::StaticVariable(ninf)); 3915 X87CommitWrite(input_reg); 3916 3917 __ bind(&done); 3918 } 3919 3920 3921 void LCodeGen::DoMathClz32(LMathClz32* instr) { 3922 Register input = ToRegister(instr->value()); 3923 Register result = ToRegister(instr->result()); 3924 3925 __ Lzcnt(result, input); 3926 } 3927 3928 3929 void LCodeGen::DoMathExp(LMathExp* instr) { 3930 X87Register input = ToX87Register(instr->value()); 3931 X87Register result_reg = ToX87Register(instr->result()); 3932 Register temp_result = ToRegister(instr->temp1()); 3933 Register temp = ToRegister(instr->temp2()); 3934 Label slow, done, smi, finish; 3935 DCHECK(result_reg.is(input)); 3936 3937 // Store input into Heap number and call runtime function kMathExpRT. 3938 if (FLAG_inline_new) { 3939 __ AllocateHeapNumber(temp_result, temp, no_reg, &slow); 3940 __ jmp(&done, Label::kNear); 3941 } 3942 3943 // Slow case: Call the runtime system to do the number allocation. 3944 __ bind(&slow); 3945 { 3946 // TODO(3095996): Put a valid pointer value in the stack slot where the 3947 // result register is stored, as this register is in the pointer map, but 3948 // contains an integer value. 3949 __ Move(temp_result, Immediate(0)); 3950 3951 // Preserve the value of all registers. 3952 PushSafepointRegistersScope scope(this); 3953 3954 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 3955 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); 3956 RecordSafepointWithRegisters(instr->pointer_map(), 0, 3957 Safepoint::kNoLazyDeopt); 3958 __ StoreToSafepointRegisterSlot(temp_result, eax); 3959 } 3960 __ bind(&done); 3961 X87LoadForUsage(input); 3962 __ fstp_d(FieldOperand(temp_result, HeapNumber::kValueOffset)); 3963 3964 { 3965 // Preserve the value of all registers. 3966 PushSafepointRegistersScope scope(this); 3967 3968 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 3969 __ push(temp_result); 3970 __ CallRuntimeSaveDoubles(Runtime::kMathExpRT); 3971 RecordSafepointWithRegisters(instr->pointer_map(), 1, 3972 Safepoint::kNoLazyDeopt); 3973 __ StoreToSafepointRegisterSlot(temp_result, eax); 3974 } 3975 X87PrepareToWrite(result_reg); 3976 // return value of MathExpRT is Smi or Heap Number. 3977 __ JumpIfSmi(temp_result, &smi); 3978 // Heap number(double) 3979 __ fld_d(FieldOperand(temp_result, HeapNumber::kValueOffset)); 3980 __ jmp(&finish); 3981 // SMI 3982 __ bind(&smi); 3983 __ SmiUntag(temp_result); 3984 __ push(temp_result); 3985 __ fild_s(MemOperand(esp, 0)); 3986 __ pop(temp_result); 3987 __ bind(&finish); 3988 X87CommitWrite(result_reg); 3989 } 3990 3991 3992 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { 3993 DCHECK(ToRegister(instr->context()).is(esi)); 3994 DCHECK(ToRegister(instr->function()).is(edi)); 3995 DCHECK(instr->HasPointerMap()); 3996 3997 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); 3998 if (known_function.is_null()) { 3999 LPointerMap* pointers = instr->pointer_map(); 4000 SafepointGenerator generator( 4001 this, pointers, Safepoint::kLazyDeopt); 4002 ParameterCount count(instr->arity()); 4003 __ InvokeFunction(edi, no_reg, count, CALL_FUNCTION, generator); 4004 } else { 4005 CallKnownFunction(known_function, 4006 instr->hydrogen()->formal_parameter_count(), 4007 instr->arity(), instr); 4008 } 4009 } 4010 4011 4012 void LCodeGen::DoCallFunction(LCallFunction* instr) { 4013 DCHECK(ToRegister(instr->context()).is(esi)); 4014 DCHECK(ToRegister(instr->function()).is(edi)); 4015 DCHECK(ToRegister(instr->result()).is(eax)); 4016 4017 int arity = instr->arity(); 4018 ConvertReceiverMode mode = instr->hydrogen()->convert_mode(); 4019 if (instr->hydrogen()->HasVectorAndSlot()) { 4020 Register slot_register = ToRegister(instr->temp_slot()); 4021 Register vector_register = ToRegister(instr->temp_vector()); 4022 DCHECK(slot_register.is(edx)); 4023 DCHECK(vector_register.is(ebx)); 4024 4025 AllowDeferredHandleDereference vector_structure_check; 4026 Handle<TypeFeedbackVector> vector = instr->hydrogen()->feedback_vector(); 4027 int index = vector->GetIndex(instr->hydrogen()->slot()); 4028 4029 __ mov(vector_register, vector); 4030 __ mov(slot_register, Immediate(Smi::FromInt(index))); 4031 4032 Handle<Code> ic = 4033 CodeFactory::CallICInOptimizedCode(isolate(), arity, mode).code(); 4034 CallCode(ic, RelocInfo::CODE_TARGET, instr); 4035 } else { 4036 __ Set(eax, arity); 4037 CallCode(isolate()->builtins()->Call(mode), RelocInfo::CODE_TARGET, instr); 4038 } 4039 } 4040 4041 4042 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { 4043 DCHECK(ToRegister(instr->context()).is(esi)); 4044 DCHECK(ToRegister(instr->constructor()).is(edi)); 4045 DCHECK(ToRegister(instr->result()).is(eax)); 4046 4047 __ Move(eax, Immediate(instr->arity())); 4048 if (instr->arity() == 1) { 4049 // We only need the allocation site for the case we have a length argument. 4050 // The case may bail out to the runtime, which will determine the correct 4051 // elements kind with the site. 4052 __ mov(ebx, instr->hydrogen()->site()); 4053 } else { 4054 __ mov(ebx, isolate()->factory()->undefined_value()); 4055 } 4056 4057 ElementsKind kind = instr->hydrogen()->elements_kind(); 4058 AllocationSiteOverrideMode override_mode = 4059 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) 4060 ? DISABLE_ALLOCATION_SITES 4061 : DONT_OVERRIDE; 4062 4063 if (instr->arity() == 0) { 4064 ArrayNoArgumentConstructorStub stub(isolate(), kind, override_mode); 4065 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4066 } else if (instr->arity() == 1) { 4067 Label done; 4068 if (IsFastPackedElementsKind(kind)) { 4069 Label packed_case; 4070 // We might need a change here 4071 // look at the first argument 4072 __ mov(ecx, Operand(esp, 0)); 4073 __ test(ecx, ecx); 4074 __ j(zero, &packed_case, Label::kNear); 4075 4076 ElementsKind holey_kind = GetHoleyElementsKind(kind); 4077 ArraySingleArgumentConstructorStub stub(isolate(), 4078 holey_kind, 4079 override_mode); 4080 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4081 __ jmp(&done, Label::kNear); 4082 __ bind(&packed_case); 4083 } 4084 4085 ArraySingleArgumentConstructorStub stub(isolate(), kind, override_mode); 4086 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4087 __ bind(&done); 4088 } else { 4089 ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode); 4090 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4091 } 4092 } 4093 4094 4095 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { 4096 DCHECK(ToRegister(instr->context()).is(esi)); 4097 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles()); 4098 } 4099 4100 4101 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) { 4102 Register function = ToRegister(instr->function()); 4103 Register code_object = ToRegister(instr->code_object()); 4104 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize)); 4105 __ mov(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object); 4106 } 4107 4108 4109 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) { 4110 Register result = ToRegister(instr->result()); 4111 Register base = ToRegister(instr->base_object()); 4112 if (instr->offset()->IsConstantOperand()) { 4113 LConstantOperand* offset = LConstantOperand::cast(instr->offset()); 4114 __ lea(result, Operand(base, ToInteger32(offset))); 4115 } else { 4116 Register offset = ToRegister(instr->offset()); 4117 __ lea(result, Operand(base, offset, times_1, 0)); 4118 } 4119 } 4120 4121 4122 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { 4123 Representation representation = instr->hydrogen()->field_representation(); 4124 4125 HObjectAccess access = instr->hydrogen()->access(); 4126 int offset = access.offset(); 4127 4128 if (access.IsExternalMemory()) { 4129 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); 4130 MemOperand operand = instr->object()->IsConstantOperand() 4131 ? MemOperand::StaticVariable( 4132 ToExternalReference(LConstantOperand::cast(instr->object()))) 4133 : MemOperand(ToRegister(instr->object()), offset); 4134 if (instr->value()->IsConstantOperand()) { 4135 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); 4136 __ mov(operand, Immediate(ToInteger32(operand_value))); 4137 } else { 4138 Register value = ToRegister(instr->value()); 4139 __ Store(value, operand, representation); 4140 } 4141 return; 4142 } 4143 4144 Register object = ToRegister(instr->object()); 4145 __ AssertNotSmi(object); 4146 DCHECK(!representation.IsSmi() || 4147 !instr->value()->IsConstantOperand() || 4148 IsSmi(LConstantOperand::cast(instr->value()))); 4149 if (representation.IsDouble()) { 4150 DCHECK(access.IsInobject()); 4151 DCHECK(!instr->hydrogen()->has_transition()); 4152 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); 4153 X87Register value = ToX87Register(instr->value()); 4154 X87Mov(FieldOperand(object, offset), value); 4155 return; 4156 } 4157 4158 if (instr->hydrogen()->has_transition()) { 4159 Handle<Map> transition = instr->hydrogen()->transition_map(); 4160 AddDeprecationDependency(transition); 4161 __ mov(FieldOperand(object, HeapObject::kMapOffset), transition); 4162 if (instr->hydrogen()->NeedsWriteBarrierForMap()) { 4163 Register temp = ToRegister(instr->temp()); 4164 Register temp_map = ToRegister(instr->temp_map()); 4165 __ mov(temp_map, transition); 4166 __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map); 4167 // Update the write barrier for the map field. 4168 __ RecordWriteForMap(object, transition, temp_map, temp, kSaveFPRegs); 4169 } 4170 } 4171 4172 // Do the store. 4173 Register write_register = object; 4174 if (!access.IsInobject()) { 4175 write_register = ToRegister(instr->temp()); 4176 __ mov(write_register, FieldOperand(object, JSObject::kPropertiesOffset)); 4177 } 4178 4179 MemOperand operand = FieldOperand(write_register, offset); 4180 if (instr->value()->IsConstantOperand()) { 4181 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); 4182 if (operand_value->IsRegister()) { 4183 Register value = ToRegister(operand_value); 4184 __ Store(value, operand, representation); 4185 } else if (representation.IsInteger32() || representation.IsExternal()) { 4186 Immediate immediate = ToImmediate(operand_value, representation); 4187 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); 4188 __ mov(operand, immediate); 4189 } else { 4190 Handle<Object> handle_value = ToHandle(operand_value); 4191 DCHECK(!instr->hydrogen()->NeedsWriteBarrier()); 4192 __ mov(operand, handle_value); 4193 } 4194 } else { 4195 Register value = ToRegister(instr->value()); 4196 __ Store(value, operand, representation); 4197 } 4198 4199 if (instr->hydrogen()->NeedsWriteBarrier()) { 4200 Register value = ToRegister(instr->value()); 4201 Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object; 4202 // Update the write barrier for the object for in-object properties. 4203 __ RecordWriteField(write_register, offset, value, temp, kSaveFPRegs, 4204 EMIT_REMEMBERED_SET, 4205 instr->hydrogen()->SmiCheckForWriteBarrier(), 4206 instr->hydrogen()->PointersToHereCheckForValue()); 4207 } 4208 } 4209 4210 4211 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { 4212 DCHECK(ToRegister(instr->context()).is(esi)); 4213 DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister())); 4214 DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister())); 4215 4216 if (instr->hydrogen()->HasVectorAndSlot()) { 4217 EmitVectorStoreICRegisters<LStoreNamedGeneric>(instr); 4218 } 4219 4220 __ mov(StoreDescriptor::NameRegister(), instr->name()); 4221 Handle<Code> ic = CodeFactory::StoreICInOptimizedCode( 4222 isolate(), instr->language_mode(), 4223 instr->hydrogen()->initialization_state()).code(); 4224 CallCode(ic, RelocInfo::CODE_TARGET, instr); 4225 } 4226 4227 4228 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { 4229 Condition cc = instr->hydrogen()->allow_equality() ? above : above_equal; 4230 if (instr->index()->IsConstantOperand()) { 4231 __ cmp(ToOperand(instr->length()), 4232 ToImmediate(LConstantOperand::cast(instr->index()), 4233 instr->hydrogen()->length()->representation())); 4234 cc = CommuteCondition(cc); 4235 } else if (instr->length()->IsConstantOperand()) { 4236 __ cmp(ToOperand(instr->index()), 4237 ToImmediate(LConstantOperand::cast(instr->length()), 4238 instr->hydrogen()->index()->representation())); 4239 } else { 4240 __ cmp(ToRegister(instr->index()), ToOperand(instr->length())); 4241 } 4242 if (FLAG_debug_code && instr->hydrogen()->skip_check()) { 4243 Label done; 4244 __ j(NegateCondition(cc), &done, Label::kNear); 4245 __ int3(); 4246 __ bind(&done); 4247 } else { 4248 DeoptimizeIf(cc, instr, Deoptimizer::kOutOfBounds); 4249 } 4250 } 4251 4252 4253 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { 4254 ElementsKind elements_kind = instr->elements_kind(); 4255 LOperand* key = instr->key(); 4256 if (!key->IsConstantOperand() && 4257 ExternalArrayOpRequiresTemp(instr->hydrogen()->key()->representation(), 4258 elements_kind)) { 4259 __ SmiUntag(ToRegister(key)); 4260 } 4261 Operand operand(BuildFastArrayOperand( 4262 instr->elements(), 4263 key, 4264 instr->hydrogen()->key()->representation(), 4265 elements_kind, 4266 instr->base_offset())); 4267 if (elements_kind == FLOAT32_ELEMENTS) { 4268 X87Mov(operand, ToX87Register(instr->value()), kX87FloatOperand); 4269 } else if (elements_kind == FLOAT64_ELEMENTS) { 4270 uint64_t int_val = kHoleNanInt64; 4271 int32_t lower = static_cast<int32_t>(int_val); 4272 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); 4273 Operand operand2 = BuildFastArrayOperand( 4274 instr->elements(), instr->key(), 4275 instr->hydrogen()->key()->representation(), elements_kind, 4276 instr->base_offset() + kPointerSize); 4277 4278 Label no_special_nan_handling, done; 4279 X87Register value = ToX87Register(instr->value()); 4280 X87Fxch(value); 4281 __ lea(esp, Operand(esp, -kDoubleSize)); 4282 __ fst_d(MemOperand(esp, 0)); 4283 __ lea(esp, Operand(esp, kDoubleSize)); 4284 int offset = sizeof(kHoleNanUpper32); 4285 // x87 converts sNaN(0xfff7fffffff7ffff) to QNaN(0xfffffffffff7ffff), 4286 // so we check the upper with 0xffffffff for hole as a temporary fix. 4287 __ cmp(MemOperand(esp, -offset), Immediate(0xffffffff)); 4288 __ j(not_equal, &no_special_nan_handling, Label::kNear); 4289 __ mov(operand, Immediate(lower)); 4290 __ mov(operand2, Immediate(upper)); 4291 __ jmp(&done, Label::kNear); 4292 4293 __ bind(&no_special_nan_handling); 4294 __ fst_d(operand); 4295 __ bind(&done); 4296 } else { 4297 Register value = ToRegister(instr->value()); 4298 switch (elements_kind) { 4299 case UINT8_ELEMENTS: 4300 case INT8_ELEMENTS: 4301 case UINT8_CLAMPED_ELEMENTS: 4302 __ mov_b(operand, value); 4303 break; 4304 case UINT16_ELEMENTS: 4305 case INT16_ELEMENTS: 4306 __ mov_w(operand, value); 4307 break; 4308 case UINT32_ELEMENTS: 4309 case INT32_ELEMENTS: 4310 __ mov(operand, value); 4311 break; 4312 case FLOAT32_ELEMENTS: 4313 case FLOAT64_ELEMENTS: 4314 case FAST_SMI_ELEMENTS: 4315 case FAST_ELEMENTS: 4316 case FAST_DOUBLE_ELEMENTS: 4317 case FAST_HOLEY_SMI_ELEMENTS: 4318 case FAST_HOLEY_ELEMENTS: 4319 case FAST_HOLEY_DOUBLE_ELEMENTS: 4320 case DICTIONARY_ELEMENTS: 4321 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 4322 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 4323 UNREACHABLE(); 4324 break; 4325 } 4326 } 4327 } 4328 4329 4330 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { 4331 Operand double_store_operand = BuildFastArrayOperand( 4332 instr->elements(), 4333 instr->key(), 4334 instr->hydrogen()->key()->representation(), 4335 FAST_DOUBLE_ELEMENTS, 4336 instr->base_offset()); 4337 4338 uint64_t int_val = kHoleNanInt64; 4339 int32_t lower = static_cast<int32_t>(int_val); 4340 int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt)); 4341 Operand double_store_operand2 = BuildFastArrayOperand( 4342 instr->elements(), instr->key(), 4343 instr->hydrogen()->key()->representation(), FAST_DOUBLE_ELEMENTS, 4344 instr->base_offset() + kPointerSize); 4345 4346 if (instr->hydrogen()->IsConstantHoleStore()) { 4347 // This means we should store the (double) hole. No floating point 4348 // registers required. 4349 __ mov(double_store_operand, Immediate(lower)); 4350 __ mov(double_store_operand2, Immediate(upper)); 4351 } else { 4352 Label no_special_nan_handling, done; 4353 X87Register value = ToX87Register(instr->value()); 4354 X87Fxch(value); 4355 4356 if (instr->NeedsCanonicalization()) { 4357 __ fld(0); 4358 __ fld(0); 4359 __ FCmp(); 4360 __ j(parity_odd, &no_special_nan_handling, Label::kNear); 4361 // All NaNs are Canonicalized to 0x7fffffffffffffff 4362 __ mov(double_store_operand, Immediate(0xffffffff)); 4363 __ mov(double_store_operand2, Immediate(0x7fffffff)); 4364 __ jmp(&done, Label::kNear); 4365 } else { 4366 __ lea(esp, Operand(esp, -kDoubleSize)); 4367 __ fst_d(MemOperand(esp, 0)); 4368 __ lea(esp, Operand(esp, kDoubleSize)); 4369 int offset = sizeof(kHoleNanUpper32); 4370 // x87 converts sNaN(0xfff7fffffff7ffff) to QNaN(0xfffffffffff7ffff), 4371 // so we check the upper with 0xffffffff for hole as a temporary fix. 4372 __ cmp(MemOperand(esp, -offset), Immediate(0xffffffff)); 4373 __ j(not_equal, &no_special_nan_handling, Label::kNear); 4374 __ mov(double_store_operand, Immediate(lower)); 4375 __ mov(double_store_operand2, Immediate(upper)); 4376 __ jmp(&done, Label::kNear); 4377 } 4378 __ bind(&no_special_nan_handling); 4379 __ fst_d(double_store_operand); 4380 __ bind(&done); 4381 } 4382 } 4383 4384 4385 void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { 4386 Register elements = ToRegister(instr->elements()); 4387 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; 4388 4389 Operand operand = BuildFastArrayOperand( 4390 instr->elements(), 4391 instr->key(), 4392 instr->hydrogen()->key()->representation(), 4393 FAST_ELEMENTS, 4394 instr->base_offset()); 4395 if (instr->value()->IsRegister()) { 4396 __ mov(operand, ToRegister(instr->value())); 4397 } else { 4398 LConstantOperand* operand_value = LConstantOperand::cast(instr->value()); 4399 if (IsSmi(operand_value)) { 4400 Immediate immediate = ToImmediate(operand_value, Representation::Smi()); 4401 __ mov(operand, immediate); 4402 } else { 4403 DCHECK(!IsInteger32(operand_value)); 4404 Handle<Object> handle_value = ToHandle(operand_value); 4405 __ mov(operand, handle_value); 4406 } 4407 } 4408 4409 if (instr->hydrogen()->NeedsWriteBarrier()) { 4410 DCHECK(instr->value()->IsRegister()); 4411 Register value = ToRegister(instr->value()); 4412 DCHECK(!instr->key()->IsConstantOperand()); 4413 SmiCheck check_needed = 4414 instr->hydrogen()->value()->type().IsHeapObject() 4415 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 4416 // Compute address of modified element and store it into key register. 4417 __ lea(key, operand); 4418 __ RecordWrite(elements, key, value, kSaveFPRegs, EMIT_REMEMBERED_SET, 4419 check_needed, 4420 instr->hydrogen()->PointersToHereCheckForValue()); 4421 } 4422 } 4423 4424 4425 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { 4426 // By cases...external, fast-double, fast 4427 if (instr->is_fixed_typed_array()) { 4428 DoStoreKeyedExternalArray(instr); 4429 } else if (instr->hydrogen()->value()->representation().IsDouble()) { 4430 DoStoreKeyedFixedDoubleArray(instr); 4431 } else { 4432 DoStoreKeyedFixedArray(instr); 4433 } 4434 } 4435 4436 4437 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { 4438 DCHECK(ToRegister(instr->context()).is(esi)); 4439 DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister())); 4440 DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister())); 4441 DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister())); 4442 4443 if (instr->hydrogen()->HasVectorAndSlot()) { 4444 EmitVectorStoreICRegisters<LStoreKeyedGeneric>(instr); 4445 } 4446 4447 Handle<Code> ic = CodeFactory::KeyedStoreICInOptimizedCode( 4448 isolate(), instr->language_mode(), 4449 instr->hydrogen()->initialization_state()).code(); 4450 CallCode(ic, RelocInfo::CODE_TARGET, instr); 4451 } 4452 4453 4454 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { 4455 Register object = ToRegister(instr->object()); 4456 Register temp = ToRegister(instr->temp()); 4457 Label no_memento_found; 4458 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); 4459 DeoptimizeIf(equal, instr, Deoptimizer::kMementoFound); 4460 __ bind(&no_memento_found); 4461 } 4462 4463 4464 void LCodeGen::DoMaybeGrowElements(LMaybeGrowElements* instr) { 4465 class DeferredMaybeGrowElements final : public LDeferredCode { 4466 public: 4467 DeferredMaybeGrowElements(LCodeGen* codegen, 4468 LMaybeGrowElements* instr, 4469 const X87Stack& x87_stack) 4470 : LDeferredCode(codegen, x87_stack), instr_(instr) {} 4471 void Generate() override { codegen()->DoDeferredMaybeGrowElements(instr_); } 4472 LInstruction* instr() override { return instr_; } 4473 4474 private: 4475 LMaybeGrowElements* instr_; 4476 }; 4477 4478 Register result = eax; 4479 DeferredMaybeGrowElements* deferred = 4480 new (zone()) DeferredMaybeGrowElements(this, instr, x87_stack_); 4481 LOperand* key = instr->key(); 4482 LOperand* current_capacity = instr->current_capacity(); 4483 4484 DCHECK(instr->hydrogen()->key()->representation().IsInteger32()); 4485 DCHECK(instr->hydrogen()->current_capacity()->representation().IsInteger32()); 4486 DCHECK(key->IsConstantOperand() || key->IsRegister()); 4487 DCHECK(current_capacity->IsConstantOperand() || 4488 current_capacity->IsRegister()); 4489 4490 if (key->IsConstantOperand() && current_capacity->IsConstantOperand()) { 4491 int32_t constant_key = ToInteger32(LConstantOperand::cast(key)); 4492 int32_t constant_capacity = 4493 ToInteger32(LConstantOperand::cast(current_capacity)); 4494 if (constant_key >= constant_capacity) { 4495 // Deferred case. 4496 __ jmp(deferred->entry()); 4497 } 4498 } else if (key->IsConstantOperand()) { 4499 int32_t constant_key = ToInteger32(LConstantOperand::cast(key)); 4500 __ cmp(ToOperand(current_capacity), Immediate(constant_key)); 4501 __ j(less_equal, deferred->entry()); 4502 } else if (current_capacity->IsConstantOperand()) { 4503 int32_t constant_capacity = 4504 ToInteger32(LConstantOperand::cast(current_capacity)); 4505 __ cmp(ToRegister(key), Immediate(constant_capacity)); 4506 __ j(greater_equal, deferred->entry()); 4507 } else { 4508 __ cmp(ToRegister(key), ToRegister(current_capacity)); 4509 __ j(greater_equal, deferred->entry()); 4510 } 4511 4512 __ mov(result, ToOperand(instr->elements())); 4513 __ bind(deferred->exit()); 4514 } 4515 4516 4517 void LCodeGen::DoDeferredMaybeGrowElements(LMaybeGrowElements* instr) { 4518 // TODO(3095996): Get rid of this. For now, we need to make the 4519 // result register contain a valid pointer because it is already 4520 // contained in the register pointer map. 4521 Register result = eax; 4522 __ Move(result, Immediate(0)); 4523 4524 // We have to call a stub. 4525 { 4526 PushSafepointRegistersScope scope(this); 4527 if (instr->object()->IsRegister()) { 4528 __ Move(result, ToRegister(instr->object())); 4529 } else { 4530 __ mov(result, ToOperand(instr->object())); 4531 } 4532 4533 LOperand* key = instr->key(); 4534 if (key->IsConstantOperand()) { 4535 __ mov(ebx, ToImmediate(key, Representation::Smi())); 4536 } else { 4537 __ Move(ebx, ToRegister(key)); 4538 __ SmiTag(ebx); 4539 } 4540 4541 GrowArrayElementsStub stub(isolate(), instr->hydrogen()->is_js_array(), 4542 instr->hydrogen()->kind()); 4543 __ CallStub(&stub); 4544 RecordSafepointWithLazyDeopt( 4545 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 4546 __ StoreToSafepointRegisterSlot(result, result); 4547 } 4548 4549 // Deopt on smi, which means the elements array changed to dictionary mode. 4550 __ test(result, Immediate(kSmiTagMask)); 4551 DeoptimizeIf(equal, instr, Deoptimizer::kSmi); 4552 } 4553 4554 4555 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { 4556 Register object_reg = ToRegister(instr->object()); 4557 4558 Handle<Map> from_map = instr->original_map(); 4559 Handle<Map> to_map = instr->transitioned_map(); 4560 ElementsKind from_kind = instr->from_kind(); 4561 ElementsKind to_kind = instr->to_kind(); 4562 4563 Label not_applicable; 4564 bool is_simple_map_transition = 4565 IsSimpleMapChangeTransition(from_kind, to_kind); 4566 Label::Distance branch_distance = 4567 is_simple_map_transition ? Label::kNear : Label::kFar; 4568 __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); 4569 __ j(not_equal, ¬_applicable, branch_distance); 4570 if (is_simple_map_transition) { 4571 Register new_map_reg = ToRegister(instr->new_map_temp()); 4572 __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), 4573 Immediate(to_map)); 4574 // Write barrier. 4575 DCHECK_NOT_NULL(instr->temp()); 4576 __ RecordWriteForMap(object_reg, to_map, new_map_reg, 4577 ToRegister(instr->temp()), kDontSaveFPRegs); 4578 } else { 4579 DCHECK(ToRegister(instr->context()).is(esi)); 4580 DCHECK(object_reg.is(eax)); 4581 PushSafepointRegistersScope scope(this); 4582 __ mov(ebx, to_map); 4583 bool is_js_array = from_map->instance_type() == JS_ARRAY_TYPE; 4584 TransitionElementsKindStub stub(isolate(), from_kind, to_kind, is_js_array); 4585 __ CallStub(&stub); 4586 RecordSafepointWithLazyDeopt(instr, 4587 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 4588 } 4589 __ bind(¬_applicable); 4590 } 4591 4592 4593 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { 4594 class DeferredStringCharCodeAt final : public LDeferredCode { 4595 public: 4596 DeferredStringCharCodeAt(LCodeGen* codegen, 4597 LStringCharCodeAt* instr, 4598 const X87Stack& x87_stack) 4599 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 4600 void Generate() override { codegen()->DoDeferredStringCharCodeAt(instr_); } 4601 LInstruction* instr() override { return instr_; } 4602 4603 private: 4604 LStringCharCodeAt* instr_; 4605 }; 4606 4607 DeferredStringCharCodeAt* deferred = 4608 new(zone()) DeferredStringCharCodeAt(this, instr, x87_stack_); 4609 4610 StringCharLoadGenerator::Generate(masm(), 4611 factory(), 4612 ToRegister(instr->string()), 4613 ToRegister(instr->index()), 4614 ToRegister(instr->result()), 4615 deferred->entry()); 4616 __ bind(deferred->exit()); 4617 } 4618 4619 4620 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { 4621 Register string = ToRegister(instr->string()); 4622 Register result = ToRegister(instr->result()); 4623 4624 // TODO(3095996): Get rid of this. For now, we need to make the 4625 // result register contain a valid pointer because it is already 4626 // contained in the register pointer map. 4627 __ Move(result, Immediate(0)); 4628 4629 PushSafepointRegistersScope scope(this); 4630 __ push(string); 4631 // Push the index as a smi. This is safe because of the checks in 4632 // DoStringCharCodeAt above. 4633 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); 4634 if (instr->index()->IsConstantOperand()) { 4635 Immediate immediate = ToImmediate(LConstantOperand::cast(instr->index()), 4636 Representation::Smi()); 4637 __ push(immediate); 4638 } else { 4639 Register index = ToRegister(instr->index()); 4640 __ SmiTag(index); 4641 __ push(index); 4642 } 4643 CallRuntimeFromDeferred(Runtime::kStringCharCodeAtRT, 2, 4644 instr, instr->context()); 4645 __ AssertSmi(eax); 4646 __ SmiUntag(eax); 4647 __ StoreToSafepointRegisterSlot(result, eax); 4648 } 4649 4650 4651 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { 4652 class DeferredStringCharFromCode final : public LDeferredCode { 4653 public: 4654 DeferredStringCharFromCode(LCodeGen* codegen, 4655 LStringCharFromCode* instr, 4656 const X87Stack& x87_stack) 4657 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 4658 void Generate() override { 4659 codegen()->DoDeferredStringCharFromCode(instr_); 4660 } 4661 LInstruction* instr() override { return instr_; } 4662 4663 private: 4664 LStringCharFromCode* instr_; 4665 }; 4666 4667 DeferredStringCharFromCode* deferred = 4668 new(zone()) DeferredStringCharFromCode(this, instr, x87_stack_); 4669 4670 DCHECK(instr->hydrogen()->value()->representation().IsInteger32()); 4671 Register char_code = ToRegister(instr->char_code()); 4672 Register result = ToRegister(instr->result()); 4673 DCHECK(!char_code.is(result)); 4674 4675 __ cmp(char_code, String::kMaxOneByteCharCode); 4676 __ j(above, deferred->entry()); 4677 __ Move(result, Immediate(factory()->single_character_string_cache())); 4678 __ mov(result, FieldOperand(result, 4679 char_code, times_pointer_size, 4680 FixedArray::kHeaderSize)); 4681 __ cmp(result, factory()->undefined_value()); 4682 __ j(equal, deferred->entry()); 4683 __ bind(deferred->exit()); 4684 } 4685 4686 4687 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { 4688 Register char_code = ToRegister(instr->char_code()); 4689 Register result = ToRegister(instr->result()); 4690 4691 // TODO(3095996): Get rid of this. For now, we need to make the 4692 // result register contain a valid pointer because it is already 4693 // contained in the register pointer map. 4694 __ Move(result, Immediate(0)); 4695 4696 PushSafepointRegistersScope scope(this); 4697 __ SmiTag(char_code); 4698 __ push(char_code); 4699 CallRuntimeFromDeferred(Runtime::kStringCharFromCode, 1, instr, 4700 instr->context()); 4701 __ StoreToSafepointRegisterSlot(result, eax); 4702 } 4703 4704 4705 void LCodeGen::DoStringAdd(LStringAdd* instr) { 4706 DCHECK(ToRegister(instr->context()).is(esi)); 4707 DCHECK(ToRegister(instr->left()).is(edx)); 4708 DCHECK(ToRegister(instr->right()).is(eax)); 4709 StringAddStub stub(isolate(), 4710 instr->hydrogen()->flags(), 4711 instr->hydrogen()->pretenure_flag()); 4712 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4713 } 4714 4715 4716 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { 4717 LOperand* input = instr->value(); 4718 LOperand* output = instr->result(); 4719 DCHECK(input->IsRegister() || input->IsStackSlot()); 4720 DCHECK(output->IsDoubleRegister()); 4721 if (input->IsRegister()) { 4722 Register input_reg = ToRegister(input); 4723 __ push(input_reg); 4724 X87Mov(ToX87Register(output), Operand(esp, 0), kX87IntOperand); 4725 __ pop(input_reg); 4726 } else { 4727 X87Mov(ToX87Register(output), ToOperand(input), kX87IntOperand); 4728 } 4729 } 4730 4731 4732 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { 4733 LOperand* input = instr->value(); 4734 LOperand* output = instr->result(); 4735 X87Register res = ToX87Register(output); 4736 X87PrepareToWrite(res); 4737 __ LoadUint32NoSSE2(ToRegister(input)); 4738 X87CommitWrite(res); 4739 } 4740 4741 4742 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { 4743 class DeferredNumberTagI final : public LDeferredCode { 4744 public: 4745 DeferredNumberTagI(LCodeGen* codegen, 4746 LNumberTagI* instr, 4747 const X87Stack& x87_stack) 4748 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 4749 void Generate() override { 4750 codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp(), 4751 SIGNED_INT32); 4752 } 4753 LInstruction* instr() override { return instr_; } 4754 4755 private: 4756 LNumberTagI* instr_; 4757 }; 4758 4759 LOperand* input = instr->value(); 4760 DCHECK(input->IsRegister() && input->Equals(instr->result())); 4761 Register reg = ToRegister(input); 4762 4763 DeferredNumberTagI* deferred = 4764 new(zone()) DeferredNumberTagI(this, instr, x87_stack_); 4765 __ SmiTag(reg); 4766 __ j(overflow, deferred->entry()); 4767 __ bind(deferred->exit()); 4768 } 4769 4770 4771 void LCodeGen::DoNumberTagU(LNumberTagU* instr) { 4772 class DeferredNumberTagU final : public LDeferredCode { 4773 public: 4774 DeferredNumberTagU(LCodeGen* codegen, 4775 LNumberTagU* instr, 4776 const X87Stack& x87_stack) 4777 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 4778 void Generate() override { 4779 codegen()->DoDeferredNumberTagIU(instr_, instr_->value(), instr_->temp(), 4780 UNSIGNED_INT32); 4781 } 4782 LInstruction* instr() override { return instr_; } 4783 4784 private: 4785 LNumberTagU* instr_; 4786 }; 4787 4788 LOperand* input = instr->value(); 4789 DCHECK(input->IsRegister() && input->Equals(instr->result())); 4790 Register reg = ToRegister(input); 4791 4792 DeferredNumberTagU* deferred = 4793 new(zone()) DeferredNumberTagU(this, instr, x87_stack_); 4794 __ cmp(reg, Immediate(Smi::kMaxValue)); 4795 __ j(above, deferred->entry()); 4796 __ SmiTag(reg); 4797 __ bind(deferred->exit()); 4798 } 4799 4800 4801 void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr, 4802 LOperand* value, 4803 LOperand* temp, 4804 IntegerSignedness signedness) { 4805 Label done, slow; 4806 Register reg = ToRegister(value); 4807 Register tmp = ToRegister(temp); 4808 4809 if (signedness == SIGNED_INT32) { 4810 // There was overflow, so bits 30 and 31 of the original integer 4811 // disagree. Try to allocate a heap number in new space and store 4812 // the value in there. If that fails, call the runtime system. 4813 __ SmiUntag(reg); 4814 __ xor_(reg, 0x80000000); 4815 __ push(reg); 4816 __ fild_s(Operand(esp, 0)); 4817 __ pop(reg); 4818 } else { 4819 // There's no fild variant for unsigned values, so zero-extend to a 64-bit 4820 // int manually. 4821 __ push(Immediate(0)); 4822 __ push(reg); 4823 __ fild_d(Operand(esp, 0)); 4824 __ pop(reg); 4825 __ pop(reg); 4826 } 4827 4828 if (FLAG_inline_new) { 4829 __ AllocateHeapNumber(reg, tmp, no_reg, &slow); 4830 __ jmp(&done, Label::kNear); 4831 } 4832 4833 // Slow case: Call the runtime system to do the number allocation. 4834 __ bind(&slow); 4835 { 4836 // TODO(3095996): Put a valid pointer value in the stack slot where the 4837 // result register is stored, as this register is in the pointer map, but 4838 // contains an integer value. 4839 __ Move(reg, Immediate(0)); 4840 4841 // Preserve the value of all registers. 4842 PushSafepointRegistersScope scope(this); 4843 4844 // NumberTagI and NumberTagD use the context from the frame, rather than 4845 // the environment's HContext or HInlinedContext value. 4846 // They only call Runtime::kAllocateHeapNumber. 4847 // The corresponding HChange instructions are added in a phase that does 4848 // not have easy access to the local context. 4849 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 4850 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); 4851 RecordSafepointWithRegisters( 4852 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); 4853 __ StoreToSafepointRegisterSlot(reg, eax); 4854 } 4855 4856 __ bind(&done); 4857 __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset)); 4858 } 4859 4860 4861 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { 4862 class DeferredNumberTagD final : public LDeferredCode { 4863 public: 4864 DeferredNumberTagD(LCodeGen* codegen, 4865 LNumberTagD* instr, 4866 const X87Stack& x87_stack) 4867 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 4868 void Generate() override { codegen()->DoDeferredNumberTagD(instr_); } 4869 LInstruction* instr() override { return instr_; } 4870 4871 private: 4872 LNumberTagD* instr_; 4873 }; 4874 4875 Register reg = ToRegister(instr->result()); 4876 4877 // Put the value to the top of stack 4878 X87Register src = ToX87Register(instr->value()); 4879 // Don't use X87LoadForUsage here, which is only used by Instruction which 4880 // clobbers fp registers. 4881 x87_stack_.Fxch(src); 4882 4883 DeferredNumberTagD* deferred = 4884 new(zone()) DeferredNumberTagD(this, instr, x87_stack_); 4885 if (FLAG_inline_new) { 4886 Register tmp = ToRegister(instr->temp()); 4887 __ AllocateHeapNumber(reg, tmp, no_reg, deferred->entry()); 4888 } else { 4889 __ jmp(deferred->entry()); 4890 } 4891 __ bind(deferred->exit()); 4892 __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset)); 4893 } 4894 4895 4896 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { 4897 // TODO(3095996): Get rid of this. For now, we need to make the 4898 // result register contain a valid pointer because it is already 4899 // contained in the register pointer map. 4900 Register reg = ToRegister(instr->result()); 4901 __ Move(reg, Immediate(0)); 4902 4903 PushSafepointRegistersScope scope(this); 4904 // NumberTagI and NumberTagD use the context from the frame, rather than 4905 // the environment's HContext or HInlinedContext value. 4906 // They only call Runtime::kAllocateHeapNumber. 4907 // The corresponding HChange instructions are added in a phase that does 4908 // not have easy access to the local context. 4909 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 4910 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); 4911 RecordSafepointWithRegisters( 4912 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); 4913 __ StoreToSafepointRegisterSlot(reg, eax); 4914 } 4915 4916 4917 void LCodeGen::DoSmiTag(LSmiTag* instr) { 4918 HChange* hchange = instr->hydrogen(); 4919 Register input = ToRegister(instr->value()); 4920 if (hchange->CheckFlag(HValue::kCanOverflow) && 4921 hchange->value()->CheckFlag(HValue::kUint32)) { 4922 __ test(input, Immediate(0xc0000000)); 4923 DeoptimizeIf(not_zero, instr, Deoptimizer::kOverflow); 4924 } 4925 __ SmiTag(input); 4926 if (hchange->CheckFlag(HValue::kCanOverflow) && 4927 !hchange->value()->CheckFlag(HValue::kUint32)) { 4928 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 4929 } 4930 } 4931 4932 4933 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { 4934 LOperand* input = instr->value(); 4935 Register result = ToRegister(input); 4936 DCHECK(input->IsRegister() && input->Equals(instr->result())); 4937 if (instr->needs_check()) { 4938 __ test(result, Immediate(kSmiTagMask)); 4939 DeoptimizeIf(not_zero, instr, Deoptimizer::kNotASmi); 4940 } else { 4941 __ AssertSmi(result); 4942 } 4943 __ SmiUntag(result); 4944 } 4945 4946 4947 void LCodeGen::EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input_reg, 4948 Register temp_reg, X87Register res_reg, 4949 NumberUntagDMode mode) { 4950 bool can_convert_undefined_to_nan = 4951 instr->hydrogen()->can_convert_undefined_to_nan(); 4952 bool deoptimize_on_minus_zero = instr->hydrogen()->deoptimize_on_minus_zero(); 4953 4954 Label load_smi, done; 4955 4956 X87PrepareToWrite(res_reg); 4957 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { 4958 // Smi check. 4959 __ JumpIfSmi(input_reg, &load_smi); 4960 4961 // Heap number map check. 4962 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), 4963 factory()->heap_number_map()); 4964 if (!can_convert_undefined_to_nan) { 4965 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); 4966 } else { 4967 Label heap_number, convert; 4968 __ j(equal, &heap_number); 4969 4970 // Convert undefined (or hole) to NaN. 4971 __ cmp(input_reg, factory()->undefined_value()); 4972 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumberUndefined); 4973 4974 __ bind(&convert); 4975 __ push(Immediate(0xffffffff)); 4976 __ push(Immediate(0x7fffffff)); 4977 __ fld_d(MemOperand(esp, 0)); 4978 __ lea(esp, Operand(esp, kDoubleSize)); 4979 __ jmp(&done, Label::kNear); 4980 4981 __ bind(&heap_number); 4982 } 4983 // Heap number to x87 conversion. 4984 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); 4985 if (deoptimize_on_minus_zero) { 4986 __ fldz(); 4987 __ FCmp(); 4988 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); 4989 __ j(not_zero, &done, Label::kNear); 4990 4991 // Use general purpose registers to check if we have -0.0 4992 __ mov(temp_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 4993 __ test(temp_reg, Immediate(HeapNumber::kSignMask)); 4994 __ j(zero, &done, Label::kNear); 4995 4996 // Pop FPU stack before deoptimizing. 4997 __ fstp(0); 4998 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); 4999 } 5000 __ jmp(&done, Label::kNear); 5001 } else { 5002 DCHECK(mode == NUMBER_CANDIDATE_IS_SMI); 5003 } 5004 5005 __ bind(&load_smi); 5006 // Clobbering a temp is faster than re-tagging the 5007 // input register since we avoid dependencies. 5008 __ mov(temp_reg, input_reg); 5009 __ SmiUntag(temp_reg); // Untag smi before converting to float. 5010 __ push(temp_reg); 5011 __ fild_s(Operand(esp, 0)); 5012 __ add(esp, Immediate(kPointerSize)); 5013 __ bind(&done); 5014 X87CommitWrite(res_reg); 5015 } 5016 5017 5018 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) { 5019 Register input_reg = ToRegister(instr->value()); 5020 5021 // The input was optimistically untagged; revert it. 5022 STATIC_ASSERT(kSmiTagSize == 1); 5023 __ lea(input_reg, Operand(input_reg, times_2, kHeapObjectTag)); 5024 5025 if (instr->truncating()) { 5026 Label no_heap_number, check_bools, check_false; 5027 5028 // Heap number map check. 5029 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), 5030 factory()->heap_number_map()); 5031 __ j(not_equal, &no_heap_number, Label::kNear); 5032 __ TruncateHeapNumberToI(input_reg, input_reg); 5033 __ jmp(done); 5034 5035 __ bind(&no_heap_number); 5036 // Check for Oddballs. Undefined/False is converted to zero and True to one 5037 // for truncating conversions. 5038 __ cmp(input_reg, factory()->undefined_value()); 5039 __ j(not_equal, &check_bools, Label::kNear); 5040 __ Move(input_reg, Immediate(0)); 5041 __ jmp(done); 5042 5043 __ bind(&check_bools); 5044 __ cmp(input_reg, factory()->true_value()); 5045 __ j(not_equal, &check_false, Label::kNear); 5046 __ Move(input_reg, Immediate(1)); 5047 __ jmp(done); 5048 5049 __ bind(&check_false); 5050 __ cmp(input_reg, factory()->false_value()); 5051 DeoptimizeIf(not_equal, instr, 5052 Deoptimizer::kNotAHeapNumberUndefinedBoolean); 5053 __ Move(input_reg, Immediate(0)); 5054 } else { 5055 // TODO(olivf) Converting a number on the fpu is actually quite slow. We 5056 // should first try a fast conversion and then bailout to this slow case. 5057 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), 5058 isolate()->factory()->heap_number_map()); 5059 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumber); 5060 5061 __ sub(esp, Immediate(kPointerSize)); 5062 __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); 5063 5064 if (instr->hydrogen()->GetMinusZeroMode() == FAIL_ON_MINUS_ZERO) { 5065 Label no_precision_lost, not_nan, zero_check; 5066 __ fld(0); 5067 5068 __ fist_s(MemOperand(esp, 0)); 5069 __ fild_s(MemOperand(esp, 0)); 5070 __ FCmp(); 5071 __ pop(input_reg); 5072 5073 __ j(equal, &no_precision_lost, Label::kNear); 5074 __ fstp(0); 5075 DeoptimizeIf(no_condition, instr, Deoptimizer::kLostPrecision); 5076 __ bind(&no_precision_lost); 5077 5078 __ j(parity_odd, ¬_nan); 5079 __ fstp(0); 5080 DeoptimizeIf(no_condition, instr, Deoptimizer::kNaN); 5081 __ bind(¬_nan); 5082 5083 __ test(input_reg, Operand(input_reg)); 5084 __ j(zero, &zero_check, Label::kNear); 5085 __ fstp(0); 5086 __ jmp(done); 5087 5088 __ bind(&zero_check); 5089 // To check for minus zero, we load the value again as float, and check 5090 // if that is still 0. 5091 __ sub(esp, Immediate(kPointerSize)); 5092 __ fstp_s(Operand(esp, 0)); 5093 __ pop(input_reg); 5094 __ test(input_reg, Operand(input_reg)); 5095 DeoptimizeIf(not_zero, instr, Deoptimizer::kMinusZero); 5096 } else { 5097 __ fist_s(MemOperand(esp, 0)); 5098 __ fild_s(MemOperand(esp, 0)); 5099 __ FCmp(); 5100 __ pop(input_reg); 5101 DeoptimizeIf(not_equal, instr, Deoptimizer::kLostPrecision); 5102 DeoptimizeIf(parity_even, instr, Deoptimizer::kNaN); 5103 } 5104 } 5105 } 5106 5107 5108 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { 5109 class DeferredTaggedToI final : public LDeferredCode { 5110 public: 5111 DeferredTaggedToI(LCodeGen* codegen, 5112 LTaggedToI* instr, 5113 const X87Stack& x87_stack) 5114 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 5115 void Generate() override { codegen()->DoDeferredTaggedToI(instr_, done()); } 5116 LInstruction* instr() override { return instr_; } 5117 5118 private: 5119 LTaggedToI* instr_; 5120 }; 5121 5122 LOperand* input = instr->value(); 5123 DCHECK(input->IsRegister()); 5124 Register input_reg = ToRegister(input); 5125 DCHECK(input_reg.is(ToRegister(instr->result()))); 5126 5127 if (instr->hydrogen()->value()->representation().IsSmi()) { 5128 __ SmiUntag(input_reg); 5129 } else { 5130 DeferredTaggedToI* deferred = 5131 new(zone()) DeferredTaggedToI(this, instr, x87_stack_); 5132 // Optimistically untag the input. 5133 // If the input is a HeapObject, SmiUntag will set the carry flag. 5134 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 5135 __ SmiUntag(input_reg); 5136 // Branch to deferred code if the input was tagged. 5137 // The deferred code will take care of restoring the tag. 5138 __ j(carry, deferred->entry()); 5139 __ bind(deferred->exit()); 5140 } 5141 } 5142 5143 5144 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { 5145 LOperand* input = instr->value(); 5146 DCHECK(input->IsRegister()); 5147 LOperand* temp = instr->temp(); 5148 DCHECK(temp->IsRegister()); 5149 LOperand* result = instr->result(); 5150 DCHECK(result->IsDoubleRegister()); 5151 5152 Register input_reg = ToRegister(input); 5153 Register temp_reg = ToRegister(temp); 5154 5155 HValue* value = instr->hydrogen()->value(); 5156 NumberUntagDMode mode = value->representation().IsSmi() 5157 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED; 5158 5159 EmitNumberUntagDNoSSE2(instr, input_reg, temp_reg, ToX87Register(result), 5160 mode); 5161 } 5162 5163 5164 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { 5165 LOperand* input = instr->value(); 5166 DCHECK(input->IsDoubleRegister()); 5167 LOperand* result = instr->result(); 5168 DCHECK(result->IsRegister()); 5169 Register result_reg = ToRegister(result); 5170 5171 if (instr->truncating()) { 5172 X87Register input_reg = ToX87Register(input); 5173 X87Fxch(input_reg); 5174 __ TruncateX87TOSToI(result_reg); 5175 } else { 5176 Label lost_precision, is_nan, minus_zero, done; 5177 X87Register input_reg = ToX87Register(input); 5178 X87Fxch(input_reg); 5179 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(), 5180 &lost_precision, &is_nan, &minus_zero); 5181 __ jmp(&done); 5182 __ bind(&lost_precision); 5183 DeoptimizeIf(no_condition, instr, Deoptimizer::kLostPrecision); 5184 __ bind(&is_nan); 5185 DeoptimizeIf(no_condition, instr, Deoptimizer::kNaN); 5186 __ bind(&minus_zero); 5187 DeoptimizeIf(no_condition, instr, Deoptimizer::kMinusZero); 5188 __ bind(&done); 5189 } 5190 } 5191 5192 5193 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { 5194 LOperand* input = instr->value(); 5195 DCHECK(input->IsDoubleRegister()); 5196 LOperand* result = instr->result(); 5197 DCHECK(result->IsRegister()); 5198 Register result_reg = ToRegister(result); 5199 5200 Label lost_precision, is_nan, minus_zero, done; 5201 X87Register input_reg = ToX87Register(input); 5202 X87Fxch(input_reg); 5203 __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(), 5204 &lost_precision, &is_nan, &minus_zero); 5205 __ jmp(&done); 5206 __ bind(&lost_precision); 5207 DeoptimizeIf(no_condition, instr, Deoptimizer::kLostPrecision); 5208 __ bind(&is_nan); 5209 DeoptimizeIf(no_condition, instr, Deoptimizer::kNaN); 5210 __ bind(&minus_zero); 5211 DeoptimizeIf(no_condition, instr, Deoptimizer::kMinusZero); 5212 __ bind(&done); 5213 __ SmiTag(result_reg); 5214 DeoptimizeIf(overflow, instr, Deoptimizer::kOverflow); 5215 } 5216 5217 5218 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { 5219 LOperand* input = instr->value(); 5220 __ test(ToOperand(input), Immediate(kSmiTagMask)); 5221 DeoptimizeIf(not_zero, instr, Deoptimizer::kNotASmi); 5222 } 5223 5224 5225 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { 5226 if (!instr->hydrogen()->value()->type().IsHeapObject()) { 5227 LOperand* input = instr->value(); 5228 __ test(ToOperand(input), Immediate(kSmiTagMask)); 5229 DeoptimizeIf(zero, instr, Deoptimizer::kSmi); 5230 } 5231 } 5232 5233 5234 void LCodeGen::DoCheckArrayBufferNotNeutered( 5235 LCheckArrayBufferNotNeutered* instr) { 5236 Register view = ToRegister(instr->view()); 5237 Register scratch = ToRegister(instr->scratch()); 5238 5239 __ mov(scratch, FieldOperand(view, JSArrayBufferView::kBufferOffset)); 5240 __ test_b(FieldOperand(scratch, JSArrayBuffer::kBitFieldOffset), 5241 1 << JSArrayBuffer::WasNeutered::kShift); 5242 DeoptimizeIf(not_zero, instr, Deoptimizer::kOutOfBounds); 5243 } 5244 5245 5246 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { 5247 Register input = ToRegister(instr->value()); 5248 Register temp = ToRegister(instr->temp()); 5249 5250 __ mov(temp, FieldOperand(input, HeapObject::kMapOffset)); 5251 5252 if (instr->hydrogen()->is_interval_check()) { 5253 InstanceType first; 5254 InstanceType last; 5255 instr->hydrogen()->GetCheckInterval(&first, &last); 5256 5257 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), 5258 static_cast<int8_t>(first)); 5259 5260 // If there is only one type in the interval check for equality. 5261 if (first == last) { 5262 DeoptimizeIf(not_equal, instr, Deoptimizer::kWrongInstanceType); 5263 } else { 5264 DeoptimizeIf(below, instr, Deoptimizer::kWrongInstanceType); 5265 // Omit check for the last type. 5266 if (last != LAST_TYPE) { 5267 __ cmpb(FieldOperand(temp, Map::kInstanceTypeOffset), 5268 static_cast<int8_t>(last)); 5269 DeoptimizeIf(above, instr, Deoptimizer::kWrongInstanceType); 5270 } 5271 } 5272 } else { 5273 uint8_t mask; 5274 uint8_t tag; 5275 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); 5276 5277 if (base::bits::IsPowerOfTwo32(mask)) { 5278 DCHECK(tag == 0 || base::bits::IsPowerOfTwo32(tag)); 5279 __ test_b(FieldOperand(temp, Map::kInstanceTypeOffset), mask); 5280 DeoptimizeIf(tag == 0 ? not_zero : zero, instr, 5281 Deoptimizer::kWrongInstanceType); 5282 } else { 5283 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); 5284 __ and_(temp, mask); 5285 __ cmp(temp, tag); 5286 DeoptimizeIf(not_equal, instr, Deoptimizer::kWrongInstanceType); 5287 } 5288 } 5289 } 5290 5291 5292 void LCodeGen::DoCheckValue(LCheckValue* instr) { 5293 Handle<HeapObject> object = instr->hydrogen()->object().handle(); 5294 if (instr->hydrogen()->object_in_new_space()) { 5295 Register reg = ToRegister(instr->value()); 5296 Handle<Cell> cell = isolate()->factory()->NewCell(object); 5297 __ cmp(reg, Operand::ForCell(cell)); 5298 } else { 5299 Operand operand = ToOperand(instr->value()); 5300 __ cmp(operand, object); 5301 } 5302 DeoptimizeIf(not_equal, instr, Deoptimizer::kValueMismatch); 5303 } 5304 5305 5306 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { 5307 { 5308 PushSafepointRegistersScope scope(this); 5309 __ push(object); 5310 __ xor_(esi, esi); 5311 __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance); 5312 RecordSafepointWithRegisters( 5313 instr->pointer_map(), 1, Safepoint::kNoLazyDeopt); 5314 5315 __ test(eax, Immediate(kSmiTagMask)); 5316 } 5317 DeoptimizeIf(zero, instr, Deoptimizer::kInstanceMigrationFailed); 5318 } 5319 5320 5321 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { 5322 class DeferredCheckMaps final : public LDeferredCode { 5323 public: 5324 DeferredCheckMaps(LCodeGen* codegen, 5325 LCheckMaps* instr, 5326 Register object, 5327 const X87Stack& x87_stack) 5328 : LDeferredCode(codegen, x87_stack), instr_(instr), object_(object) { 5329 SetExit(check_maps()); 5330 } 5331 void Generate() override { 5332 codegen()->DoDeferredInstanceMigration(instr_, object_); 5333 } 5334 Label* check_maps() { return &check_maps_; } 5335 LInstruction* instr() override { return instr_; } 5336 5337 private: 5338 LCheckMaps* instr_; 5339 Label check_maps_; 5340 Register object_; 5341 }; 5342 5343 if (instr->hydrogen()->IsStabilityCheck()) { 5344 const UniqueSet<Map>* maps = instr->hydrogen()->maps(); 5345 for (int i = 0; i < maps->size(); ++i) { 5346 AddStabilityDependency(maps->at(i).handle()); 5347 } 5348 return; 5349 } 5350 5351 LOperand* input = instr->value(); 5352 DCHECK(input->IsRegister()); 5353 Register reg = ToRegister(input); 5354 5355 DeferredCheckMaps* deferred = NULL; 5356 if (instr->hydrogen()->HasMigrationTarget()) { 5357 deferred = new(zone()) DeferredCheckMaps(this, instr, reg, x87_stack_); 5358 __ bind(deferred->check_maps()); 5359 } 5360 5361 const UniqueSet<Map>* maps = instr->hydrogen()->maps(); 5362 Label success; 5363 for (int i = 0; i < maps->size() - 1; i++) { 5364 Handle<Map> map = maps->at(i).handle(); 5365 __ CompareMap(reg, map); 5366 __ j(equal, &success, Label::kNear); 5367 } 5368 5369 Handle<Map> map = maps->at(maps->size() - 1).handle(); 5370 __ CompareMap(reg, map); 5371 if (instr->hydrogen()->HasMigrationTarget()) { 5372 __ j(not_equal, deferred->entry()); 5373 } else { 5374 DeoptimizeIf(not_equal, instr, Deoptimizer::kWrongMap); 5375 } 5376 5377 __ bind(&success); 5378 } 5379 5380 5381 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { 5382 X87Register value_reg = ToX87Register(instr->unclamped()); 5383 Register result_reg = ToRegister(instr->result()); 5384 X87Fxch(value_reg); 5385 __ ClampTOSToUint8(result_reg); 5386 } 5387 5388 5389 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { 5390 DCHECK(instr->unclamped()->Equals(instr->result())); 5391 Register value_reg = ToRegister(instr->result()); 5392 __ ClampUint8(value_reg); 5393 } 5394 5395 5396 void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) { 5397 Register input_reg = ToRegister(instr->unclamped()); 5398 Register result_reg = ToRegister(instr->result()); 5399 Register scratch = ToRegister(instr->scratch()); 5400 Register scratch2 = ToRegister(instr->scratch2()); 5401 Register scratch3 = ToRegister(instr->scratch3()); 5402 Label is_smi, done, heap_number, valid_exponent, 5403 largest_value, zero_result, maybe_nan_or_infinity; 5404 5405 __ JumpIfSmi(input_reg, &is_smi); 5406 5407 // Check for heap number 5408 __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset), 5409 factory()->heap_number_map()); 5410 __ j(equal, &heap_number, Label::kNear); 5411 5412 // Check for undefined. Undefined is converted to zero for clamping 5413 // conversions. 5414 __ cmp(input_reg, factory()->undefined_value()); 5415 DeoptimizeIf(not_equal, instr, Deoptimizer::kNotAHeapNumberUndefined); 5416 __ jmp(&zero_result, Label::kNear); 5417 5418 // Heap number 5419 __ bind(&heap_number); 5420 5421 // Surprisingly, all of the hand-crafted bit-manipulations below are much 5422 // faster than the x86 FPU built-in instruction, especially since "banker's 5423 // rounding" would be additionally very expensive 5424 5425 // Get exponent word. 5426 __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 5427 __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); 5428 5429 // Test for negative values --> clamp to zero 5430 __ test(scratch, scratch); 5431 __ j(negative, &zero_result, Label::kNear); 5432 5433 // Get exponent alone in scratch2. 5434 __ mov(scratch2, scratch); 5435 __ and_(scratch2, HeapNumber::kExponentMask); 5436 __ shr(scratch2, HeapNumber::kExponentShift); 5437 __ j(zero, &zero_result, Label::kNear); 5438 __ sub(scratch2, Immediate(HeapNumber::kExponentBias - 1)); 5439 __ j(negative, &zero_result, Label::kNear); 5440 5441 const uint32_t non_int8_exponent = 7; 5442 __ cmp(scratch2, Immediate(non_int8_exponent + 1)); 5443 // If the exponent is too big, check for special values. 5444 __ j(greater, &maybe_nan_or_infinity, Label::kNear); 5445 5446 __ bind(&valid_exponent); 5447 // Exponent word in scratch, exponent in scratch2. We know that 0 <= exponent 5448 // < 7. The shift bias is the number of bits to shift the mantissa such that 5449 // with an exponent of 7 such the that top-most one is in bit 30, allowing 5450 // detection the rounding overflow of a 255.5 to 256 (bit 31 goes from 0 to 5451 // 1). 5452 int shift_bias = (30 - HeapNumber::kExponentShift) - 7 - 1; 5453 __ lea(result_reg, MemOperand(scratch2, shift_bias)); 5454 // Here result_reg (ecx) is the shift, scratch is the exponent word. Get the 5455 // top bits of the mantissa. 5456 __ and_(scratch, HeapNumber::kMantissaMask); 5457 // Put back the implicit 1 of the mantissa 5458 __ or_(scratch, 1 << HeapNumber::kExponentShift); 5459 // Shift up to round 5460 __ shl_cl(scratch); 5461 // Use "banker's rounding" to spec: If fractional part of number is 0.5, then 5462 // use the bit in the "ones" place and add it to the "halves" place, which has 5463 // the effect of rounding to even. 5464 __ mov(scratch2, scratch); 5465 const uint32_t one_half_bit_shift = 30 - sizeof(uint8_t) * 8; 5466 const uint32_t one_bit_shift = one_half_bit_shift + 1; 5467 __ and_(scratch2, Immediate((1 << one_bit_shift) - 1)); 5468 __ cmp(scratch2, Immediate(1 << one_half_bit_shift)); 5469 Label no_round; 5470 __ j(less, &no_round, Label::kNear); 5471 Label round_up; 5472 __ mov(scratch2, Immediate(1 << one_half_bit_shift)); 5473 __ j(greater, &round_up, Label::kNear); 5474 __ test(scratch3, scratch3); 5475 __ j(not_zero, &round_up, Label::kNear); 5476 __ mov(scratch2, scratch); 5477 __ and_(scratch2, Immediate(1 << one_bit_shift)); 5478 __ shr(scratch2, 1); 5479 __ bind(&round_up); 5480 __ add(scratch, scratch2); 5481 __ j(overflow, &largest_value, Label::kNear); 5482 __ bind(&no_round); 5483 __ shr(scratch, 23); 5484 __ mov(result_reg, scratch); 5485 __ jmp(&done, Label::kNear); 5486 5487 __ bind(&maybe_nan_or_infinity); 5488 // Check for NaN/Infinity, all other values map to 255 5489 __ cmp(scratch2, Immediate(HeapNumber::kInfinityOrNanExponent + 1)); 5490 __ j(not_equal, &largest_value, Label::kNear); 5491 5492 // Check for NaN, which differs from Infinity in that at least one mantissa 5493 // bit is set. 5494 __ and_(scratch, HeapNumber::kMantissaMask); 5495 __ or_(scratch, FieldOperand(input_reg, HeapNumber::kMantissaOffset)); 5496 __ j(not_zero, &zero_result, Label::kNear); // M!=0 --> NaN 5497 // Infinity -> Fall through to map to 255. 5498 5499 __ bind(&largest_value); 5500 __ mov(result_reg, Immediate(255)); 5501 __ jmp(&done, Label::kNear); 5502 5503 __ bind(&zero_result); 5504 __ xor_(result_reg, result_reg); 5505 __ jmp(&done, Label::kNear); 5506 5507 // smi 5508 __ bind(&is_smi); 5509 if (!input_reg.is(result_reg)) { 5510 __ mov(result_reg, input_reg); 5511 } 5512 __ SmiUntag(result_reg); 5513 __ ClampUint8(result_reg); 5514 __ bind(&done); 5515 } 5516 5517 5518 void LCodeGen::DoDoubleBits(LDoubleBits* instr) { 5519 X87Register value_reg = ToX87Register(instr->value()); 5520 Register result_reg = ToRegister(instr->result()); 5521 X87Fxch(value_reg); 5522 __ sub(esp, Immediate(kDoubleSize)); 5523 __ fst_d(Operand(esp, 0)); 5524 if (instr->hydrogen()->bits() == HDoubleBits::HIGH) { 5525 __ mov(result_reg, Operand(esp, kPointerSize)); 5526 } else { 5527 __ mov(result_reg, Operand(esp, 0)); 5528 } 5529 __ add(esp, Immediate(kDoubleSize)); 5530 } 5531 5532 5533 void LCodeGen::DoConstructDouble(LConstructDouble* instr) { 5534 Register hi_reg = ToRegister(instr->hi()); 5535 Register lo_reg = ToRegister(instr->lo()); 5536 X87Register result_reg = ToX87Register(instr->result()); 5537 // Follow below pattern to write a x87 fp register. 5538 X87PrepareToWrite(result_reg); 5539 __ sub(esp, Immediate(kDoubleSize)); 5540 __ mov(Operand(esp, 0), lo_reg); 5541 __ mov(Operand(esp, kPointerSize), hi_reg); 5542 __ fld_d(Operand(esp, 0)); 5543 __ add(esp, Immediate(kDoubleSize)); 5544 X87CommitWrite(result_reg); 5545 } 5546 5547 5548 void LCodeGen::DoAllocate(LAllocate* instr) { 5549 class DeferredAllocate final : public LDeferredCode { 5550 public: 5551 DeferredAllocate(LCodeGen* codegen, 5552 LAllocate* instr, 5553 const X87Stack& x87_stack) 5554 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 5555 void Generate() override { codegen()->DoDeferredAllocate(instr_); } 5556 LInstruction* instr() override { return instr_; } 5557 5558 private: 5559 LAllocate* instr_; 5560 }; 5561 5562 DeferredAllocate* deferred = 5563 new(zone()) DeferredAllocate(this, instr, x87_stack_); 5564 5565 Register result = ToRegister(instr->result()); 5566 Register temp = ToRegister(instr->temp()); 5567 5568 // Allocate memory for the object. 5569 AllocationFlags flags = TAG_OBJECT; 5570 if (instr->hydrogen()->MustAllocateDoubleAligned()) { 5571 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT); 5572 } 5573 if (instr->hydrogen()->IsOldSpaceAllocation()) { 5574 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation()); 5575 flags = static_cast<AllocationFlags>(flags | PRETENURE); 5576 } 5577 5578 if (instr->size()->IsConstantOperand()) { 5579 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); 5580 CHECK(size <= Page::kMaxRegularHeapObjectSize); 5581 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags); 5582 } else { 5583 Register size = ToRegister(instr->size()); 5584 __ Allocate(size, result, temp, no_reg, deferred->entry(), flags); 5585 } 5586 5587 __ bind(deferred->exit()); 5588 5589 if (instr->hydrogen()->MustPrefillWithFiller()) { 5590 if (instr->size()->IsConstantOperand()) { 5591 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); 5592 __ mov(temp, (size / kPointerSize) - 1); 5593 } else { 5594 temp = ToRegister(instr->size()); 5595 __ shr(temp, kPointerSizeLog2); 5596 __ dec(temp); 5597 } 5598 Label loop; 5599 __ bind(&loop); 5600 __ mov(FieldOperand(result, temp, times_pointer_size, 0), 5601 isolate()->factory()->one_pointer_filler_map()); 5602 __ dec(temp); 5603 __ j(not_zero, &loop); 5604 } 5605 } 5606 5607 5608 void LCodeGen::DoDeferredAllocate(LAllocate* instr) { 5609 Register result = ToRegister(instr->result()); 5610 5611 // TODO(3095996): Get rid of this. For now, we need to make the 5612 // result register contain a valid pointer because it is already 5613 // contained in the register pointer map. 5614 __ Move(result, Immediate(Smi::FromInt(0))); 5615 5616 PushSafepointRegistersScope scope(this); 5617 if (instr->size()->IsRegister()) { 5618 Register size = ToRegister(instr->size()); 5619 DCHECK(!size.is(result)); 5620 __ SmiTag(ToRegister(instr->size())); 5621 __ push(size); 5622 } else { 5623 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); 5624 if (size >= 0 && size <= Smi::kMaxValue) { 5625 __ push(Immediate(Smi::FromInt(size))); 5626 } else { 5627 // We should never get here at runtime => abort 5628 __ int3(); 5629 return; 5630 } 5631 } 5632 5633 int flags = AllocateDoubleAlignFlag::encode( 5634 instr->hydrogen()->MustAllocateDoubleAligned()); 5635 if (instr->hydrogen()->IsOldSpaceAllocation()) { 5636 DCHECK(!instr->hydrogen()->IsNewSpaceAllocation()); 5637 flags = AllocateTargetSpace::update(flags, OLD_SPACE); 5638 } else { 5639 flags = AllocateTargetSpace::update(flags, NEW_SPACE); 5640 } 5641 __ push(Immediate(Smi::FromInt(flags))); 5642 5643 CallRuntimeFromDeferred( 5644 Runtime::kAllocateInTargetSpace, 2, instr, instr->context()); 5645 __ StoreToSafepointRegisterSlot(result, eax); 5646 } 5647 5648 5649 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { 5650 DCHECK(ToRegister(instr->value()).is(eax)); 5651 __ push(eax); 5652 CallRuntime(Runtime::kToFastProperties, 1, instr); 5653 } 5654 5655 5656 void LCodeGen::DoTypeof(LTypeof* instr) { 5657 DCHECK(ToRegister(instr->context()).is(esi)); 5658 DCHECK(ToRegister(instr->value()).is(ebx)); 5659 Label end, do_call; 5660 Register value_register = ToRegister(instr->value()); 5661 __ JumpIfNotSmi(value_register, &do_call); 5662 __ mov(eax, Immediate(isolate()->factory()->number_string())); 5663 __ jmp(&end); 5664 __ bind(&do_call); 5665 TypeofStub stub(isolate()); 5666 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 5667 __ bind(&end); 5668 } 5669 5670 5671 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { 5672 Register input = ToRegister(instr->value()); 5673 Condition final_branch_condition = EmitTypeofIs(instr, input); 5674 if (final_branch_condition != no_condition) { 5675 EmitBranch(instr, final_branch_condition); 5676 } 5677 } 5678 5679 5680 Condition LCodeGen::EmitTypeofIs(LTypeofIsAndBranch* instr, Register input) { 5681 Label* true_label = instr->TrueLabel(chunk_); 5682 Label* false_label = instr->FalseLabel(chunk_); 5683 Handle<String> type_name = instr->type_literal(); 5684 int left_block = instr->TrueDestination(chunk_); 5685 int right_block = instr->FalseDestination(chunk_); 5686 int next_block = GetNextEmittedBlock(); 5687 5688 Label::Distance true_distance = left_block == next_block ? Label::kNear 5689 : Label::kFar; 5690 Label::Distance false_distance = right_block == next_block ? Label::kNear 5691 : Label::kFar; 5692 Condition final_branch_condition = no_condition; 5693 if (String::Equals(type_name, factory()->number_string())) { 5694 __ JumpIfSmi(input, true_label, true_distance); 5695 __ cmp(FieldOperand(input, HeapObject::kMapOffset), 5696 factory()->heap_number_map()); 5697 final_branch_condition = equal; 5698 5699 } else if (String::Equals(type_name, factory()->string_string())) { 5700 __ JumpIfSmi(input, false_label, false_distance); 5701 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); 5702 final_branch_condition = below; 5703 5704 } else if (String::Equals(type_name, factory()->symbol_string())) { 5705 __ JumpIfSmi(input, false_label, false_distance); 5706 __ CmpObjectType(input, SYMBOL_TYPE, input); 5707 final_branch_condition = equal; 5708 5709 } else if (String::Equals(type_name, factory()->boolean_string())) { 5710 __ cmp(input, factory()->true_value()); 5711 __ j(equal, true_label, true_distance); 5712 __ cmp(input, factory()->false_value()); 5713 final_branch_condition = equal; 5714 5715 } else if (String::Equals(type_name, factory()->undefined_string())) { 5716 __ cmp(input, factory()->undefined_value()); 5717 __ j(equal, true_label, true_distance); 5718 __ JumpIfSmi(input, false_label, false_distance); 5719 // Check for undetectable objects => true. 5720 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); 5721 __ test_b(FieldOperand(input, Map::kBitFieldOffset), 5722 1 << Map::kIsUndetectable); 5723 final_branch_condition = not_zero; 5724 5725 } else if (String::Equals(type_name, factory()->function_string())) { 5726 __ JumpIfSmi(input, false_label, false_distance); 5727 // Check for callable and not undetectable objects => true. 5728 __ mov(input, FieldOperand(input, HeapObject::kMapOffset)); 5729 __ movzx_b(input, FieldOperand(input, Map::kBitFieldOffset)); 5730 __ and_(input, (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); 5731 __ cmp(input, 1 << Map::kIsCallable); 5732 final_branch_condition = equal; 5733 5734 } else if (String::Equals(type_name, factory()->object_string())) { 5735 __ JumpIfSmi(input, false_label, false_distance); 5736 __ cmp(input, factory()->null_value()); 5737 __ j(equal, true_label, true_distance); 5738 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 5739 __ CmpObjectType(input, FIRST_JS_RECEIVER_TYPE, input); 5740 __ j(below, false_label, false_distance); 5741 // Check for callable or undetectable objects => false. 5742 __ test_b(FieldOperand(input, Map::kBitFieldOffset), 5743 (1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)); 5744 final_branch_condition = zero; 5745 5746 // clang-format off 5747 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 5748 } else if (String::Equals(type_name, factory()->type##_string())) { \ 5749 __ JumpIfSmi(input, false_label, false_distance); \ 5750 __ cmp(FieldOperand(input, HeapObject::kMapOffset), \ 5751 factory()->type##_map()); \ 5752 final_branch_condition = equal; 5753 SIMD128_TYPES(SIMD128_TYPE) 5754 #undef SIMD128_TYPE 5755 // clang-format on 5756 5757 } else { 5758 __ jmp(false_label, false_distance); 5759 } 5760 return final_branch_condition; 5761 } 5762 5763 5764 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { 5765 if (info()->ShouldEnsureSpaceForLazyDeopt()) { 5766 // Ensure that we have enough space after the previous lazy-bailout 5767 // instruction for patching the code here. 5768 int current_pc = masm()->pc_offset(); 5769 if (current_pc < last_lazy_deopt_pc_ + space_needed) { 5770 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; 5771 __ Nop(padding_size); 5772 } 5773 } 5774 last_lazy_deopt_pc_ = masm()->pc_offset(); 5775 } 5776 5777 5778 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { 5779 last_lazy_deopt_pc_ = masm()->pc_offset(); 5780 DCHECK(instr->HasEnvironment()); 5781 LEnvironment* env = instr->environment(); 5782 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 5783 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 5784 } 5785 5786 5787 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { 5788 Deoptimizer::BailoutType type = instr->hydrogen()->type(); 5789 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the 5790 // needed return address), even though the implementation of LAZY and EAGER is 5791 // now identical. When LAZY is eventually completely folded into EAGER, remove 5792 // the special case below. 5793 if (info()->IsStub() && type == Deoptimizer::EAGER) { 5794 type = Deoptimizer::LAZY; 5795 } 5796 DeoptimizeIf(no_condition, instr, instr->hydrogen()->reason(), type); 5797 } 5798 5799 5800 void LCodeGen::DoDummy(LDummy* instr) { 5801 // Nothing to see here, move on! 5802 } 5803 5804 5805 void LCodeGen::DoDummyUse(LDummyUse* instr) { 5806 // Nothing to see here, move on! 5807 } 5808 5809 5810 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { 5811 PushSafepointRegistersScope scope(this); 5812 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 5813 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); 5814 RecordSafepointWithLazyDeopt( 5815 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 5816 DCHECK(instr->HasEnvironment()); 5817 LEnvironment* env = instr->environment(); 5818 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 5819 } 5820 5821 5822 void LCodeGen::DoStackCheck(LStackCheck* instr) { 5823 class DeferredStackCheck final : public LDeferredCode { 5824 public: 5825 DeferredStackCheck(LCodeGen* codegen, 5826 LStackCheck* instr, 5827 const X87Stack& x87_stack) 5828 : LDeferredCode(codegen, x87_stack), instr_(instr) { } 5829 void Generate() override { codegen()->DoDeferredStackCheck(instr_); } 5830 LInstruction* instr() override { return instr_; } 5831 5832 private: 5833 LStackCheck* instr_; 5834 }; 5835 5836 DCHECK(instr->HasEnvironment()); 5837 LEnvironment* env = instr->environment(); 5838 // There is no LLazyBailout instruction for stack-checks. We have to 5839 // prepare for lazy deoptimization explicitly here. 5840 if (instr->hydrogen()->is_function_entry()) { 5841 // Perform stack overflow check. 5842 Label done; 5843 ExternalReference stack_limit = 5844 ExternalReference::address_of_stack_limit(isolate()); 5845 __ cmp(esp, Operand::StaticVariable(stack_limit)); 5846 __ j(above_equal, &done, Label::kNear); 5847 5848 DCHECK(instr->context()->IsRegister()); 5849 DCHECK(ToRegister(instr->context()).is(esi)); 5850 CallCode(isolate()->builtins()->StackCheck(), 5851 RelocInfo::CODE_TARGET, 5852 instr); 5853 __ bind(&done); 5854 } else { 5855 DCHECK(instr->hydrogen()->is_backwards_branch()); 5856 // Perform stack overflow check if this goto needs it before jumping. 5857 DeferredStackCheck* deferred_stack_check = 5858 new(zone()) DeferredStackCheck(this, instr, x87_stack_); 5859 ExternalReference stack_limit = 5860 ExternalReference::address_of_stack_limit(isolate()); 5861 __ cmp(esp, Operand::StaticVariable(stack_limit)); 5862 __ j(below, deferred_stack_check->entry()); 5863 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 5864 __ bind(instr->done_label()); 5865 deferred_stack_check->SetExit(instr->done_label()); 5866 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 5867 // Don't record a deoptimization index for the safepoint here. 5868 // This will be done explicitly when emitting call and the safepoint in 5869 // the deferred code. 5870 } 5871 } 5872 5873 5874 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { 5875 // This is a pseudo-instruction that ensures that the environment here is 5876 // properly registered for deoptimization and records the assembler's PC 5877 // offset. 5878 LEnvironment* environment = instr->environment(); 5879 5880 // If the environment were already registered, we would have no way of 5881 // backpatching it with the spill slot operands. 5882 DCHECK(!environment->HasBeenRegistered()); 5883 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 5884 5885 GenerateOsrPrologue(); 5886 } 5887 5888 5889 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { 5890 DCHECK(ToRegister(instr->context()).is(esi)); 5891 __ test(eax, Immediate(kSmiTagMask)); 5892 DeoptimizeIf(zero, instr, Deoptimizer::kSmi); 5893 5894 STATIC_ASSERT(JS_PROXY_TYPE == FIRST_JS_RECEIVER_TYPE); 5895 __ CmpObjectType(eax, JS_PROXY_TYPE, ecx); 5896 DeoptimizeIf(below_equal, instr, Deoptimizer::kWrongInstanceType); 5897 5898 Label use_cache, call_runtime; 5899 __ CheckEnumCache(&call_runtime); 5900 5901 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); 5902 __ jmp(&use_cache, Label::kNear); 5903 5904 // Get the set of properties to enumerate. 5905 __ bind(&call_runtime); 5906 __ push(eax); 5907 CallRuntime(Runtime::kGetPropertyNamesFast, instr); 5908 5909 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), 5910 isolate()->factory()->meta_map()); 5911 DeoptimizeIf(not_equal, instr, Deoptimizer::kWrongMap); 5912 __ bind(&use_cache); 5913 } 5914 5915 5916 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { 5917 Register map = ToRegister(instr->map()); 5918 Register result = ToRegister(instr->result()); 5919 Label load_cache, done; 5920 __ EnumLength(result, map); 5921 __ cmp(result, Immediate(Smi::FromInt(0))); 5922 __ j(not_equal, &load_cache, Label::kNear); 5923 __ mov(result, isolate()->factory()->empty_fixed_array()); 5924 __ jmp(&done, Label::kNear); 5925 5926 __ bind(&load_cache); 5927 __ LoadInstanceDescriptors(map, result); 5928 __ mov(result, 5929 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); 5930 __ mov(result, 5931 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); 5932 __ bind(&done); 5933 __ test(result, result); 5934 DeoptimizeIf(equal, instr, Deoptimizer::kNoCache); 5935 } 5936 5937 5938 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { 5939 Register object = ToRegister(instr->value()); 5940 __ cmp(ToRegister(instr->map()), 5941 FieldOperand(object, HeapObject::kMapOffset)); 5942 DeoptimizeIf(not_equal, instr, Deoptimizer::kWrongMap); 5943 } 5944 5945 5946 void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr, 5947 Register object, 5948 Register index) { 5949 PushSafepointRegistersScope scope(this); 5950 __ push(object); 5951 __ push(index); 5952 __ xor_(esi, esi); 5953 __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble); 5954 RecordSafepointWithRegisters( 5955 instr->pointer_map(), 2, Safepoint::kNoLazyDeopt); 5956 __ StoreToSafepointRegisterSlot(object, eax); 5957 } 5958 5959 5960 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { 5961 class DeferredLoadMutableDouble final : public LDeferredCode { 5962 public: 5963 DeferredLoadMutableDouble(LCodeGen* codegen, 5964 LLoadFieldByIndex* instr, 5965 Register object, 5966 Register index, 5967 const X87Stack& x87_stack) 5968 : LDeferredCode(codegen, x87_stack), 5969 instr_(instr), 5970 object_(object), 5971 index_(index) { 5972 } 5973 void Generate() override { 5974 codegen()->DoDeferredLoadMutableDouble(instr_, object_, index_); 5975 } 5976 LInstruction* instr() override { return instr_; } 5977 5978 private: 5979 LLoadFieldByIndex* instr_; 5980 Register object_; 5981 Register index_; 5982 }; 5983 5984 Register object = ToRegister(instr->object()); 5985 Register index = ToRegister(instr->index()); 5986 5987 DeferredLoadMutableDouble* deferred; 5988 deferred = new(zone()) DeferredLoadMutableDouble( 5989 this, instr, object, index, x87_stack_); 5990 5991 Label out_of_object, done; 5992 __ test(index, Immediate(Smi::FromInt(1))); 5993 __ j(not_zero, deferred->entry()); 5994 5995 __ sar(index, 1); 5996 5997 __ cmp(index, Immediate(0)); 5998 __ j(less, &out_of_object, Label::kNear); 5999 __ mov(object, FieldOperand(object, 6000 index, 6001 times_half_pointer_size, 6002 JSObject::kHeaderSize)); 6003 __ jmp(&done, Label::kNear); 6004 6005 __ bind(&out_of_object); 6006 __ mov(object, FieldOperand(object, JSObject::kPropertiesOffset)); 6007 __ neg(index); 6008 // Index is now equal to out of object property index plus 1. 6009 __ mov(object, FieldOperand(object, 6010 index, 6011 times_half_pointer_size, 6012 FixedArray::kHeaderSize - kPointerSize)); 6013 __ bind(deferred->exit()); 6014 __ bind(&done); 6015 } 6016 6017 6018 void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) { 6019 Register context = ToRegister(instr->context()); 6020 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), context); 6021 } 6022 6023 6024 void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) { 6025 Handle<ScopeInfo> scope_info = instr->scope_info(); 6026 __ Push(scope_info); 6027 __ push(ToRegister(instr->function())); 6028 CallRuntime(Runtime::kPushBlockContext, instr); 6029 RecordSafepoint(Safepoint::kNoLazyDeopt); 6030 } 6031 6032 6033 #undef __ 6034 6035 } // namespace internal 6036 } // namespace v8 6037 6038 #endif // V8_TARGET_ARCH_X87 6039