lithium-codegen-x64.cc revision 592a9fc1d8ea420377a2e7efd0600e20b058be2b
1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "v8.h" 29 30#if defined(V8_TARGET_ARCH_X64) 31 32#include "x64/lithium-codegen-x64.h" 33#include "code-stubs.h" 34#include "stub-cache.h" 35 36namespace v8 { 37namespace internal { 38 39 40// When invoking builtins, we need to record the safepoint in the middle of 41// the invoke instruction sequence generated by the macro assembler. 42class SafepointGenerator : public CallWrapper { 43 public: 44 SafepointGenerator(LCodeGen* codegen, 45 LPointerMap* pointers, 46 Safepoint::DeoptMode mode) 47 : codegen_(codegen), 48 pointers_(pointers), 49 deopt_mode_(mode) { } 50 virtual ~SafepointGenerator() { } 51 52 virtual void BeforeCall(int call_size) const { 53 codegen_->EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - call_size); 54 } 55 56 virtual void AfterCall() const { 57 codegen_->RecordSafepoint(pointers_, deopt_mode_); 58 } 59 60 private: 61 LCodeGen* codegen_; 62 LPointerMap* pointers_; 63 Safepoint::DeoptMode deopt_mode_; 64}; 65 66 67#define __ masm()-> 68 69bool LCodeGen::GenerateCode() { 70 HPhase phase("Code generation", chunk()); 71 ASSERT(is_unused()); 72 status_ = GENERATING; 73 74 // Open a frame scope to indicate that there is a frame on the stack. The 75 // MANUAL indicates that the scope shouldn't actually generate code to set up 76 // the frame (that is done in GeneratePrologue). 77 FrameScope frame_scope(masm_, StackFrame::MANUAL); 78 79 return GeneratePrologue() && 80 GenerateBody() && 81 GenerateDeferredCode() && 82 GenerateJumpTable() && 83 GenerateSafepointTable(); 84} 85 86 87void LCodeGen::FinishCode(Handle<Code> code) { 88 ASSERT(is_done()); 89 code->set_stack_slots(GetStackSlotCount()); 90 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); 91 PopulateDeoptimizationData(code); 92} 93 94 95void LCodeGen::Abort(const char* format, ...) { 96 if (FLAG_trace_bailout) { 97 SmartArrayPointer<char> name( 98 info()->shared_info()->DebugName()->ToCString()); 99 PrintF("Aborting LCodeGen in @\"%s\": ", *name); 100 va_list arguments; 101 va_start(arguments, format); 102 OS::VPrint(format, arguments); 103 va_end(arguments); 104 PrintF("\n"); 105 } 106 status_ = ABORTED; 107} 108 109 110void LCodeGen::Comment(const char* format, ...) { 111 if (!FLAG_code_comments) return; 112 char buffer[4 * KB]; 113 StringBuilder builder(buffer, ARRAY_SIZE(buffer)); 114 va_list arguments; 115 va_start(arguments, format); 116 builder.AddFormattedList(format, arguments); 117 va_end(arguments); 118 119 // Copy the string before recording it in the assembler to avoid 120 // issues when the stack allocated buffer goes out of scope. 121 int length = builder.position(); 122 Vector<char> copy = Vector<char>::New(length + 1); 123 memcpy(copy.start(), builder.Finalize(), copy.length()); 124 masm()->RecordComment(copy.start()); 125} 126 127 128bool LCodeGen::GeneratePrologue() { 129 ASSERT(is_generating()); 130 131#ifdef DEBUG 132 if (strlen(FLAG_stop_at) > 0 && 133 info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { 134 __ int3(); 135 } 136#endif 137 138 // Strict mode functions need to replace the receiver with undefined 139 // when called as functions (without an explicit receiver 140 // object). rcx is zero for method calls and non-zero for function 141 // calls. 142 if (!info_->is_classic_mode() || info_->is_native()) { 143 Label ok; 144 __ testq(rcx, rcx); 145 __ j(zero, &ok, Label::kNear); 146 // +1 for return address. 147 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; 148 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); 149 __ movq(Operand(rsp, receiver_offset), kScratchRegister); 150 __ bind(&ok); 151 } 152 153 __ push(rbp); // Caller's frame pointer. 154 __ movq(rbp, rsp); 155 __ push(rsi); // Callee's context. 156 __ push(rdi); // Callee's JS function. 157 158 // Reserve space for the stack slots needed by the code. 159 int slots = GetStackSlotCount(); 160 if (slots > 0) { 161 if (FLAG_debug_code) { 162 __ Set(rax, slots); 163 __ movq(kScratchRegister, kSlotsZapValue, RelocInfo::NONE); 164 Label loop; 165 __ bind(&loop); 166 __ push(kScratchRegister); 167 __ decl(rax); 168 __ j(not_zero, &loop); 169 } else { 170 __ subq(rsp, Immediate(slots * kPointerSize)); 171#ifdef _MSC_VER 172 // On windows, you may not access the stack more than one page below 173 // the most recently mapped page. To make the allocated area randomly 174 // accessible, we write to each page in turn (the value is irrelevant). 175 const int kPageSize = 4 * KB; 176 for (int offset = slots * kPointerSize - kPageSize; 177 offset > 0; 178 offset -= kPageSize) { 179 __ movq(Operand(rsp, offset), rax); 180 } 181#endif 182 } 183 } 184 185 // Possibly allocate a local context. 186 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 187 if (heap_slots > 0) { 188 Comment(";;; Allocate local context"); 189 // Argument to NewContext is the function, which is still in rdi. 190 __ push(rdi); 191 if (heap_slots <= FastNewContextStub::kMaximumSlots) { 192 FastNewContextStub stub(heap_slots); 193 __ CallStub(&stub); 194 } else { 195 __ CallRuntime(Runtime::kNewFunctionContext, 1); 196 } 197 RecordSafepoint(Safepoint::kNoLazyDeopt); 198 // Context is returned in both rax and rsi. It replaces the context 199 // passed to us. It's saved in the stack and kept live in rsi. 200 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); 201 202 // Copy any necessary parameters into the context. 203 int num_parameters = scope()->num_parameters(); 204 for (int i = 0; i < num_parameters; i++) { 205 Variable* var = scope()->parameter(i); 206 if (var->IsContextSlot()) { 207 int parameter_offset = StandardFrameConstants::kCallerSPOffset + 208 (num_parameters - 1 - i) * kPointerSize; 209 // Load parameter from stack. 210 __ movq(rax, Operand(rbp, parameter_offset)); 211 // Store it in the context. 212 int context_offset = Context::SlotOffset(var->index()); 213 __ movq(Operand(rsi, context_offset), rax); 214 // Update the write barrier. This clobbers rax and rbx. 215 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); 216 } 217 } 218 Comment(";;; End allocate local context"); 219 } 220 221 // Trace the call. 222 if (FLAG_trace) { 223 __ CallRuntime(Runtime::kTraceEnter, 0); 224 } 225 return !is_aborted(); 226} 227 228 229bool LCodeGen::GenerateBody() { 230 ASSERT(is_generating()); 231 bool emit_instructions = true; 232 for (current_instruction_ = 0; 233 !is_aborted() && current_instruction_ < instructions_->length(); 234 current_instruction_++) { 235 LInstruction* instr = instructions_->at(current_instruction_); 236 if (instr->IsLabel()) { 237 LLabel* label = LLabel::cast(instr); 238 emit_instructions = !label->HasReplacement(); 239 } 240 241 if (emit_instructions) { 242 Comment(";;; @%d: %s.", current_instruction_, instr->Mnemonic()); 243 instr->CompileToNative(this); 244 } 245 } 246 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 247 return !is_aborted(); 248} 249 250 251bool LCodeGen::GenerateJumpTable() { 252 for (int i = 0; i < jump_table_.length(); i++) { 253 __ bind(&jump_table_[i].label); 254 __ Jump(jump_table_[i].address, RelocInfo::RUNTIME_ENTRY); 255 } 256 return !is_aborted(); 257} 258 259 260bool LCodeGen::GenerateDeferredCode() { 261 ASSERT(is_generating()); 262 if (deferred_.length() > 0) { 263 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { 264 LDeferredCode* code = deferred_[i]; 265 __ bind(code->entry()); 266 Comment(";;; Deferred code @%d: %s.", 267 code->instruction_index(), 268 code->instr()->Mnemonic()); 269 code->Generate(); 270 __ jmp(code->exit()); 271 } 272 } 273 274 // Deferred code is the last part of the instruction sequence. Mark 275 // the generated code as done unless we bailed out. 276 if (!is_aborted()) status_ = DONE; 277 return !is_aborted(); 278} 279 280 281bool LCodeGen::GenerateSafepointTable() { 282 ASSERT(is_done()); 283 safepoints_.Emit(masm(), GetStackSlotCount()); 284 return !is_aborted(); 285} 286 287 288Register LCodeGen::ToRegister(int index) const { 289 return Register::FromAllocationIndex(index); 290} 291 292 293XMMRegister LCodeGen::ToDoubleRegister(int index) const { 294 return XMMRegister::FromAllocationIndex(index); 295} 296 297 298Register LCodeGen::ToRegister(LOperand* op) const { 299 ASSERT(op->IsRegister()); 300 return ToRegister(op->index()); 301} 302 303 304XMMRegister LCodeGen::ToDoubleRegister(LOperand* op) const { 305 ASSERT(op->IsDoubleRegister()); 306 return ToDoubleRegister(op->index()); 307} 308 309 310bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const { 311 return op->IsConstantOperand() && 312 chunk_->LookupLiteralRepresentation(op).IsInteger32(); 313} 314 315 316bool LCodeGen::IsTaggedConstant(LConstantOperand* op) const { 317 return op->IsConstantOperand() && 318 chunk_->LookupLiteralRepresentation(op).IsTagged(); 319} 320 321 322int LCodeGen::ToInteger32(LConstantOperand* op) const { 323 Handle<Object> value = chunk_->LookupLiteral(op); 324 ASSERT(chunk_->LookupLiteralRepresentation(op).IsInteger32()); 325 ASSERT(static_cast<double>(static_cast<int32_t>(value->Number())) == 326 value->Number()); 327 return static_cast<int32_t>(value->Number()); 328} 329 330 331double LCodeGen::ToDouble(LConstantOperand* op) const { 332 Handle<Object> value = chunk_->LookupLiteral(op); 333 return value->Number(); 334} 335 336 337Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { 338 Handle<Object> literal = chunk_->LookupLiteral(op); 339 ASSERT(chunk_->LookupLiteralRepresentation(op).IsTagged()); 340 return literal; 341} 342 343 344Operand LCodeGen::ToOperand(LOperand* op) const { 345 // Does not handle registers. In X64 assembler, plain registers are not 346 // representable as an Operand. 347 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); 348 int index = op->index(); 349 if (index >= 0) { 350 // Local or spill slot. Skip the frame pointer, function, and 351 // context in the fixed part of the frame. 352 return Operand(rbp, -(index + 3) * kPointerSize); 353 } else { 354 // Incoming parameter. Skip the return address. 355 return Operand(rbp, -(index - 1) * kPointerSize); 356 } 357} 358 359 360void LCodeGen::WriteTranslation(LEnvironment* environment, 361 Translation* translation) { 362 if (environment == NULL) return; 363 364 // The translation includes one command per value in the environment. 365 int translation_size = environment->values()->length(); 366 // The output frame height does not include the parameters. 367 int height = translation_size - environment->parameter_count(); 368 369 WriteTranslation(environment->outer(), translation); 370 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 371 translation->BeginFrame(environment->ast_id(), closure_id, height); 372 for (int i = 0; i < translation_size; ++i) { 373 LOperand* value = environment->values()->at(i); 374 // spilled_registers_ and spilled_double_registers_ are either 375 // both NULL or both set. 376 if (environment->spilled_registers() != NULL && value != NULL) { 377 if (value->IsRegister() && 378 environment->spilled_registers()[value->index()] != NULL) { 379 translation->MarkDuplicate(); 380 AddToTranslation(translation, 381 environment->spilled_registers()[value->index()], 382 environment->HasTaggedValueAt(i)); 383 } else if ( 384 value->IsDoubleRegister() && 385 environment->spilled_double_registers()[value->index()] != NULL) { 386 translation->MarkDuplicate(); 387 AddToTranslation( 388 translation, 389 environment->spilled_double_registers()[value->index()], 390 false); 391 } 392 } 393 394 AddToTranslation(translation, value, environment->HasTaggedValueAt(i)); 395 } 396} 397 398 399void LCodeGen::AddToTranslation(Translation* translation, 400 LOperand* op, 401 bool is_tagged) { 402 if (op == NULL) { 403 // TODO(twuerthinger): Introduce marker operands to indicate that this value 404 // is not present and must be reconstructed from the deoptimizer. Currently 405 // this is only used for the arguments object. 406 translation->StoreArgumentsObject(); 407 } else if (op->IsStackSlot()) { 408 if (is_tagged) { 409 translation->StoreStackSlot(op->index()); 410 } else { 411 translation->StoreInt32StackSlot(op->index()); 412 } 413 } else if (op->IsDoubleStackSlot()) { 414 translation->StoreDoubleStackSlot(op->index()); 415 } else if (op->IsArgument()) { 416 ASSERT(is_tagged); 417 int src_index = GetStackSlotCount() + op->index(); 418 translation->StoreStackSlot(src_index); 419 } else if (op->IsRegister()) { 420 Register reg = ToRegister(op); 421 if (is_tagged) { 422 translation->StoreRegister(reg); 423 } else { 424 translation->StoreInt32Register(reg); 425 } 426 } else if (op->IsDoubleRegister()) { 427 XMMRegister reg = ToDoubleRegister(op); 428 translation->StoreDoubleRegister(reg); 429 } else if (op->IsConstantOperand()) { 430 Handle<Object> literal = chunk()->LookupLiteral(LConstantOperand::cast(op)); 431 int src_index = DefineDeoptimizationLiteral(literal); 432 translation->StoreLiteral(src_index); 433 } else { 434 UNREACHABLE(); 435 } 436} 437 438 439void LCodeGen::CallCodeGeneric(Handle<Code> code, 440 RelocInfo::Mode mode, 441 LInstruction* instr, 442 SafepointMode safepoint_mode, 443 int argc) { 444 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code)); 445 ASSERT(instr != NULL); 446 LPointerMap* pointers = instr->pointer_map(); 447 RecordPosition(pointers->position()); 448 __ call(code, mode); 449 RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc); 450 451 // Signal that we don't inline smi code before these stubs in the 452 // optimizing code generator. 453 if (code->kind() == Code::BINARY_OP_IC || 454 code->kind() == Code::COMPARE_IC) { 455 __ nop(); 456 } 457} 458 459 460void LCodeGen::CallCode(Handle<Code> code, 461 RelocInfo::Mode mode, 462 LInstruction* instr) { 463 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT, 0); 464} 465 466 467void LCodeGen::CallRuntime(const Runtime::Function* function, 468 int num_arguments, 469 LInstruction* instr) { 470 ASSERT(instr != NULL); 471 ASSERT(instr->HasPointerMap()); 472 LPointerMap* pointers = instr->pointer_map(); 473 RecordPosition(pointers->position()); 474 475 __ CallRuntime(function, num_arguments); 476 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); 477} 478 479 480void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, 481 int argc, 482 LInstruction* instr) { 483 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 484 __ CallRuntimeSaveDoubles(id); 485 RecordSafepointWithRegisters( 486 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); 487} 488 489 490void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, 491 Safepoint::DeoptMode mode) { 492 if (!environment->HasBeenRegistered()) { 493 // Physical stack frame layout: 494 // -x ............. -4 0 ..................................... y 495 // [incoming arguments] [spill slots] [pushed outgoing arguments] 496 497 // Layout of the environment: 498 // 0 ..................................................... size-1 499 // [parameters] [locals] [expression stack including arguments] 500 501 // Layout of the translation: 502 // 0 ........................................................ size - 1 + 4 503 // [expression stack including arguments] [locals] [4 words] [parameters] 504 // |>------------ translation_size ------------<| 505 506 int frame_count = 0; 507 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { 508 ++frame_count; 509 } 510 Translation translation(&translations_, frame_count); 511 WriteTranslation(environment, &translation); 512 int deoptimization_index = deoptimizations_.length(); 513 int pc_offset = masm()->pc_offset(); 514 environment->Register(deoptimization_index, 515 translation.index(), 516 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); 517 deoptimizations_.Add(environment); 518 } 519} 520 521 522void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) { 523 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 524 ASSERT(environment->HasBeenRegistered()); 525 int id = environment->deoptimization_index(); 526 Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER); 527 ASSERT(entry != NULL); 528 if (entry == NULL) { 529 Abort("bailout was not prepared"); 530 return; 531 } 532 533 if (cc == no_condition) { 534 __ Jump(entry, RelocInfo::RUNTIME_ENTRY); 535 } else { 536 // We often have several deopts to the same entry, reuse the last 537 // jump entry if this is the case. 538 if (jump_table_.is_empty() || 539 jump_table_.last().address != entry) { 540 jump_table_.Add(JumpTableEntry(entry)); 541 } 542 __ j(cc, &jump_table_.last().label); 543 } 544} 545 546 547void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { 548 int length = deoptimizations_.length(); 549 if (length == 0) return; 550 ASSERT(FLAG_deopt); 551 Handle<DeoptimizationInputData> data = 552 factory()->NewDeoptimizationInputData(length, TENURED); 553 554 Handle<ByteArray> translations = translations_.CreateByteArray(); 555 data->SetTranslationByteArray(*translations); 556 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); 557 558 Handle<FixedArray> literals = 559 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED); 560 for (int i = 0; i < deoptimization_literals_.length(); i++) { 561 literals->set(i, *deoptimization_literals_[i]); 562 } 563 data->SetLiteralArray(*literals); 564 565 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id())); 566 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); 567 568 // Populate the deoptimization entries. 569 for (int i = 0; i < length; i++) { 570 LEnvironment* env = deoptimizations_[i]; 571 data->SetAstId(i, Smi::FromInt(env->ast_id())); 572 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); 573 data->SetArgumentsStackHeight(i, 574 Smi::FromInt(env->arguments_stack_height())); 575 data->SetPc(i, Smi::FromInt(env->pc_offset())); 576 } 577 code->set_deoptimization_data(*data); 578} 579 580 581int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) { 582 int result = deoptimization_literals_.length(); 583 for (int i = 0; i < deoptimization_literals_.length(); ++i) { 584 if (deoptimization_literals_[i].is_identical_to(literal)) return i; 585 } 586 deoptimization_literals_.Add(literal); 587 return result; 588} 589 590 591void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { 592 ASSERT(deoptimization_literals_.length() == 0); 593 594 const ZoneList<Handle<JSFunction> >* inlined_closures = 595 chunk()->inlined_closures(); 596 597 for (int i = 0, length = inlined_closures->length(); 598 i < length; 599 i++) { 600 DefineDeoptimizationLiteral(inlined_closures->at(i)); 601 } 602 603 inlined_function_count_ = deoptimization_literals_.length(); 604} 605 606 607void LCodeGen::RecordSafepointWithLazyDeopt( 608 LInstruction* instr, SafepointMode safepoint_mode, int argc) { 609 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { 610 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); 611 } else { 612 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS); 613 RecordSafepointWithRegisters( 614 instr->pointer_map(), argc, Safepoint::kLazyDeopt); 615 } 616} 617 618 619void LCodeGen::RecordSafepoint( 620 LPointerMap* pointers, 621 Safepoint::Kind kind, 622 int arguments, 623 Safepoint::DeoptMode deopt_mode) { 624 ASSERT(kind == expected_safepoint_kind_); 625 626 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); 627 628 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), 629 kind, arguments, deopt_mode); 630 for (int i = 0; i < operands->length(); i++) { 631 LOperand* pointer = operands->at(i); 632 if (pointer->IsStackSlot()) { 633 safepoint.DefinePointerSlot(pointer->index()); 634 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { 635 safepoint.DefinePointerRegister(ToRegister(pointer)); 636 } 637 } 638 if (kind & Safepoint::kWithRegisters) { 639 // Register rsi always contains a pointer to the context. 640 safepoint.DefinePointerRegister(rsi); 641 } 642} 643 644 645void LCodeGen::RecordSafepoint(LPointerMap* pointers, 646 Safepoint::DeoptMode deopt_mode) { 647 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode); 648} 649 650 651void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { 652 LPointerMap empty_pointers(RelocInfo::kNoPosition); 653 RecordSafepoint(&empty_pointers, deopt_mode); 654} 655 656 657void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, 658 int arguments, 659 Safepoint::DeoptMode deopt_mode) { 660 RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode); 661} 662 663 664void LCodeGen::RecordPosition(int position) { 665 if (position == RelocInfo::kNoPosition) return; 666 masm()->positions_recorder()->RecordPosition(position); 667} 668 669 670void LCodeGen::DoLabel(LLabel* label) { 671 if (label->is_loop_header()) { 672 Comment(";;; B%d - LOOP entry", label->block_id()); 673 } else { 674 Comment(";;; B%d", label->block_id()); 675 } 676 __ bind(label->label()); 677 current_block_ = label->block_id(); 678 DoGap(label); 679} 680 681 682void LCodeGen::DoParallelMove(LParallelMove* move) { 683 resolver_.Resolve(move); 684} 685 686 687void LCodeGen::DoGap(LGap* gap) { 688 for (int i = LGap::FIRST_INNER_POSITION; 689 i <= LGap::LAST_INNER_POSITION; 690 i++) { 691 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); 692 LParallelMove* move = gap->GetParallelMove(inner_pos); 693 if (move != NULL) DoParallelMove(move); 694 } 695} 696 697 698void LCodeGen::DoInstructionGap(LInstructionGap* instr) { 699 DoGap(instr); 700} 701 702 703void LCodeGen::DoParameter(LParameter* instr) { 704 // Nothing to do. 705} 706 707 708void LCodeGen::DoCallStub(LCallStub* instr) { 709 ASSERT(ToRegister(instr->result()).is(rax)); 710 switch (instr->hydrogen()->major_key()) { 711 case CodeStub::RegExpConstructResult: { 712 RegExpConstructResultStub stub; 713 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 714 break; 715 } 716 case CodeStub::RegExpExec: { 717 RegExpExecStub stub; 718 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 719 break; 720 } 721 case CodeStub::SubString: { 722 SubStringStub stub; 723 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 724 break; 725 } 726 case CodeStub::NumberToString: { 727 NumberToStringStub stub; 728 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 729 break; 730 } 731 case CodeStub::StringAdd: { 732 StringAddStub stub(NO_STRING_ADD_FLAGS); 733 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 734 break; 735 } 736 case CodeStub::StringCompare: { 737 StringCompareStub stub; 738 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 739 break; 740 } 741 case CodeStub::TranscendentalCache: { 742 TranscendentalCacheStub stub(instr->transcendental_type(), 743 TranscendentalCacheStub::TAGGED); 744 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 745 break; 746 } 747 default: 748 UNREACHABLE(); 749 } 750} 751 752 753void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { 754 // Nothing to do. 755} 756 757 758void LCodeGen::DoModI(LModI* instr) { 759 if (instr->hydrogen()->HasPowerOf2Divisor()) { 760 Register dividend = ToRegister(instr->InputAt(0)); 761 762 int32_t divisor = 763 HConstant::cast(instr->hydrogen()->right())->Integer32Value(); 764 765 if (divisor < 0) divisor = -divisor; 766 767 Label positive_dividend, done; 768 __ testl(dividend, dividend); 769 __ j(not_sign, &positive_dividend, Label::kNear); 770 __ negl(dividend); 771 __ andl(dividend, Immediate(divisor - 1)); 772 __ negl(dividend); 773 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 774 __ j(not_zero, &done, Label::kNear); 775 DeoptimizeIf(no_condition, instr->environment()); 776 } else { 777 __ jmp(&done, Label::kNear); 778 } 779 __ bind(&positive_dividend); 780 __ andl(dividend, Immediate(divisor - 1)); 781 __ bind(&done); 782 } else { 783 Label done, remainder_eq_dividend, slow, do_subtraction, both_positive; 784 Register left_reg = ToRegister(instr->InputAt(0)); 785 Register right_reg = ToRegister(instr->InputAt(1)); 786 Register result_reg = ToRegister(instr->result()); 787 788 ASSERT(left_reg.is(rax)); 789 ASSERT(result_reg.is(rdx)); 790 ASSERT(!right_reg.is(rax)); 791 ASSERT(!right_reg.is(rdx)); 792 793 // Check for x % 0. 794 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { 795 __ testl(right_reg, right_reg); 796 DeoptimizeIf(zero, instr->environment()); 797 } 798 799 __ testl(left_reg, left_reg); 800 __ j(zero, &remainder_eq_dividend, Label::kNear); 801 __ j(sign, &slow, Label::kNear); 802 803 __ testl(right_reg, right_reg); 804 __ j(not_sign, &both_positive, Label::kNear); 805 // The sign of the divisor doesn't matter. 806 __ neg(right_reg); 807 808 __ bind(&both_positive); 809 // If the dividend is smaller than the nonnegative 810 // divisor, the dividend is the result. 811 __ cmpl(left_reg, right_reg); 812 __ j(less, &remainder_eq_dividend, Label::kNear); 813 814 // Check if the divisor is a PowerOfTwo integer. 815 Register scratch = ToRegister(instr->TempAt(0)); 816 __ movl(scratch, right_reg); 817 __ subl(scratch, Immediate(1)); 818 __ testl(scratch, right_reg); 819 __ j(not_zero, &do_subtraction, Label::kNear); 820 __ andl(left_reg, scratch); 821 __ jmp(&remainder_eq_dividend, Label::kNear); 822 823 __ bind(&do_subtraction); 824 const int kUnfolds = 3; 825 // Try a few subtractions of the dividend. 826 __ movl(scratch, left_reg); 827 for (int i = 0; i < kUnfolds; i++) { 828 // Reduce the dividend by the divisor. 829 __ subl(left_reg, right_reg); 830 // Check if the dividend is less than the divisor. 831 __ cmpl(left_reg, right_reg); 832 __ j(less, &remainder_eq_dividend, Label::kNear); 833 } 834 __ movl(left_reg, scratch); 835 836 // Slow case, using idiv instruction. 837 __ bind(&slow); 838 // Sign extend eax to edx. 839 // (We are using only the low 32 bits of the values.) 840 __ cdq(); 841 842 // Check for (0 % -x) that will produce negative zero. 843 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 844 Label positive_left; 845 Label done; 846 __ testl(left_reg, left_reg); 847 __ j(not_sign, &positive_left, Label::kNear); 848 __ idivl(right_reg); 849 850 // Test the remainder for 0, because then the result would be -0. 851 __ testl(result_reg, result_reg); 852 __ j(not_zero, &done, Label::kNear); 853 854 DeoptimizeIf(no_condition, instr->environment()); 855 __ bind(&positive_left); 856 __ idivl(right_reg); 857 __ bind(&done); 858 } else { 859 __ idivl(right_reg); 860 } 861 __ jmp(&done, Label::kNear); 862 863 __ bind(&remainder_eq_dividend); 864 __ movl(result_reg, left_reg); 865 866 __ bind(&done); 867 } 868} 869 870 871void LCodeGen::DoDivI(LDivI* instr) { 872 LOperand* right = instr->InputAt(1); 873 ASSERT(ToRegister(instr->result()).is(rax)); 874 ASSERT(ToRegister(instr->InputAt(0)).is(rax)); 875 ASSERT(!ToRegister(instr->InputAt(1)).is(rax)); 876 ASSERT(!ToRegister(instr->InputAt(1)).is(rdx)); 877 878 Register left_reg = rax; 879 880 // Check for x / 0. 881 Register right_reg = ToRegister(right); 882 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { 883 __ testl(right_reg, right_reg); 884 DeoptimizeIf(zero, instr->environment()); 885 } 886 887 // Check for (0 / -x) that will produce negative zero. 888 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 889 Label left_not_zero; 890 __ testl(left_reg, left_reg); 891 __ j(not_zero, &left_not_zero, Label::kNear); 892 __ testl(right_reg, right_reg); 893 DeoptimizeIf(sign, instr->environment()); 894 __ bind(&left_not_zero); 895 } 896 897 // Check for (-kMinInt / -1). 898 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 899 Label left_not_min_int; 900 __ cmpl(left_reg, Immediate(kMinInt)); 901 __ j(not_zero, &left_not_min_int, Label::kNear); 902 __ cmpl(right_reg, Immediate(-1)); 903 DeoptimizeIf(zero, instr->environment()); 904 __ bind(&left_not_min_int); 905 } 906 907 // Sign extend to rdx. 908 __ cdq(); 909 __ idivl(right_reg); 910 911 // Deoptimize if remainder is not 0. 912 __ testl(rdx, rdx); 913 DeoptimizeIf(not_zero, instr->environment()); 914} 915 916 917void LCodeGen::DoMulI(LMulI* instr) { 918 Register left = ToRegister(instr->InputAt(0)); 919 LOperand* right = instr->InputAt(1); 920 921 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 922 __ movl(kScratchRegister, left); 923 } 924 925 bool can_overflow = 926 instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 927 if (right->IsConstantOperand()) { 928 int right_value = ToInteger32(LConstantOperand::cast(right)); 929 if (right_value == -1) { 930 __ negl(left); 931 } else if (right_value == 0) { 932 __ xorl(left, left); 933 } else if (right_value == 2) { 934 __ addl(left, left); 935 } else if (!can_overflow) { 936 // If the multiplication is known to not overflow, we 937 // can use operations that don't set the overflow flag 938 // correctly. 939 switch (right_value) { 940 case 1: 941 // Do nothing. 942 break; 943 case 3: 944 __ leal(left, Operand(left, left, times_2, 0)); 945 break; 946 case 4: 947 __ shll(left, Immediate(2)); 948 break; 949 case 5: 950 __ leal(left, Operand(left, left, times_4, 0)); 951 break; 952 case 8: 953 __ shll(left, Immediate(3)); 954 break; 955 case 9: 956 __ leal(left, Operand(left, left, times_8, 0)); 957 break; 958 case 16: 959 __ shll(left, Immediate(4)); 960 break; 961 default: 962 __ imull(left, left, Immediate(right_value)); 963 break; 964 } 965 } else { 966 __ imull(left, left, Immediate(right_value)); 967 } 968 } else if (right->IsStackSlot()) { 969 __ imull(left, ToOperand(right)); 970 } else { 971 __ imull(left, ToRegister(right)); 972 } 973 974 if (can_overflow) { 975 DeoptimizeIf(overflow, instr->environment()); 976 } 977 978 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 979 // Bail out if the result is supposed to be negative zero. 980 Label done; 981 __ testl(left, left); 982 __ j(not_zero, &done, Label::kNear); 983 if (right->IsConstantOperand()) { 984 if (ToInteger32(LConstantOperand::cast(right)) <= 0) { 985 DeoptimizeIf(no_condition, instr->environment()); 986 } 987 } else if (right->IsStackSlot()) { 988 __ or_(kScratchRegister, ToOperand(right)); 989 DeoptimizeIf(sign, instr->environment()); 990 } else { 991 // Test the non-zero operand for negative sign. 992 __ or_(kScratchRegister, ToRegister(right)); 993 DeoptimizeIf(sign, instr->environment()); 994 } 995 __ bind(&done); 996 } 997} 998 999 1000void LCodeGen::DoBitI(LBitI* instr) { 1001 LOperand* left = instr->InputAt(0); 1002 LOperand* right = instr->InputAt(1); 1003 ASSERT(left->Equals(instr->result())); 1004 ASSERT(left->IsRegister()); 1005 1006 if (right->IsConstantOperand()) { 1007 int right_operand = ToInteger32(LConstantOperand::cast(right)); 1008 switch (instr->op()) { 1009 case Token::BIT_AND: 1010 __ andl(ToRegister(left), Immediate(right_operand)); 1011 break; 1012 case Token::BIT_OR: 1013 __ orl(ToRegister(left), Immediate(right_operand)); 1014 break; 1015 case Token::BIT_XOR: 1016 __ xorl(ToRegister(left), Immediate(right_operand)); 1017 break; 1018 default: 1019 UNREACHABLE(); 1020 break; 1021 } 1022 } else if (right->IsStackSlot()) { 1023 switch (instr->op()) { 1024 case Token::BIT_AND: 1025 __ andl(ToRegister(left), ToOperand(right)); 1026 break; 1027 case Token::BIT_OR: 1028 __ orl(ToRegister(left), ToOperand(right)); 1029 break; 1030 case Token::BIT_XOR: 1031 __ xorl(ToRegister(left), ToOperand(right)); 1032 break; 1033 default: 1034 UNREACHABLE(); 1035 break; 1036 } 1037 } else { 1038 ASSERT(right->IsRegister()); 1039 switch (instr->op()) { 1040 case Token::BIT_AND: 1041 __ andl(ToRegister(left), ToRegister(right)); 1042 break; 1043 case Token::BIT_OR: 1044 __ orl(ToRegister(left), ToRegister(right)); 1045 break; 1046 case Token::BIT_XOR: 1047 __ xorl(ToRegister(left), ToRegister(right)); 1048 break; 1049 default: 1050 UNREACHABLE(); 1051 break; 1052 } 1053 } 1054} 1055 1056 1057void LCodeGen::DoShiftI(LShiftI* instr) { 1058 LOperand* left = instr->InputAt(0); 1059 LOperand* right = instr->InputAt(1); 1060 ASSERT(left->Equals(instr->result())); 1061 ASSERT(left->IsRegister()); 1062 if (right->IsRegister()) { 1063 ASSERT(ToRegister(right).is(rcx)); 1064 1065 switch (instr->op()) { 1066 case Token::SAR: 1067 __ sarl_cl(ToRegister(left)); 1068 break; 1069 case Token::SHR: 1070 __ shrl_cl(ToRegister(left)); 1071 if (instr->can_deopt()) { 1072 __ testl(ToRegister(left), ToRegister(left)); 1073 DeoptimizeIf(negative, instr->environment()); 1074 } 1075 break; 1076 case Token::SHL: 1077 __ shll_cl(ToRegister(left)); 1078 break; 1079 default: 1080 UNREACHABLE(); 1081 break; 1082 } 1083 } else { 1084 int value = ToInteger32(LConstantOperand::cast(right)); 1085 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); 1086 switch (instr->op()) { 1087 case Token::SAR: 1088 if (shift_count != 0) { 1089 __ sarl(ToRegister(left), Immediate(shift_count)); 1090 } 1091 break; 1092 case Token::SHR: 1093 if (shift_count == 0 && instr->can_deopt()) { 1094 __ testl(ToRegister(left), ToRegister(left)); 1095 DeoptimizeIf(negative, instr->environment()); 1096 } else { 1097 __ shrl(ToRegister(left), Immediate(shift_count)); 1098 } 1099 break; 1100 case Token::SHL: 1101 if (shift_count != 0) { 1102 __ shll(ToRegister(left), Immediate(shift_count)); 1103 } 1104 break; 1105 default: 1106 UNREACHABLE(); 1107 break; 1108 } 1109 } 1110} 1111 1112 1113void LCodeGen::DoSubI(LSubI* instr) { 1114 LOperand* left = instr->InputAt(0); 1115 LOperand* right = instr->InputAt(1); 1116 ASSERT(left->Equals(instr->result())); 1117 1118 if (right->IsConstantOperand()) { 1119 __ subl(ToRegister(left), 1120 Immediate(ToInteger32(LConstantOperand::cast(right)))); 1121 } else if (right->IsRegister()) { 1122 __ subl(ToRegister(left), ToRegister(right)); 1123 } else { 1124 __ subl(ToRegister(left), ToOperand(right)); 1125 } 1126 1127 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1128 DeoptimizeIf(overflow, instr->environment()); 1129 } 1130} 1131 1132 1133void LCodeGen::DoConstantI(LConstantI* instr) { 1134 ASSERT(instr->result()->IsRegister()); 1135 __ Set(ToRegister(instr->result()), instr->value()); 1136} 1137 1138 1139void LCodeGen::DoConstantD(LConstantD* instr) { 1140 ASSERT(instr->result()->IsDoubleRegister()); 1141 XMMRegister res = ToDoubleRegister(instr->result()); 1142 double v = instr->value(); 1143 uint64_t int_val = BitCast<uint64_t, double>(v); 1144 // Use xor to produce +0.0 in a fast and compact way, but avoid to 1145 // do so if the constant is -0.0. 1146 if (int_val == 0) { 1147 __ xorps(res, res); 1148 } else { 1149 Register tmp = ToRegister(instr->TempAt(0)); 1150 __ Set(tmp, int_val); 1151 __ movq(res, tmp); 1152 } 1153} 1154 1155 1156void LCodeGen::DoConstantT(LConstantT* instr) { 1157 ASSERT(instr->result()->IsRegister()); 1158 __ Move(ToRegister(instr->result()), instr->value()); 1159} 1160 1161 1162void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) { 1163 Register result = ToRegister(instr->result()); 1164 Register array = ToRegister(instr->InputAt(0)); 1165 __ movq(result, FieldOperand(array, JSArray::kLengthOffset)); 1166} 1167 1168 1169void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) { 1170 Register result = ToRegister(instr->result()); 1171 Register array = ToRegister(instr->InputAt(0)); 1172 __ movq(result, FieldOperand(array, FixedArrayBase::kLengthOffset)); 1173} 1174 1175 1176void LCodeGen::DoElementsKind(LElementsKind* instr) { 1177 Register result = ToRegister(instr->result()); 1178 Register input = ToRegister(instr->InputAt(0)); 1179 1180 // Load map into |result|. 1181 __ movq(result, FieldOperand(input, HeapObject::kMapOffset)); 1182 // Load the map's "bit field 2" into |result|. We only need the first byte. 1183 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset)); 1184 // Retrieve elements_kind from bit field 2. 1185 __ and_(result, Immediate(Map::kElementsKindMask)); 1186 __ shr(result, Immediate(Map::kElementsKindShift)); 1187} 1188 1189 1190void LCodeGen::DoValueOf(LValueOf* instr) { 1191 Register input = ToRegister(instr->InputAt(0)); 1192 Register result = ToRegister(instr->result()); 1193 ASSERT(input.is(result)); 1194 Label done; 1195 // If the object is a smi return the object. 1196 __ JumpIfSmi(input, &done, Label::kNear); 1197 1198 // If the object is not a value type, return the object. 1199 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); 1200 __ j(not_equal, &done, Label::kNear); 1201 __ movq(result, FieldOperand(input, JSValue::kValueOffset)); 1202 1203 __ bind(&done); 1204} 1205 1206 1207void LCodeGen::DoBitNotI(LBitNotI* instr) { 1208 LOperand* input = instr->InputAt(0); 1209 ASSERT(input->Equals(instr->result())); 1210 __ not_(ToRegister(input)); 1211} 1212 1213 1214void LCodeGen::DoThrow(LThrow* instr) { 1215 __ push(ToRegister(instr->InputAt(0))); 1216 CallRuntime(Runtime::kThrow, 1, instr); 1217 1218 if (FLAG_debug_code) { 1219 Comment("Unreachable code."); 1220 __ int3(); 1221 } 1222} 1223 1224 1225void LCodeGen::DoAddI(LAddI* instr) { 1226 LOperand* left = instr->InputAt(0); 1227 LOperand* right = instr->InputAt(1); 1228 ASSERT(left->Equals(instr->result())); 1229 1230 if (right->IsConstantOperand()) { 1231 __ addl(ToRegister(left), 1232 Immediate(ToInteger32(LConstantOperand::cast(right)))); 1233 } else if (right->IsRegister()) { 1234 __ addl(ToRegister(left), ToRegister(right)); 1235 } else { 1236 __ addl(ToRegister(left), ToOperand(right)); 1237 } 1238 1239 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1240 DeoptimizeIf(overflow, instr->environment()); 1241 } 1242} 1243 1244 1245void LCodeGen::DoArithmeticD(LArithmeticD* instr) { 1246 XMMRegister left = ToDoubleRegister(instr->InputAt(0)); 1247 XMMRegister right = ToDoubleRegister(instr->InputAt(1)); 1248 XMMRegister result = ToDoubleRegister(instr->result()); 1249 // All operations except MOD are computed in-place. 1250 ASSERT(instr->op() == Token::MOD || left.is(result)); 1251 switch (instr->op()) { 1252 case Token::ADD: 1253 __ addsd(left, right); 1254 break; 1255 case Token::SUB: 1256 __ subsd(left, right); 1257 break; 1258 case Token::MUL: 1259 __ mulsd(left, right); 1260 break; 1261 case Token::DIV: 1262 __ divsd(left, right); 1263 break; 1264 case Token::MOD: 1265 __ PrepareCallCFunction(2); 1266 __ movaps(xmm0, left); 1267 ASSERT(right.is(xmm1)); 1268 __ CallCFunction( 1269 ExternalReference::double_fp_operation(Token::MOD, isolate()), 2); 1270 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 1271 __ movaps(result, xmm0); 1272 break; 1273 default: 1274 UNREACHABLE(); 1275 break; 1276 } 1277} 1278 1279 1280void LCodeGen::DoArithmeticT(LArithmeticT* instr) { 1281 ASSERT(ToRegister(instr->InputAt(0)).is(rdx)); 1282 ASSERT(ToRegister(instr->InputAt(1)).is(rax)); 1283 ASSERT(ToRegister(instr->result()).is(rax)); 1284 1285 BinaryOpStub stub(instr->op(), NO_OVERWRITE); 1286 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 1287 __ nop(); // Signals no inlined code. 1288} 1289 1290 1291int LCodeGen::GetNextEmittedBlock(int block) { 1292 for (int i = block + 1; i < graph()->blocks()->length(); ++i) { 1293 LLabel* label = chunk_->GetLabel(i); 1294 if (!label->HasReplacement()) return i; 1295 } 1296 return -1; 1297} 1298 1299 1300void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) { 1301 int next_block = GetNextEmittedBlock(current_block_); 1302 right_block = chunk_->LookupDestination(right_block); 1303 left_block = chunk_->LookupDestination(left_block); 1304 1305 if (right_block == left_block) { 1306 EmitGoto(left_block); 1307 } else if (left_block == next_block) { 1308 __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block)); 1309 } else if (right_block == next_block) { 1310 __ j(cc, chunk_->GetAssemblyLabel(left_block)); 1311 } else { 1312 __ j(cc, chunk_->GetAssemblyLabel(left_block)); 1313 if (cc != always) { 1314 __ jmp(chunk_->GetAssemblyLabel(right_block)); 1315 } 1316 } 1317} 1318 1319 1320void LCodeGen::DoBranch(LBranch* instr) { 1321 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1322 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1323 1324 Representation r = instr->hydrogen()->value()->representation(); 1325 if (r.IsInteger32()) { 1326 Register reg = ToRegister(instr->InputAt(0)); 1327 __ testl(reg, reg); 1328 EmitBranch(true_block, false_block, not_zero); 1329 } else if (r.IsDouble()) { 1330 XMMRegister reg = ToDoubleRegister(instr->InputAt(0)); 1331 __ xorps(xmm0, xmm0); 1332 __ ucomisd(reg, xmm0); 1333 EmitBranch(true_block, false_block, not_equal); 1334 } else { 1335 ASSERT(r.IsTagged()); 1336 Register reg = ToRegister(instr->InputAt(0)); 1337 HType type = instr->hydrogen()->value()->type(); 1338 if (type.IsBoolean()) { 1339 __ CompareRoot(reg, Heap::kTrueValueRootIndex); 1340 EmitBranch(true_block, false_block, equal); 1341 } else if (type.IsSmi()) { 1342 __ SmiCompare(reg, Smi::FromInt(0)); 1343 EmitBranch(true_block, false_block, not_equal); 1344 } else { 1345 Label* true_label = chunk_->GetAssemblyLabel(true_block); 1346 Label* false_label = chunk_->GetAssemblyLabel(false_block); 1347 1348 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); 1349 // Avoid deopts in the case where we've never executed this path before. 1350 if (expected.IsEmpty()) expected = ToBooleanStub::all_types(); 1351 1352 if (expected.Contains(ToBooleanStub::UNDEFINED)) { 1353 // undefined -> false. 1354 __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); 1355 __ j(equal, false_label); 1356 } 1357 if (expected.Contains(ToBooleanStub::BOOLEAN)) { 1358 // true -> true. 1359 __ CompareRoot(reg, Heap::kTrueValueRootIndex); 1360 __ j(equal, true_label); 1361 // false -> false. 1362 __ CompareRoot(reg, Heap::kFalseValueRootIndex); 1363 __ j(equal, false_label); 1364 } 1365 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { 1366 // 'null' -> false. 1367 __ CompareRoot(reg, Heap::kNullValueRootIndex); 1368 __ j(equal, false_label); 1369 } 1370 1371 if (expected.Contains(ToBooleanStub::SMI)) { 1372 // Smis: 0 -> false, all other -> true. 1373 __ Cmp(reg, Smi::FromInt(0)); 1374 __ j(equal, false_label); 1375 __ JumpIfSmi(reg, true_label); 1376 } else if (expected.NeedsMap()) { 1377 // If we need a map later and have a Smi -> deopt. 1378 __ testb(reg, Immediate(kSmiTagMask)); 1379 DeoptimizeIf(zero, instr->environment()); 1380 } 1381 1382 const Register map = kScratchRegister; 1383 if (expected.NeedsMap()) { 1384 __ movq(map, FieldOperand(reg, HeapObject::kMapOffset)); 1385 1386 if (expected.CanBeUndetectable()) { 1387 // Undetectable -> false. 1388 __ testb(FieldOperand(map, Map::kBitFieldOffset), 1389 Immediate(1 << Map::kIsUndetectable)); 1390 __ j(not_zero, false_label); 1391 } 1392 } 1393 1394 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { 1395 // spec object -> true. 1396 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); 1397 __ j(above_equal, true_label); 1398 } 1399 1400 if (expected.Contains(ToBooleanStub::STRING)) { 1401 // String value -> false iff empty. 1402 Label not_string; 1403 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 1404 __ j(above_equal, ¬_string, Label::kNear); 1405 __ cmpq(FieldOperand(reg, String::kLengthOffset), Immediate(0)); 1406 __ j(not_zero, true_label); 1407 __ jmp(false_label); 1408 __ bind(¬_string); 1409 } 1410 1411 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { 1412 // heap number -> false iff +0, -0, or NaN. 1413 Label not_heap_number; 1414 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); 1415 __ j(not_equal, ¬_heap_number, Label::kNear); 1416 __ xorps(xmm0, xmm0); 1417 __ ucomisd(xmm0, FieldOperand(reg, HeapNumber::kValueOffset)); 1418 __ j(zero, false_label); 1419 __ jmp(true_label); 1420 __ bind(¬_heap_number); 1421 } 1422 1423 // We've seen something for the first time -> deopt. 1424 DeoptimizeIf(no_condition, instr->environment()); 1425 } 1426 } 1427} 1428 1429 1430void LCodeGen::EmitGoto(int block) { 1431 block = chunk_->LookupDestination(block); 1432 int next_block = GetNextEmittedBlock(current_block_); 1433 if (block != next_block) { 1434 __ jmp(chunk_->GetAssemblyLabel(block)); 1435 } 1436} 1437 1438 1439void LCodeGen::DoGoto(LGoto* instr) { 1440 EmitGoto(instr->block_id()); 1441} 1442 1443 1444inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { 1445 Condition cond = no_condition; 1446 switch (op) { 1447 case Token::EQ: 1448 case Token::EQ_STRICT: 1449 cond = equal; 1450 break; 1451 case Token::LT: 1452 cond = is_unsigned ? below : less; 1453 break; 1454 case Token::GT: 1455 cond = is_unsigned ? above : greater; 1456 break; 1457 case Token::LTE: 1458 cond = is_unsigned ? below_equal : less_equal; 1459 break; 1460 case Token::GTE: 1461 cond = is_unsigned ? above_equal : greater_equal; 1462 break; 1463 case Token::IN: 1464 case Token::INSTANCEOF: 1465 default: 1466 UNREACHABLE(); 1467 } 1468 return cond; 1469} 1470 1471 1472void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { 1473 LOperand* left = instr->InputAt(0); 1474 LOperand* right = instr->InputAt(1); 1475 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1476 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1477 Condition cc = TokenToCondition(instr->op(), instr->is_double()); 1478 1479 if (left->IsConstantOperand() && right->IsConstantOperand()) { 1480 // We can statically evaluate the comparison. 1481 double left_val = ToDouble(LConstantOperand::cast(left)); 1482 double right_val = ToDouble(LConstantOperand::cast(right)); 1483 int next_block = 1484 EvalComparison(instr->op(), left_val, right_val) ? true_block 1485 : false_block; 1486 EmitGoto(next_block); 1487 } else { 1488 if (instr->is_double()) { 1489 // Don't base result on EFLAGS when a NaN is involved. Instead 1490 // jump to the false block. 1491 __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); 1492 __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); 1493 } else { 1494 int32_t value; 1495 if (right->IsConstantOperand()) { 1496 value = ToInteger32(LConstantOperand::cast(right)); 1497 __ cmpl(ToRegister(left), Immediate(value)); 1498 } else if (left->IsConstantOperand()) { 1499 value = ToInteger32(LConstantOperand::cast(left)); 1500 if (right->IsRegister()) { 1501 __ cmpl(ToRegister(right), Immediate(value)); 1502 } else { 1503 __ cmpl(ToOperand(right), Immediate(value)); 1504 } 1505 // We transposed the operands. Reverse the condition. 1506 cc = ReverseCondition(cc); 1507 } else { 1508 if (right->IsRegister()) { 1509 __ cmpl(ToRegister(left), ToRegister(right)); 1510 } else { 1511 __ cmpl(ToRegister(left), ToOperand(right)); 1512 } 1513 } 1514 } 1515 EmitBranch(true_block, false_block, cc); 1516 } 1517} 1518 1519 1520void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { 1521 Register left = ToRegister(instr->InputAt(0)); 1522 Register right = ToRegister(instr->InputAt(1)); 1523 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1524 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1525 1526 __ cmpq(left, right); 1527 EmitBranch(true_block, false_block, equal); 1528} 1529 1530 1531void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) { 1532 Register left = ToRegister(instr->InputAt(0)); 1533 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1534 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1535 1536 __ cmpq(left, Immediate(instr->hydrogen()->right())); 1537 EmitBranch(true_block, false_block, equal); 1538} 1539 1540 1541void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { 1542 Register reg = ToRegister(instr->InputAt(0)); 1543 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1544 1545 // If the expression is known to be untagged or a smi, then it's definitely 1546 // not null, and it can't be a an undetectable object. 1547 if (instr->hydrogen()->representation().IsSpecialization() || 1548 instr->hydrogen()->type().IsSmi()) { 1549 EmitGoto(false_block); 1550 return; 1551 } 1552 1553 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1554 Heap::RootListIndex nil_value = instr->nil() == kNullValue ? 1555 Heap::kNullValueRootIndex : 1556 Heap::kUndefinedValueRootIndex; 1557 __ CompareRoot(reg, nil_value); 1558 if (instr->kind() == kStrictEquality) { 1559 EmitBranch(true_block, false_block, equal); 1560 } else { 1561 Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ? 1562 Heap::kUndefinedValueRootIndex : 1563 Heap::kNullValueRootIndex; 1564 Label* true_label = chunk_->GetAssemblyLabel(true_block); 1565 Label* false_label = chunk_->GetAssemblyLabel(false_block); 1566 __ j(equal, true_label); 1567 __ CompareRoot(reg, other_nil_value); 1568 __ j(equal, true_label); 1569 __ JumpIfSmi(reg, false_label); 1570 // Check for undetectable objects by looking in the bit field in 1571 // the map. The object has already been smi checked. 1572 Register scratch = ToRegister(instr->TempAt(0)); 1573 __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); 1574 __ testb(FieldOperand(scratch, Map::kBitFieldOffset), 1575 Immediate(1 << Map::kIsUndetectable)); 1576 EmitBranch(true_block, false_block, not_zero); 1577 } 1578} 1579 1580 1581Condition LCodeGen::EmitIsObject(Register input, 1582 Label* is_not_object, 1583 Label* is_object) { 1584 ASSERT(!input.is(kScratchRegister)); 1585 1586 __ JumpIfSmi(input, is_not_object); 1587 1588 __ CompareRoot(input, Heap::kNullValueRootIndex); 1589 __ j(equal, is_object); 1590 1591 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); 1592 // Undetectable objects behave like undefined. 1593 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), 1594 Immediate(1 << Map::kIsUndetectable)); 1595 __ j(not_zero, is_not_object); 1596 1597 __ movzxbl(kScratchRegister, 1598 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); 1599 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 1600 __ j(below, is_not_object); 1601 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); 1602 return below_equal; 1603} 1604 1605 1606void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { 1607 Register reg = ToRegister(instr->InputAt(0)); 1608 1609 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1610 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1611 Label* true_label = chunk_->GetAssemblyLabel(true_block); 1612 Label* false_label = chunk_->GetAssemblyLabel(false_block); 1613 1614 Condition true_cond = EmitIsObject(reg, false_label, true_label); 1615 1616 EmitBranch(true_block, false_block, true_cond); 1617} 1618 1619 1620Condition LCodeGen::EmitIsString(Register input, 1621 Register temp1, 1622 Label* is_not_string) { 1623 __ JumpIfSmi(input, is_not_string); 1624 Condition cond = masm_->IsObjectStringType(input, temp1, temp1); 1625 1626 return cond; 1627} 1628 1629 1630void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { 1631 Register reg = ToRegister(instr->InputAt(0)); 1632 Register temp = ToRegister(instr->TempAt(0)); 1633 1634 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1635 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1636 Label* false_label = chunk_->GetAssemblyLabel(false_block); 1637 1638 Condition true_cond = EmitIsString(reg, temp, false_label); 1639 1640 EmitBranch(true_block, false_block, true_cond); 1641} 1642 1643 1644void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { 1645 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1646 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1647 1648 Condition is_smi; 1649 if (instr->InputAt(0)->IsRegister()) { 1650 Register input = ToRegister(instr->InputAt(0)); 1651 is_smi = masm()->CheckSmi(input); 1652 } else { 1653 Operand input = ToOperand(instr->InputAt(0)); 1654 is_smi = masm()->CheckSmi(input); 1655 } 1656 EmitBranch(true_block, false_block, is_smi); 1657} 1658 1659 1660void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { 1661 Register input = ToRegister(instr->InputAt(0)); 1662 Register temp = ToRegister(instr->TempAt(0)); 1663 1664 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1665 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1666 1667 __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block)); 1668 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); 1669 __ testb(FieldOperand(temp, Map::kBitFieldOffset), 1670 Immediate(1 << Map::kIsUndetectable)); 1671 EmitBranch(true_block, false_block, not_zero); 1672} 1673 1674 1675void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { 1676 Token::Value op = instr->op(); 1677 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1678 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1679 1680 Handle<Code> ic = CompareIC::GetUninitialized(op); 1681 CallCode(ic, RelocInfo::CODE_TARGET, instr); 1682 1683 Condition condition = TokenToCondition(op, false); 1684 __ testq(rax, rax); 1685 1686 EmitBranch(true_block, false_block, condition); 1687} 1688 1689 1690static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { 1691 InstanceType from = instr->from(); 1692 InstanceType to = instr->to(); 1693 if (from == FIRST_TYPE) return to; 1694 ASSERT(from == to || to == LAST_TYPE); 1695 return from; 1696} 1697 1698 1699static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { 1700 InstanceType from = instr->from(); 1701 InstanceType to = instr->to(); 1702 if (from == to) return equal; 1703 if (to == LAST_TYPE) return above_equal; 1704 if (from == FIRST_TYPE) return below_equal; 1705 UNREACHABLE(); 1706 return equal; 1707} 1708 1709 1710void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { 1711 Register input = ToRegister(instr->InputAt(0)); 1712 1713 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1714 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1715 1716 Label* false_label = chunk_->GetAssemblyLabel(false_block); 1717 1718 __ JumpIfSmi(input, false_label); 1719 1720 __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister); 1721 EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen())); 1722} 1723 1724 1725void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { 1726 Register input = ToRegister(instr->InputAt(0)); 1727 Register result = ToRegister(instr->result()); 1728 1729 if (FLAG_debug_code) { 1730 __ AbortIfNotString(input); 1731 } 1732 1733 __ movl(result, FieldOperand(input, String::kHashFieldOffset)); 1734 ASSERT(String::kHashShift >= kSmiTagSize); 1735 __ IndexFromHash(result, result); 1736} 1737 1738 1739void LCodeGen::DoHasCachedArrayIndexAndBranch( 1740 LHasCachedArrayIndexAndBranch* instr) { 1741 Register input = ToRegister(instr->InputAt(0)); 1742 1743 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1744 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1745 1746 __ testl(FieldOperand(input, String::kHashFieldOffset), 1747 Immediate(String::kContainsCachedArrayIndexMask)); 1748 EmitBranch(true_block, false_block, equal); 1749} 1750 1751 1752// Branches to a label or falls through with the answer in the z flag. 1753// Trashes the temp register and possibly input (if it and temp are aliased). 1754void LCodeGen::EmitClassOfTest(Label* is_true, 1755 Label* is_false, 1756 Handle<String> class_name, 1757 Register input, 1758 Register temp, 1759 Register scratch) { 1760 __ JumpIfSmi(input, is_false); 1761 1762 if (class_name->IsEqualTo(CStrVector("Function"))) { 1763 // Assuming the following assertions, we can use the same compares to test 1764 // for both being a function type and being in the object type range. 1765 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); 1766 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == 1767 FIRST_SPEC_OBJECT_TYPE + 1); 1768 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == 1769 LAST_SPEC_OBJECT_TYPE - 1); 1770 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 1771 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); 1772 __ j(below, is_false); 1773 __ j(equal, is_true); 1774 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE); 1775 __ j(equal, is_true); 1776 } else { 1777 // Faster code path to avoid two compares: subtract lower bound from the 1778 // actual type and do a signed compare with the width of the type range. 1779 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); 1780 __ movzxbl(scratch, FieldOperand(temp, Map::kInstanceTypeOffset)); 1781 __ subq(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 1782 __ cmpq(scratch, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - 1783 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 1784 __ j(above, is_false); 1785 } 1786 1787 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. 1788 // Check if the constructor in the map is a function. 1789 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); 1790 1791 // Objects with a non-function constructor have class 'Object'. 1792 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); 1793 if (class_name->IsEqualTo(CStrVector("Object"))) { 1794 __ j(not_equal, is_true); 1795 } else { 1796 __ j(not_equal, is_false); 1797 } 1798 1799 // temp now contains the constructor function. Grab the 1800 // instance class name from there. 1801 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); 1802 __ movq(temp, FieldOperand(temp, 1803 SharedFunctionInfo::kInstanceClassNameOffset)); 1804 // The class name we are testing against is a symbol because it's a literal. 1805 // The name in the constructor is a symbol because of the way the context is 1806 // booted. This routine isn't expected to work for random API-created 1807 // classes and it doesn't have to because you can't access it with natives 1808 // syntax. Since both sides are symbols it is sufficient to use an identity 1809 // comparison. 1810 ASSERT(class_name->IsSymbol()); 1811 __ Cmp(temp, class_name); 1812 // End with the answer in the z flag. 1813} 1814 1815 1816void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { 1817 Register input = ToRegister(instr->InputAt(0)); 1818 Register temp = ToRegister(instr->TempAt(0)); 1819 Register temp2 = ToRegister(instr->TempAt(1)); 1820 Handle<String> class_name = instr->hydrogen()->class_name(); 1821 1822 int true_block = chunk_->LookupDestination(instr->true_block_id()); 1823 int false_block = chunk_->LookupDestination(instr->false_block_id()); 1824 1825 Label* true_label = chunk_->GetAssemblyLabel(true_block); 1826 Label* false_label = chunk_->GetAssemblyLabel(false_block); 1827 1828 EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); 1829 1830 EmitBranch(true_block, false_block, equal); 1831} 1832 1833 1834void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { 1835 Register reg = ToRegister(instr->InputAt(0)); 1836 int true_block = instr->true_block_id(); 1837 int false_block = instr->false_block_id(); 1838 1839 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); 1840 EmitBranch(true_block, false_block, equal); 1841} 1842 1843 1844void LCodeGen::DoInstanceOf(LInstanceOf* instr) { 1845 InstanceofStub stub(InstanceofStub::kNoFlags); 1846 __ push(ToRegister(instr->InputAt(0))); 1847 __ push(ToRegister(instr->InputAt(1))); 1848 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 1849 Label true_value, done; 1850 __ testq(rax, rax); 1851 __ j(zero, &true_value, Label::kNear); 1852 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); 1853 __ jmp(&done, Label::kNear); 1854 __ bind(&true_value); 1855 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); 1856 __ bind(&done); 1857} 1858 1859 1860void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { 1861 class DeferredInstanceOfKnownGlobal: public LDeferredCode { 1862 public: 1863 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, 1864 LInstanceOfKnownGlobal* instr) 1865 : LDeferredCode(codegen), instr_(instr) { } 1866 virtual void Generate() { 1867 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); 1868 } 1869 virtual LInstruction* instr() { return instr_; } 1870 Label* map_check() { return &map_check_; } 1871 private: 1872 LInstanceOfKnownGlobal* instr_; 1873 Label map_check_; 1874 }; 1875 1876 1877 DeferredInstanceOfKnownGlobal* deferred; 1878 deferred = new DeferredInstanceOfKnownGlobal(this, instr); 1879 1880 Label done, false_result; 1881 Register object = ToRegister(instr->InputAt(0)); 1882 1883 // A Smi is not an instance of anything. 1884 __ JumpIfSmi(object, &false_result); 1885 1886 // This is the inlined call site instanceof cache. The two occurences of the 1887 // hole value will be patched to the last map/result pair generated by the 1888 // instanceof stub. 1889 Label cache_miss; 1890 // Use a temp register to avoid memory operands with variable lengths. 1891 Register map = ToRegister(instr->TempAt(0)); 1892 __ movq(map, FieldOperand(object, HeapObject::kMapOffset)); 1893 __ bind(deferred->map_check()); // Label for calculating code patching. 1894 Handle<JSGlobalPropertyCell> cache_cell = 1895 factory()->NewJSGlobalPropertyCell(factory()->the_hole_value()); 1896 __ movq(kScratchRegister, cache_cell, RelocInfo::GLOBAL_PROPERTY_CELL); 1897 __ cmpq(map, Operand(kScratchRegister, 0)); 1898 __ j(not_equal, &cache_miss, Label::kNear); 1899 // Patched to load either true or false. 1900 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); 1901#ifdef DEBUG 1902 // Check that the code size between patch label and patch sites is invariant. 1903 Label end_of_patched_code; 1904 __ bind(&end_of_patched_code); 1905 ASSERT(true); 1906#endif 1907 __ jmp(&done); 1908 1909 // The inlined call site cache did not match. Check for null and string 1910 // before calling the deferred code. 1911 __ bind(&cache_miss); // Null is not an instance of anything. 1912 __ CompareRoot(object, Heap::kNullValueRootIndex); 1913 __ j(equal, &false_result, Label::kNear); 1914 1915 // String values are not instances of anything. 1916 __ JumpIfNotString(object, kScratchRegister, deferred->entry()); 1917 1918 __ bind(&false_result); 1919 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); 1920 1921 __ bind(deferred->exit()); 1922 __ bind(&done); 1923} 1924 1925 1926void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 1927 Label* map_check) { 1928 { 1929 PushSafepointRegistersScope scope(this); 1930 InstanceofStub::Flags flags = static_cast<InstanceofStub::Flags>( 1931 InstanceofStub::kNoFlags | InstanceofStub::kCallSiteInlineCheck); 1932 InstanceofStub stub(flags); 1933 1934 __ push(ToRegister(instr->InputAt(0))); 1935 __ Push(instr->function()); 1936 1937 static const int kAdditionalDelta = 10; 1938 int delta = 1939 masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta; 1940 ASSERT(delta >= 0); 1941 __ push_imm32(delta); 1942 1943 // We are pushing three values on the stack but recording a 1944 // safepoint with two arguments because stub is going to 1945 // remove the third argument from the stack before jumping 1946 // to instanceof builtin on the slow path. 1947 CallCodeGeneric(stub.GetCode(), 1948 RelocInfo::CODE_TARGET, 1949 instr, 1950 RECORD_SAFEPOINT_WITH_REGISTERS, 1951 2); 1952 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); 1953 ASSERT(instr->HasDeoptimizationEnvironment()); 1954 LEnvironment* env = instr->deoptimization_environment(); 1955 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 1956 // Move result to a register that survives the end of the 1957 // PushSafepointRegisterScope. 1958 __ movq(kScratchRegister, rax); 1959 } 1960 __ testq(kScratchRegister, kScratchRegister); 1961 Label load_false; 1962 Label done; 1963 __ j(not_zero, &load_false); 1964 __ LoadRoot(rax, Heap::kTrueValueRootIndex); 1965 __ jmp(&done); 1966 __ bind(&load_false); 1967 __ LoadRoot(rax, Heap::kFalseValueRootIndex); 1968 __ bind(&done); 1969} 1970 1971 1972void LCodeGen::DoCmpT(LCmpT* instr) { 1973 Token::Value op = instr->op(); 1974 1975 Handle<Code> ic = CompareIC::GetUninitialized(op); 1976 CallCode(ic, RelocInfo::CODE_TARGET, instr); 1977 1978 Condition condition = TokenToCondition(op, false); 1979 Label true_value, done; 1980 __ testq(rax, rax); 1981 __ j(condition, &true_value, Label::kNear); 1982 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); 1983 __ jmp(&done, Label::kNear); 1984 __ bind(&true_value); 1985 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); 1986 __ bind(&done); 1987} 1988 1989 1990void LCodeGen::DoReturn(LReturn* instr) { 1991 if (FLAG_trace) { 1992 // Preserve the return value on the stack and rely on the runtime 1993 // call to return the value in the same register. 1994 __ push(rax); 1995 __ CallRuntime(Runtime::kTraceExit, 1); 1996 } 1997 __ movq(rsp, rbp); 1998 __ pop(rbp); 1999 __ Ret((GetParameterCount() + 1) * kPointerSize, rcx); 2000} 2001 2002 2003void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { 2004 Register result = ToRegister(instr->result()); 2005 if (result.is(rax)) { 2006 __ load_rax(instr->hydrogen()->cell().location(), 2007 RelocInfo::GLOBAL_PROPERTY_CELL); 2008 } else { 2009 __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); 2010 __ movq(result, Operand(result, 0)); 2011 } 2012 if (instr->hydrogen()->RequiresHoleCheck()) { 2013 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); 2014 DeoptimizeIf(equal, instr->environment()); 2015 } 2016} 2017 2018 2019void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { 2020 ASSERT(ToRegister(instr->global_object()).is(rax)); 2021 ASSERT(ToRegister(instr->result()).is(rax)); 2022 2023 __ Move(rcx, instr->name()); 2024 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET : 2025 RelocInfo::CODE_TARGET_CONTEXT; 2026 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 2027 CallCode(ic, mode, instr); 2028} 2029 2030 2031void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { 2032 Register object = ToRegister(instr->TempAt(0)); 2033 Register address = ToRegister(instr->TempAt(1)); 2034 Register value = ToRegister(instr->InputAt(0)); 2035 ASSERT(!value.is(object)); 2036 Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell()); 2037 2038 __ movq(address, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL); 2039 2040 // If the cell we are storing to contains the hole it could have 2041 // been deleted from the property dictionary. In that case, we need 2042 // to update the property details in the property dictionary to mark 2043 // it as no longer deleted. We deoptimize in that case. 2044 if (instr->hydrogen()->RequiresHoleCheck()) { 2045 __ CompareRoot(Operand(address, 0), Heap::kTheHoleValueRootIndex); 2046 DeoptimizeIf(equal, instr->environment()); 2047 } 2048 2049 // Store the value. 2050 __ movq(Operand(address, 0), value); 2051 // Cells are always rescanned, so no write barrier here. 2052} 2053 2054 2055void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { 2056 ASSERT(ToRegister(instr->global_object()).is(rdx)); 2057 ASSERT(ToRegister(instr->value()).is(rax)); 2058 2059 __ Move(rcx, instr->name()); 2060 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) 2061 ? isolate()->builtins()->StoreIC_Initialize_Strict() 2062 : isolate()->builtins()->StoreIC_Initialize(); 2063 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); 2064} 2065 2066 2067void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { 2068 Register context = ToRegister(instr->context()); 2069 Register result = ToRegister(instr->result()); 2070 __ movq(result, ContextOperand(context, instr->slot_index())); 2071} 2072 2073 2074void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { 2075 Register context = ToRegister(instr->context()); 2076 Register value = ToRegister(instr->value()); 2077 __ movq(ContextOperand(context, instr->slot_index()), value); 2078 if (instr->hydrogen()->NeedsWriteBarrier()) { 2079 HType type = instr->hydrogen()->value()->type(); 2080 SmiCheck check_needed = 2081 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 2082 int offset = Context::SlotOffset(instr->slot_index()); 2083 Register scratch = ToRegister(instr->TempAt(0)); 2084 __ RecordWriteContextSlot(context, 2085 offset, 2086 value, 2087 scratch, 2088 kSaveFPRegs, 2089 EMIT_REMEMBERED_SET, 2090 check_needed); 2091 } 2092} 2093 2094 2095void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { 2096 Register object = ToRegister(instr->InputAt(0)); 2097 Register result = ToRegister(instr->result()); 2098 if (instr->hydrogen()->is_in_object()) { 2099 __ movq(result, FieldOperand(object, instr->hydrogen()->offset())); 2100 } else { 2101 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); 2102 __ movq(result, FieldOperand(result, instr->hydrogen()->offset())); 2103 } 2104} 2105 2106 2107void LCodeGen::EmitLoadFieldOrConstantFunction(Register result, 2108 Register object, 2109 Handle<Map> type, 2110 Handle<String> name) { 2111 LookupResult lookup(isolate()); 2112 type->LookupInDescriptors(NULL, *name, &lookup); 2113 ASSERT(lookup.IsProperty() && 2114 (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); 2115 if (lookup.type() == FIELD) { 2116 int index = lookup.GetLocalFieldIndexFromMap(*type); 2117 int offset = index * kPointerSize; 2118 if (index < 0) { 2119 // Negative property indices are in-object properties, indexed 2120 // from the end of the fixed part of the object. 2121 __ movq(result, FieldOperand(object, offset + type->instance_size())); 2122 } else { 2123 // Non-negative property indices are in the properties array. 2124 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); 2125 __ movq(result, FieldOperand(result, offset + FixedArray::kHeaderSize)); 2126 } 2127 } else { 2128 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type)); 2129 LoadHeapObject(result, Handle<HeapObject>::cast(function)); 2130 } 2131} 2132 2133 2134void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) { 2135 Register object = ToRegister(instr->object()); 2136 Register result = ToRegister(instr->result()); 2137 2138 int map_count = instr->hydrogen()->types()->length(); 2139 Handle<String> name = instr->hydrogen()->name(); 2140 2141 if (map_count == 0) { 2142 ASSERT(instr->hydrogen()->need_generic()); 2143 __ Move(rcx, instr->hydrogen()->name()); 2144 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 2145 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2146 } else { 2147 Label done; 2148 for (int i = 0; i < map_count - 1; ++i) { 2149 Handle<Map> map = instr->hydrogen()->types()->at(i); 2150 Label next; 2151 __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map); 2152 __ j(not_equal, &next, Label::kNear); 2153 EmitLoadFieldOrConstantFunction(result, object, map, name); 2154 __ jmp(&done, Label::kNear); 2155 __ bind(&next); 2156 } 2157 Handle<Map> map = instr->hydrogen()->types()->last(); 2158 __ Cmp(FieldOperand(object, HeapObject::kMapOffset), map); 2159 if (instr->hydrogen()->need_generic()) { 2160 Label generic; 2161 __ j(not_equal, &generic, Label::kNear); 2162 EmitLoadFieldOrConstantFunction(result, object, map, name); 2163 __ jmp(&done, Label::kNear); 2164 __ bind(&generic); 2165 __ Move(rcx, instr->hydrogen()->name()); 2166 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 2167 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2168 } else { 2169 DeoptimizeIf(not_equal, instr->environment()); 2170 EmitLoadFieldOrConstantFunction(result, object, map, name); 2171 } 2172 __ bind(&done); 2173 } 2174} 2175 2176 2177void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { 2178 ASSERT(ToRegister(instr->object()).is(rax)); 2179 ASSERT(ToRegister(instr->result()).is(rax)); 2180 2181 __ Move(rcx, instr->name()); 2182 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 2183 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2184} 2185 2186 2187void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { 2188 Register function = ToRegister(instr->function()); 2189 Register result = ToRegister(instr->result()); 2190 2191 // Check that the function really is a function. 2192 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); 2193 DeoptimizeIf(not_equal, instr->environment()); 2194 2195 // Check whether the function has an instance prototype. 2196 Label non_instance; 2197 __ testb(FieldOperand(result, Map::kBitFieldOffset), 2198 Immediate(1 << Map::kHasNonInstancePrototype)); 2199 __ j(not_zero, &non_instance, Label::kNear); 2200 2201 // Get the prototype or initial map from the function. 2202 __ movq(result, 2203 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2204 2205 // Check that the function has a prototype or an initial map. 2206 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); 2207 DeoptimizeIf(equal, instr->environment()); 2208 2209 // If the function does not have an initial map, we're done. 2210 Label done; 2211 __ CmpObjectType(result, MAP_TYPE, kScratchRegister); 2212 __ j(not_equal, &done, Label::kNear); 2213 2214 // Get the prototype from the initial map. 2215 __ movq(result, FieldOperand(result, Map::kPrototypeOffset)); 2216 __ jmp(&done, Label::kNear); 2217 2218 // Non-instance prototype: Fetch prototype from constructor field 2219 // in the function's map. 2220 __ bind(&non_instance); 2221 __ movq(result, FieldOperand(result, Map::kConstructorOffset)); 2222 2223 // All done. 2224 __ bind(&done); 2225} 2226 2227 2228void LCodeGen::DoLoadElements(LLoadElements* instr) { 2229 Register result = ToRegister(instr->result()); 2230 Register input = ToRegister(instr->InputAt(0)); 2231 __ movq(result, FieldOperand(input, JSObject::kElementsOffset)); 2232 if (FLAG_debug_code) { 2233 Label done, ok, fail; 2234 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), 2235 Heap::kFixedArrayMapRootIndex); 2236 __ j(equal, &done, Label::kNear); 2237 __ CompareRoot(FieldOperand(result, HeapObject::kMapOffset), 2238 Heap::kFixedCOWArrayMapRootIndex); 2239 __ j(equal, &done, Label::kNear); 2240 Register temp((result.is(rax)) ? rbx : rax); 2241 __ push(temp); 2242 __ movq(temp, FieldOperand(result, HeapObject::kMapOffset)); 2243 __ movzxbq(temp, FieldOperand(temp, Map::kBitField2Offset)); 2244 __ and_(temp, Immediate(Map::kElementsKindMask)); 2245 __ shr(temp, Immediate(Map::kElementsKindShift)); 2246 __ cmpl(temp, Immediate(FAST_ELEMENTS)); 2247 __ j(equal, &ok, Label::kNear); 2248 __ cmpl(temp, Immediate(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND)); 2249 __ j(less, &fail, Label::kNear); 2250 __ cmpl(temp, Immediate(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND)); 2251 __ j(less_equal, &ok, Label::kNear); 2252 __ bind(&fail); 2253 __ Abort("Check for fast or external elements failed"); 2254 __ bind(&ok); 2255 __ pop(temp); 2256 __ bind(&done); 2257 } 2258} 2259 2260 2261void LCodeGen::DoLoadExternalArrayPointer( 2262 LLoadExternalArrayPointer* instr) { 2263 Register result = ToRegister(instr->result()); 2264 Register input = ToRegister(instr->InputAt(0)); 2265 __ movq(result, FieldOperand(input, 2266 ExternalPixelArray::kExternalPointerOffset)); 2267} 2268 2269 2270void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { 2271 Register arguments = ToRegister(instr->arguments()); 2272 Register length = ToRegister(instr->length()); 2273 Register result = ToRegister(instr->result()); 2274 2275 if (instr->index()->IsRegister()) { 2276 __ subl(length, ToRegister(instr->index())); 2277 } else { 2278 __ subl(length, ToOperand(instr->index())); 2279 } 2280 DeoptimizeIf(below_equal, instr->environment()); 2281 2282 // There are two words between the frame pointer and the last argument. 2283 // Subtracting from length accounts for one of them add one more. 2284 __ movq(result, Operand(arguments, length, times_pointer_size, kPointerSize)); 2285} 2286 2287 2288void LCodeGen::DoLoadKeyedFastElement(LLoadKeyedFastElement* instr) { 2289 Register result = ToRegister(instr->result()); 2290 2291 // Load the result. 2292 __ movq(result, 2293 BuildFastArrayOperand(instr->elements(), instr->key(), 2294 FAST_ELEMENTS, 2295 FixedArray::kHeaderSize - kHeapObjectTag)); 2296 2297 // Check for the hole value. 2298 if (instr->hydrogen()->RequiresHoleCheck()) { 2299 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); 2300 DeoptimizeIf(equal, instr->environment()); 2301 } 2302} 2303 2304 2305void LCodeGen::DoLoadKeyedFastDoubleElement( 2306 LLoadKeyedFastDoubleElement* instr) { 2307 XMMRegister result(ToDoubleRegister(instr->result())); 2308 2309 int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + 2310 sizeof(kHoleNanLower32); 2311 Operand hole_check_operand = BuildFastArrayOperand( 2312 instr->elements(), 2313 instr->key(), 2314 FAST_DOUBLE_ELEMENTS, 2315 offset); 2316 __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32)); 2317 DeoptimizeIf(equal, instr->environment()); 2318 2319 Operand double_load_operand = BuildFastArrayOperand( 2320 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, 2321 FixedDoubleArray::kHeaderSize - kHeapObjectTag); 2322 __ movsd(result, double_load_operand); 2323} 2324 2325 2326Operand LCodeGen::BuildFastArrayOperand( 2327 LOperand* elements_pointer, 2328 LOperand* key, 2329 ElementsKind elements_kind, 2330 uint32_t offset) { 2331 Register elements_pointer_reg = ToRegister(elements_pointer); 2332 int shift_size = ElementsKindToShiftSize(elements_kind); 2333 if (key->IsConstantOperand()) { 2334 int constant_value = ToInteger32(LConstantOperand::cast(key)); 2335 if (constant_value & 0xF0000000) { 2336 Abort("array index constant value too big"); 2337 } 2338 return Operand(elements_pointer_reg, 2339 constant_value * (1 << shift_size) + offset); 2340 } else { 2341 ScaleFactor scale_factor = static_cast<ScaleFactor>(shift_size); 2342 return Operand(elements_pointer_reg, ToRegister(key), 2343 scale_factor, offset); 2344 } 2345} 2346 2347 2348void LCodeGen::DoLoadKeyedSpecializedArrayElement( 2349 LLoadKeyedSpecializedArrayElement* instr) { 2350 ElementsKind elements_kind = instr->elements_kind(); 2351 Operand operand(BuildFastArrayOperand(instr->external_pointer(), 2352 instr->key(), elements_kind, 0)); 2353 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { 2354 XMMRegister result(ToDoubleRegister(instr->result())); 2355 __ movss(result, operand); 2356 __ cvtss2sd(result, result); 2357 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 2358 __ movsd(ToDoubleRegister(instr->result()), operand); 2359 } else { 2360 Register result(ToRegister(instr->result())); 2361 switch (elements_kind) { 2362 case EXTERNAL_BYTE_ELEMENTS: 2363 __ movsxbq(result, operand); 2364 break; 2365 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 2366 case EXTERNAL_PIXEL_ELEMENTS: 2367 __ movzxbq(result, operand); 2368 break; 2369 case EXTERNAL_SHORT_ELEMENTS: 2370 __ movsxwq(result, operand); 2371 break; 2372 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 2373 __ movzxwq(result, operand); 2374 break; 2375 case EXTERNAL_INT_ELEMENTS: 2376 __ movsxlq(result, operand); 2377 break; 2378 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 2379 __ movl(result, operand); 2380 __ testl(result, result); 2381 // TODO(danno): we could be more clever here, perhaps having a special 2382 // version of the stub that detects if the overflow case actually 2383 // happens, and generate code that returns a double rather than int. 2384 DeoptimizeIf(negative, instr->environment()); 2385 break; 2386 case EXTERNAL_FLOAT_ELEMENTS: 2387 case EXTERNAL_DOUBLE_ELEMENTS: 2388 case FAST_ELEMENTS: 2389 case FAST_SMI_ONLY_ELEMENTS: 2390 case FAST_DOUBLE_ELEMENTS: 2391 case DICTIONARY_ELEMENTS: 2392 case NON_STRICT_ARGUMENTS_ELEMENTS: 2393 UNREACHABLE(); 2394 break; 2395 } 2396 } 2397} 2398 2399 2400void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { 2401 ASSERT(ToRegister(instr->object()).is(rdx)); 2402 ASSERT(ToRegister(instr->key()).is(rax)); 2403 2404 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); 2405 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2406} 2407 2408 2409void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { 2410 Register result = ToRegister(instr->result()); 2411 2412 // Check for arguments adapter frame. 2413 Label done, adapted; 2414 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2415 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset), 2416 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 2417 __ j(equal, &adapted, Label::kNear); 2418 2419 // No arguments adaptor frame. 2420 __ movq(result, rbp); 2421 __ jmp(&done, Label::kNear); 2422 2423 // Arguments adaptor frame present. 2424 __ bind(&adapted); 2425 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2426 2427 // Result is the frame pointer for the frame if not adapted and for the real 2428 // frame below the adaptor frame if adapted. 2429 __ bind(&done); 2430} 2431 2432 2433void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { 2434 Register result = ToRegister(instr->result()); 2435 2436 Label done; 2437 2438 // If no arguments adaptor frame the number of arguments is fixed. 2439 if (instr->InputAt(0)->IsRegister()) { 2440 __ cmpq(rbp, ToRegister(instr->InputAt(0))); 2441 } else { 2442 __ cmpq(rbp, ToOperand(instr->InputAt(0))); 2443 } 2444 __ movl(result, Immediate(scope()->num_parameters())); 2445 __ j(equal, &done, Label::kNear); 2446 2447 // Arguments adaptor frame present. Get argument length from there. 2448 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2449 __ SmiToInteger32(result, 2450 Operand(result, 2451 ArgumentsAdaptorFrameConstants::kLengthOffset)); 2452 2453 // Argument length is in result register. 2454 __ bind(&done); 2455} 2456 2457 2458void LCodeGen::DoApplyArguments(LApplyArguments* instr) { 2459 Register receiver = ToRegister(instr->receiver()); 2460 Register function = ToRegister(instr->function()); 2461 Register length = ToRegister(instr->length()); 2462 Register elements = ToRegister(instr->elements()); 2463 ASSERT(receiver.is(rax)); // Used for parameter count. 2464 ASSERT(function.is(rdi)); // Required by InvokeFunction. 2465 ASSERT(ToRegister(instr->result()).is(rax)); 2466 2467 // If the receiver is null or undefined, we have to pass the global 2468 // object as a receiver to normal functions. Values have to be 2469 // passed unchanged to builtins and strict-mode functions. 2470 Label global_object, receiver_ok; 2471 2472 // Do not transform the receiver to object for strict mode 2473 // functions. 2474 __ movq(kScratchRegister, 2475 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); 2476 __ testb(FieldOperand(kScratchRegister, 2477 SharedFunctionInfo::kStrictModeByteOffset), 2478 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); 2479 __ j(not_equal, &receiver_ok, Label::kNear); 2480 2481 // Do not transform the receiver to object for builtins. 2482 __ testb(FieldOperand(kScratchRegister, 2483 SharedFunctionInfo::kNativeByteOffset), 2484 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); 2485 __ j(not_equal, &receiver_ok, Label::kNear); 2486 2487 // Normal function. Replace undefined or null with global receiver. 2488 __ CompareRoot(receiver, Heap::kNullValueRootIndex); 2489 __ j(equal, &global_object, Label::kNear); 2490 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); 2491 __ j(equal, &global_object, Label::kNear); 2492 2493 // The receiver should be a JS object. 2494 Condition is_smi = __ CheckSmi(receiver); 2495 DeoptimizeIf(is_smi, instr->environment()); 2496 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); 2497 DeoptimizeIf(below, instr->environment()); 2498 __ jmp(&receiver_ok, Label::kNear); 2499 2500 __ bind(&global_object); 2501 // TODO(kmillikin): We have a hydrogen value for the global object. See 2502 // if it's better to use it than to explicitly fetch it from the context 2503 // here. 2504 __ movq(receiver, ContextOperand(rsi, Context::GLOBAL_INDEX)); 2505 __ movq(receiver, 2506 FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset)); 2507 __ bind(&receiver_ok); 2508 2509 // Copy the arguments to this function possibly from the 2510 // adaptor frame below it. 2511 const uint32_t kArgumentsLimit = 1 * KB; 2512 __ cmpq(length, Immediate(kArgumentsLimit)); 2513 DeoptimizeIf(above, instr->environment()); 2514 2515 __ push(receiver); 2516 __ movq(receiver, length); 2517 2518 // Loop through the arguments pushing them onto the execution 2519 // stack. 2520 Label invoke, loop; 2521 // length is a small non-negative integer, due to the test above. 2522 __ testl(length, length); 2523 __ j(zero, &invoke, Label::kNear); 2524 __ bind(&loop); 2525 __ push(Operand(elements, length, times_pointer_size, 1 * kPointerSize)); 2526 __ decl(length); 2527 __ j(not_zero, &loop); 2528 2529 // Invoke the function. 2530 __ bind(&invoke); 2531 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); 2532 LPointerMap* pointers = instr->pointer_map(); 2533 RecordPosition(pointers->position()); 2534 SafepointGenerator safepoint_generator( 2535 this, pointers, Safepoint::kLazyDeopt); 2536 v8::internal::ParameterCount actual(rax); 2537 __ InvokeFunction(function, actual, CALL_FUNCTION, 2538 safepoint_generator, CALL_AS_METHOD); 2539 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2540} 2541 2542 2543void LCodeGen::DoPushArgument(LPushArgument* instr) { 2544 LOperand* argument = instr->InputAt(0); 2545 EmitPushTaggedOperand(argument); 2546} 2547 2548 2549void LCodeGen::DoThisFunction(LThisFunction* instr) { 2550 Register result = ToRegister(instr->result()); 2551 LoadHeapObject(result, instr->hydrogen()->closure()); 2552} 2553 2554 2555void LCodeGen::DoContext(LContext* instr) { 2556 Register result = ToRegister(instr->result()); 2557 __ movq(result, rsi); 2558} 2559 2560 2561void LCodeGen::DoOuterContext(LOuterContext* instr) { 2562 Register context = ToRegister(instr->context()); 2563 Register result = ToRegister(instr->result()); 2564 __ movq(result, 2565 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX))); 2566} 2567 2568 2569void LCodeGen::DoGlobalObject(LGlobalObject* instr) { 2570 Register result = ToRegister(instr->result()); 2571 __ movq(result, GlobalObjectOperand()); 2572} 2573 2574 2575void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { 2576 Register global = ToRegister(instr->global()); 2577 Register result = ToRegister(instr->result()); 2578 __ movq(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset)); 2579} 2580 2581 2582void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 2583 int arity, 2584 LInstruction* instr, 2585 CallKind call_kind) { 2586 // Change context if needed. 2587 bool change_context = 2588 (info()->closure()->context() != function->context()) || 2589 scope()->contains_with() || 2590 (scope()->num_heap_slots() > 0); 2591 if (change_context) { 2592 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 2593 } 2594 2595 // Set rax to arguments count if adaption is not needed. Assumes that rax 2596 // is available to write to at this point. 2597 if (!function->NeedsArgumentsAdaption()) { 2598 __ Set(rax, arity); 2599 } 2600 2601 LPointerMap* pointers = instr->pointer_map(); 2602 RecordPosition(pointers->position()); 2603 2604 // Invoke function. 2605 __ SetCallKind(rcx, call_kind); 2606 if (*function == *info()->closure()) { 2607 __ CallSelf(); 2608 } else { 2609 __ call(FieldOperand(rdi, JSFunction::kCodeEntryOffset)); 2610 } 2611 2612 // Setup deoptimization. 2613 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); 2614 2615 // Restore context. 2616 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2617} 2618 2619 2620void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { 2621 ASSERT(ToRegister(instr->result()).is(rax)); 2622 __ Move(rdi, instr->function()); 2623 CallKnownFunction(instr->function(), 2624 instr->arity(), 2625 instr, 2626 CALL_AS_METHOD); 2627} 2628 2629 2630void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) { 2631 Register input_reg = ToRegister(instr->InputAt(0)); 2632 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), 2633 Heap::kHeapNumberMapRootIndex); 2634 DeoptimizeIf(not_equal, instr->environment()); 2635 2636 Label done; 2637 Register tmp = input_reg.is(rax) ? rcx : rax; 2638 Register tmp2 = tmp.is(rcx) ? rdx : input_reg.is(rcx) ? rdx : rcx; 2639 2640 // Preserve the value of all registers. 2641 PushSafepointRegistersScope scope(this); 2642 2643 Label negative; 2644 __ movl(tmp, FieldOperand(input_reg, HeapNumber::kExponentOffset)); 2645 // Check the sign of the argument. If the argument is positive, just 2646 // return it. We do not need to patch the stack since |input| and 2647 // |result| are the same register and |input| will be restored 2648 // unchanged by popping safepoint registers. 2649 __ testl(tmp, Immediate(HeapNumber::kSignMask)); 2650 __ j(not_zero, &negative); 2651 __ jmp(&done); 2652 2653 __ bind(&negative); 2654 2655 Label allocated, slow; 2656 __ AllocateHeapNumber(tmp, tmp2, &slow); 2657 __ jmp(&allocated); 2658 2659 // Slow case: Call the runtime system to do the number allocation. 2660 __ bind(&slow); 2661 2662 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); 2663 // Set the pointer to the new heap number in tmp. 2664 if (!tmp.is(rax)) { 2665 __ movq(tmp, rax); 2666 } 2667 2668 // Restore input_reg after call to runtime. 2669 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); 2670 2671 __ bind(&allocated); 2672 __ movq(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset)); 2673 __ shl(tmp2, Immediate(1)); 2674 __ shr(tmp2, Immediate(1)); 2675 __ movq(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2); 2676 __ StoreToSafepointRegisterSlot(input_reg, tmp); 2677 2678 __ bind(&done); 2679} 2680 2681 2682void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) { 2683 Register input_reg = ToRegister(instr->InputAt(0)); 2684 __ testl(input_reg, input_reg); 2685 Label is_positive; 2686 __ j(not_sign, &is_positive); 2687 __ negl(input_reg); // Sets flags. 2688 DeoptimizeIf(negative, instr->environment()); 2689 __ bind(&is_positive); 2690} 2691 2692 2693void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) { 2694 // Class for deferred case. 2695 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { 2696 public: 2697 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, 2698 LUnaryMathOperation* instr) 2699 : LDeferredCode(codegen), instr_(instr) { } 2700 virtual void Generate() { 2701 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); 2702 } 2703 virtual LInstruction* instr() { return instr_; } 2704 private: 2705 LUnaryMathOperation* instr_; 2706 }; 2707 2708 ASSERT(instr->InputAt(0)->Equals(instr->result())); 2709 Representation r = instr->hydrogen()->value()->representation(); 2710 2711 if (r.IsDouble()) { 2712 XMMRegister scratch = xmm0; 2713 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); 2714 __ xorps(scratch, scratch); 2715 __ subsd(scratch, input_reg); 2716 __ andpd(input_reg, scratch); 2717 } else if (r.IsInteger32()) { 2718 EmitIntegerMathAbs(instr); 2719 } else { // Tagged case. 2720 DeferredMathAbsTaggedHeapNumber* deferred = 2721 new DeferredMathAbsTaggedHeapNumber(this, instr); 2722 Register input_reg = ToRegister(instr->InputAt(0)); 2723 // Smi check. 2724 __ JumpIfNotSmi(input_reg, deferred->entry()); 2725 __ SmiToInteger32(input_reg, input_reg); 2726 EmitIntegerMathAbs(instr); 2727 __ Integer32ToSmi(input_reg, input_reg); 2728 __ bind(deferred->exit()); 2729 } 2730} 2731 2732 2733void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { 2734 XMMRegister xmm_scratch = xmm0; 2735 Register output_reg = ToRegister(instr->result()); 2736 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); 2737 Label done; 2738 2739 if (CpuFeatures::IsSupported(SSE4_1)) { 2740 CpuFeatures::Scope scope(SSE4_1); 2741 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 2742 // Deoptimize if minus zero. 2743 __ movq(output_reg, input_reg); 2744 __ subq(output_reg, Immediate(1)); 2745 DeoptimizeIf(overflow, instr->environment()); 2746 } 2747 __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown); 2748 __ cvttsd2si(output_reg, xmm_scratch); 2749 __ cmpl(output_reg, Immediate(0x80000000)); 2750 DeoptimizeIf(equal, instr->environment()); 2751 } else { 2752 // Deoptimize on negative inputs. 2753 __ xorps(xmm_scratch, xmm_scratch); // Zero the register. 2754 __ ucomisd(input_reg, xmm_scratch); 2755 DeoptimizeIf(below, instr->environment()); 2756 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 2757 // Check for negative zero. 2758 Label positive_sign; 2759 __ j(above, &positive_sign, Label::kNear); 2760 __ movmskpd(output_reg, input_reg); 2761 __ testq(output_reg, Immediate(1)); 2762 DeoptimizeIf(not_zero, instr->environment()); 2763 __ Set(output_reg, 0); 2764 __ jmp(&done); 2765 __ bind(&positive_sign); 2766 } 2767 2768 // Use truncating instruction (OK because input is positive). 2769 __ cvttsd2si(output_reg, input_reg); 2770 2771 // Overflow is signalled with minint. 2772 __ cmpl(output_reg, Immediate(0x80000000)); 2773 DeoptimizeIf(equal, instr->environment()); 2774 } 2775 __ bind(&done); 2776} 2777 2778 2779void LCodeGen::DoMathRound(LUnaryMathOperation* instr) { 2780 const XMMRegister xmm_scratch = xmm0; 2781 Register output_reg = ToRegister(instr->result()); 2782 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); 2783 2784 Label done; 2785 // xmm_scratch = 0.5 2786 __ movq(kScratchRegister, V8_INT64_C(0x3FE0000000000000), RelocInfo::NONE); 2787 __ movq(xmm_scratch, kScratchRegister); 2788 Label below_half; 2789 __ ucomisd(xmm_scratch, input_reg); 2790 // If input_reg is NaN, this doesn't jump. 2791 __ j(above, &below_half, Label::kNear); 2792 // input = input + 0.5 2793 // This addition might give a result that isn't the correct for 2794 // rounding, due to loss of precision, but only for a number that's 2795 // so big that the conversion below will overflow anyway. 2796 __ addsd(xmm_scratch, input_reg); 2797 // Compute Math.floor(input). 2798 // Use truncating instruction (OK because input is positive). 2799 __ cvttsd2si(output_reg, xmm_scratch); 2800 // Overflow is signalled with minint. 2801 __ cmpl(output_reg, Immediate(0x80000000)); 2802 DeoptimizeIf(equal, instr->environment()); 2803 __ jmp(&done); 2804 2805 __ bind(&below_half); 2806 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 2807 // Bailout if negative (including -0). 2808 __ movq(output_reg, input_reg); 2809 __ testq(output_reg, output_reg); 2810 DeoptimizeIf(negative, instr->environment()); 2811 } else { 2812 // Bailout if below -0.5, otherwise round to (positive) zero, even 2813 // if negative. 2814 // xmm_scrach = -0.5 2815 __ movq(kScratchRegister, V8_INT64_C(0xBFE0000000000000), RelocInfo::NONE); 2816 __ movq(xmm_scratch, kScratchRegister); 2817 __ ucomisd(input_reg, xmm_scratch); 2818 DeoptimizeIf(below, instr->environment()); 2819 } 2820 __ xorl(output_reg, output_reg); 2821 2822 __ bind(&done); 2823} 2824 2825 2826void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) { 2827 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); 2828 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); 2829 __ sqrtsd(input_reg, input_reg); 2830} 2831 2832 2833void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) { 2834 XMMRegister xmm_scratch = xmm0; 2835 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); 2836 ASSERT(ToDoubleRegister(instr->result()).is(input_reg)); 2837 __ xorps(xmm_scratch, xmm_scratch); 2838 __ addsd(input_reg, xmm_scratch); // Convert -0 to +0. 2839 __ sqrtsd(input_reg, input_reg); 2840} 2841 2842 2843void LCodeGen::DoPower(LPower* instr) { 2844 LOperand* left = instr->InputAt(0); 2845 XMMRegister left_reg = ToDoubleRegister(left); 2846 ASSERT(!left_reg.is(xmm1)); 2847 LOperand* right = instr->InputAt(1); 2848 XMMRegister result_reg = ToDoubleRegister(instr->result()); 2849 Representation exponent_type = instr->hydrogen()->right()->representation(); 2850 if (exponent_type.IsDouble()) { 2851 __ PrepareCallCFunction(2); 2852 // Move arguments to correct registers 2853 __ movaps(xmm0, left_reg); 2854 ASSERT(ToDoubleRegister(right).is(xmm1)); 2855 __ CallCFunction( 2856 ExternalReference::power_double_double_function(isolate()), 2); 2857 } else if (exponent_type.IsInteger32()) { 2858 __ PrepareCallCFunction(2); 2859 // Move arguments to correct registers: xmm0 and edi (not rdi). 2860 // On Windows, the registers are xmm0 and edx. 2861 __ movaps(xmm0, left_reg); 2862#ifdef _WIN64 2863 ASSERT(ToRegister(right).is(rdx)); 2864#else 2865 ASSERT(ToRegister(right).is(rdi)); 2866#endif 2867 __ CallCFunction( 2868 ExternalReference::power_double_int_function(isolate()), 2); 2869 } else { 2870 ASSERT(exponent_type.IsTagged()); 2871 Register right_reg = ToRegister(right); 2872 2873 Label non_smi, call; 2874 __ JumpIfNotSmi(right_reg, &non_smi); 2875 __ SmiToInteger32(right_reg, right_reg); 2876 __ cvtlsi2sd(xmm1, right_reg); 2877 __ jmp(&call); 2878 2879 __ bind(&non_smi); 2880 __ CmpObjectType(right_reg, HEAP_NUMBER_TYPE , kScratchRegister); 2881 DeoptimizeIf(not_equal, instr->environment()); 2882 __ movsd(xmm1, FieldOperand(right_reg, HeapNumber::kValueOffset)); 2883 2884 __ bind(&call); 2885 __ PrepareCallCFunction(2); 2886 // Move arguments to correct registers xmm0 and xmm1. 2887 __ movaps(xmm0, left_reg); 2888 // Right argument is already in xmm1. 2889 __ CallCFunction( 2890 ExternalReference::power_double_double_function(isolate()), 2); 2891 } 2892 // Return value is in xmm0. 2893 __ movaps(result_reg, xmm0); 2894 // Restore context register. 2895 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2896} 2897 2898 2899void LCodeGen::DoMathLog(LUnaryMathOperation* instr) { 2900 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); 2901 TranscendentalCacheStub stub(TranscendentalCache::LOG, 2902 TranscendentalCacheStub::UNTAGGED); 2903 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 2904} 2905 2906 2907void LCodeGen::DoMathTan(LUnaryMathOperation* instr) { 2908 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); 2909 TranscendentalCacheStub stub(TranscendentalCache::TAN, 2910 TranscendentalCacheStub::UNTAGGED); 2911 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 2912} 2913 2914 2915void LCodeGen::DoMathCos(LUnaryMathOperation* instr) { 2916 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); 2917 TranscendentalCacheStub stub(TranscendentalCache::COS, 2918 TranscendentalCacheStub::UNTAGGED); 2919 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 2920} 2921 2922 2923void LCodeGen::DoMathSin(LUnaryMathOperation* instr) { 2924 ASSERT(ToDoubleRegister(instr->result()).is(xmm1)); 2925 TranscendentalCacheStub stub(TranscendentalCache::SIN, 2926 TranscendentalCacheStub::UNTAGGED); 2927 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 2928} 2929 2930 2931void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) { 2932 switch (instr->op()) { 2933 case kMathAbs: 2934 DoMathAbs(instr); 2935 break; 2936 case kMathFloor: 2937 DoMathFloor(instr); 2938 break; 2939 case kMathRound: 2940 DoMathRound(instr); 2941 break; 2942 case kMathSqrt: 2943 DoMathSqrt(instr); 2944 break; 2945 case kMathPowHalf: 2946 DoMathPowHalf(instr); 2947 break; 2948 case kMathCos: 2949 DoMathCos(instr); 2950 break; 2951 case kMathSin: 2952 DoMathSin(instr); 2953 break; 2954 case kMathTan: 2955 DoMathTan(instr); 2956 break; 2957 case kMathLog: 2958 DoMathLog(instr); 2959 break; 2960 2961 default: 2962 UNREACHABLE(); 2963 } 2964} 2965 2966 2967void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { 2968 ASSERT(ToRegister(instr->function()).is(rdi)); 2969 ASSERT(instr->HasPointerMap()); 2970 ASSERT(instr->HasDeoptimizationEnvironment()); 2971 LPointerMap* pointers = instr->pointer_map(); 2972 RecordPosition(pointers->position()); 2973 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); 2974 ParameterCount count(instr->arity()); 2975 __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD); 2976 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2977} 2978 2979 2980void LCodeGen::DoCallKeyed(LCallKeyed* instr) { 2981 ASSERT(ToRegister(instr->key()).is(rcx)); 2982 ASSERT(ToRegister(instr->result()).is(rax)); 2983 2984 int arity = instr->arity(); 2985 Handle<Code> ic = 2986 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); 2987 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2988 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 2989} 2990 2991 2992void LCodeGen::DoCallNamed(LCallNamed* instr) { 2993 ASSERT(ToRegister(instr->result()).is(rax)); 2994 2995 int arity = instr->arity(); 2996 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; 2997 Handle<Code> ic = 2998 isolate()->stub_cache()->ComputeCallInitialize(arity, mode); 2999 __ Move(rcx, instr->name()); 3000 CallCode(ic, mode, instr); 3001 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 3002} 3003 3004 3005void LCodeGen::DoCallFunction(LCallFunction* instr) { 3006 ASSERT(ToRegister(instr->function()).is(rdi)); 3007 ASSERT(ToRegister(instr->result()).is(rax)); 3008 3009 int arity = instr->arity(); 3010 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); 3011 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 3012 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 3013} 3014 3015 3016void LCodeGen::DoCallGlobal(LCallGlobal* instr) { 3017 ASSERT(ToRegister(instr->result()).is(rax)); 3018 int arity = instr->arity(); 3019 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; 3020 Handle<Code> ic = 3021 isolate()->stub_cache()->ComputeCallInitialize(arity, mode); 3022 __ Move(rcx, instr->name()); 3023 CallCode(ic, mode, instr); 3024 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 3025} 3026 3027 3028void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { 3029 ASSERT(ToRegister(instr->result()).is(rax)); 3030 __ Move(rdi, instr->target()); 3031 CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION); 3032} 3033 3034 3035void LCodeGen::DoCallNew(LCallNew* instr) { 3036 ASSERT(ToRegister(instr->InputAt(0)).is(rdi)); 3037 ASSERT(ToRegister(instr->result()).is(rax)); 3038 3039 Handle<Code> builtin = isolate()->builtins()->JSConstructCall(); 3040 __ Set(rax, instr->arity()); 3041 CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr); 3042} 3043 3044 3045void LCodeGen::DoCallRuntime(LCallRuntime* instr) { 3046 CallRuntime(instr->function(), instr->arity(), instr); 3047} 3048 3049 3050void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { 3051 Register object = ToRegister(instr->object()); 3052 Register value = ToRegister(instr->value()); 3053 int offset = instr->offset(); 3054 3055 if (!instr->transition().is_null()) { 3056 __ Move(FieldOperand(object, HeapObject::kMapOffset), instr->transition()); 3057 } 3058 3059 // Do the store. 3060 HType type = instr->hydrogen()->value()->type(); 3061 SmiCheck check_needed = 3062 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 3063 if (instr->is_in_object()) { 3064 __ movq(FieldOperand(object, offset), value); 3065 if (instr->hydrogen()->NeedsWriteBarrier()) { 3066 Register temp = ToRegister(instr->TempAt(0)); 3067 // Update the write barrier for the object for in-object properties. 3068 __ RecordWriteField(object, 3069 offset, 3070 value, 3071 temp, 3072 kSaveFPRegs, 3073 EMIT_REMEMBERED_SET, 3074 check_needed); 3075 } 3076 } else { 3077 Register temp = ToRegister(instr->TempAt(0)); 3078 __ movq(temp, FieldOperand(object, JSObject::kPropertiesOffset)); 3079 __ movq(FieldOperand(temp, offset), value); 3080 if (instr->hydrogen()->NeedsWriteBarrier()) { 3081 // Update the write barrier for the properties array. 3082 // object is used as a scratch register. 3083 __ RecordWriteField(temp, 3084 offset, 3085 value, 3086 object, 3087 kSaveFPRegs, 3088 EMIT_REMEMBERED_SET, 3089 check_needed); 3090 } 3091 } 3092} 3093 3094 3095void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { 3096 ASSERT(ToRegister(instr->object()).is(rdx)); 3097 ASSERT(ToRegister(instr->value()).is(rax)); 3098 3099 __ Move(rcx, instr->hydrogen()->name()); 3100 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) 3101 ? isolate()->builtins()->StoreIC_Initialize_Strict() 3102 : isolate()->builtins()->StoreIC_Initialize(); 3103 CallCode(ic, RelocInfo::CODE_TARGET, instr); 3104} 3105 3106 3107void LCodeGen::DoStoreKeyedSpecializedArrayElement( 3108 LStoreKeyedSpecializedArrayElement* instr) { 3109 ElementsKind elements_kind = instr->elements_kind(); 3110 Operand operand(BuildFastArrayOperand(instr->external_pointer(), 3111 instr->key(), elements_kind, 0)); 3112 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { 3113 XMMRegister value(ToDoubleRegister(instr->value())); 3114 __ cvtsd2ss(value, value); 3115 __ movss(operand, value); 3116 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 3117 __ movsd(operand, ToDoubleRegister(instr->value())); 3118 } else { 3119 Register value(ToRegister(instr->value())); 3120 switch (elements_kind) { 3121 case EXTERNAL_PIXEL_ELEMENTS: 3122 case EXTERNAL_BYTE_ELEMENTS: 3123 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 3124 __ movb(operand, value); 3125 break; 3126 case EXTERNAL_SHORT_ELEMENTS: 3127 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 3128 __ movw(operand, value); 3129 break; 3130 case EXTERNAL_INT_ELEMENTS: 3131 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 3132 __ movl(operand, value); 3133 break; 3134 case EXTERNAL_FLOAT_ELEMENTS: 3135 case EXTERNAL_DOUBLE_ELEMENTS: 3136 case FAST_ELEMENTS: 3137 case FAST_SMI_ONLY_ELEMENTS: 3138 case FAST_DOUBLE_ELEMENTS: 3139 case DICTIONARY_ELEMENTS: 3140 case NON_STRICT_ARGUMENTS_ELEMENTS: 3141 UNREACHABLE(); 3142 break; 3143 } 3144 } 3145} 3146 3147 3148void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { 3149 if (instr->index()->IsConstantOperand()) { 3150 if (instr->length()->IsRegister()) { 3151 __ cmpq(ToRegister(instr->length()), 3152 Immediate(ToInteger32(LConstantOperand::cast(instr->index())))); 3153 } else { 3154 __ cmpq(ToOperand(instr->length()), 3155 Immediate(ToInteger32(LConstantOperand::cast(instr->index())))); 3156 } 3157 } else { 3158 if (instr->length()->IsRegister()) { 3159 __ cmpq(ToRegister(instr->length()), ToRegister(instr->index())); 3160 } else { 3161 __ cmpq(ToOperand(instr->length()), ToRegister(instr->index())); 3162 } 3163 } 3164 DeoptimizeIf(below_equal, instr->environment()); 3165} 3166 3167 3168void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) { 3169 Register value = ToRegister(instr->value()); 3170 Register elements = ToRegister(instr->object()); 3171 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; 3172 3173 // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS 3174 // conversion, so it deopts in that case. 3175 if (instr->hydrogen()->ValueNeedsSmiCheck()) { 3176 Condition cc = masm()->CheckSmi(value); 3177 DeoptimizeIf(NegateCondition(cc), instr->environment()); 3178 } 3179 3180 // Do the store. 3181 if (instr->key()->IsConstantOperand()) { 3182 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); 3183 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); 3184 int offset = 3185 ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize; 3186 __ movq(FieldOperand(elements, offset), value); 3187 } else { 3188 __ movq(FieldOperand(elements, 3189 key, 3190 times_pointer_size, 3191 FixedArray::kHeaderSize), 3192 value); 3193 } 3194 3195 if (instr->hydrogen()->NeedsWriteBarrier()) { 3196 HType type = instr->hydrogen()->value()->type(); 3197 SmiCheck check_needed = 3198 type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 3199 // Compute address of modified element and store it into key register. 3200 __ lea(key, FieldOperand(elements, 3201 key, 3202 times_pointer_size, 3203 FixedArray::kHeaderSize)); 3204 __ RecordWrite(elements, 3205 key, 3206 value, 3207 kSaveFPRegs, 3208 EMIT_REMEMBERED_SET, 3209 check_needed); 3210 } 3211} 3212 3213 3214void LCodeGen::DoStoreKeyedFastDoubleElement( 3215 LStoreKeyedFastDoubleElement* instr) { 3216 XMMRegister value = ToDoubleRegister(instr->value()); 3217 Label have_value; 3218 3219 __ ucomisd(value, value); 3220 __ j(parity_odd, &have_value); // NaN. 3221 3222 __ Set(kScratchRegister, BitCast<uint64_t>( 3223 FixedDoubleArray::canonical_not_the_hole_nan_as_double())); 3224 __ movq(value, kScratchRegister); 3225 3226 __ bind(&have_value); 3227 Operand double_store_operand = BuildFastArrayOperand( 3228 instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, 3229 FixedDoubleArray::kHeaderSize - kHeapObjectTag); 3230 __ movsd(double_store_operand, value); 3231} 3232 3233void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { 3234 ASSERT(ToRegister(instr->object()).is(rdx)); 3235 ASSERT(ToRegister(instr->key()).is(rcx)); 3236 ASSERT(ToRegister(instr->value()).is(rax)); 3237 3238 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) 3239 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() 3240 : isolate()->builtins()->KeyedStoreIC_Initialize(); 3241 CallCode(ic, RelocInfo::CODE_TARGET, instr); 3242} 3243 3244 3245void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { 3246 Register object_reg = ToRegister(instr->object()); 3247 Register new_map_reg = ToRegister(instr->new_map_reg()); 3248 3249 Handle<Map> from_map = instr->original_map(); 3250 Handle<Map> to_map = instr->transitioned_map(); 3251 ElementsKind from_kind = from_map->elements_kind(); 3252 ElementsKind to_kind = to_map->elements_kind(); 3253 3254 Label not_applicable; 3255 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); 3256 __ j(not_equal, ¬_applicable); 3257 __ movq(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT); 3258 if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { 3259 __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); 3260 // Write barrier. 3261 ASSERT_NE(instr->temp_reg(), NULL); 3262 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, 3263 ToRegister(instr->temp_reg()), kDontSaveFPRegs); 3264 } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && 3265 to_kind == FAST_DOUBLE_ELEMENTS) { 3266 Register fixed_object_reg = ToRegister(instr->temp_reg()); 3267 ASSERT(fixed_object_reg.is(rdx)); 3268 ASSERT(new_map_reg.is(rbx)); 3269 __ movq(fixed_object_reg, object_reg); 3270 CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), 3271 RelocInfo::CODE_TARGET, instr); 3272 } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { 3273 Register fixed_object_reg = ToRegister(instr->temp_reg()); 3274 ASSERT(fixed_object_reg.is(rdx)); 3275 ASSERT(new_map_reg.is(rbx)); 3276 __ movq(fixed_object_reg, object_reg); 3277 CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), 3278 RelocInfo::CODE_TARGET, instr); 3279 } else { 3280 UNREACHABLE(); 3281 } 3282 __ bind(¬_applicable); 3283} 3284 3285 3286void LCodeGen::DoStringAdd(LStringAdd* instr) { 3287 EmitPushTaggedOperand(instr->left()); 3288 EmitPushTaggedOperand(instr->right()); 3289 StringAddStub stub(NO_STRING_CHECK_IN_STUB); 3290 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 3291} 3292 3293 3294void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { 3295 class DeferredStringCharCodeAt: public LDeferredCode { 3296 public: 3297 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) 3298 : LDeferredCode(codegen), instr_(instr) { } 3299 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } 3300 virtual LInstruction* instr() { return instr_; } 3301 private: 3302 LStringCharCodeAt* instr_; 3303 }; 3304 3305 DeferredStringCharCodeAt* deferred = 3306 new DeferredStringCharCodeAt(this, instr); 3307 3308 StringCharLoadGenerator::Generate(masm(), 3309 ToRegister(instr->string()), 3310 ToRegister(instr->index()), 3311 ToRegister(instr->result()), 3312 deferred->entry()); 3313 __ bind(deferred->exit()); 3314} 3315 3316 3317void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { 3318 Register string = ToRegister(instr->string()); 3319 Register result = ToRegister(instr->result()); 3320 3321 // TODO(3095996): Get rid of this. For now, we need to make the 3322 // result register contain a valid pointer because it is already 3323 // contained in the register pointer map. 3324 __ Set(result, 0); 3325 3326 PushSafepointRegistersScope scope(this); 3327 __ push(string); 3328 // Push the index as a smi. This is safe because of the checks in 3329 // DoStringCharCodeAt above. 3330 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); 3331 if (instr->index()->IsConstantOperand()) { 3332 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); 3333 __ Push(Smi::FromInt(const_index)); 3334 } else { 3335 Register index = ToRegister(instr->index()); 3336 __ Integer32ToSmi(index, index); 3337 __ push(index); 3338 } 3339 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); 3340 if (FLAG_debug_code) { 3341 __ AbortIfNotSmi(rax); 3342 } 3343 __ SmiToInteger32(rax, rax); 3344 __ StoreToSafepointRegisterSlot(result, rax); 3345} 3346 3347 3348void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { 3349 class DeferredStringCharFromCode: public LDeferredCode { 3350 public: 3351 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) 3352 : LDeferredCode(codegen), instr_(instr) { } 3353 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } 3354 virtual LInstruction* instr() { return instr_; } 3355 private: 3356 LStringCharFromCode* instr_; 3357 }; 3358 3359 DeferredStringCharFromCode* deferred = 3360 new DeferredStringCharFromCode(this, instr); 3361 3362 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); 3363 Register char_code = ToRegister(instr->char_code()); 3364 Register result = ToRegister(instr->result()); 3365 ASSERT(!char_code.is(result)); 3366 3367 __ cmpl(char_code, Immediate(String::kMaxAsciiCharCode)); 3368 __ j(above, deferred->entry()); 3369 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex); 3370 __ movq(result, FieldOperand(result, 3371 char_code, times_pointer_size, 3372 FixedArray::kHeaderSize)); 3373 __ CompareRoot(result, Heap::kUndefinedValueRootIndex); 3374 __ j(equal, deferred->entry()); 3375 __ bind(deferred->exit()); 3376} 3377 3378 3379void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { 3380 Register char_code = ToRegister(instr->char_code()); 3381 Register result = ToRegister(instr->result()); 3382 3383 // TODO(3095996): Get rid of this. For now, we need to make the 3384 // result register contain a valid pointer because it is already 3385 // contained in the register pointer map. 3386 __ Set(result, 0); 3387 3388 PushSafepointRegistersScope scope(this); 3389 __ Integer32ToSmi(char_code, char_code); 3390 __ push(char_code); 3391 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr); 3392 __ StoreToSafepointRegisterSlot(result, rax); 3393} 3394 3395 3396void LCodeGen::DoStringLength(LStringLength* instr) { 3397 Register string = ToRegister(instr->string()); 3398 Register result = ToRegister(instr->result()); 3399 __ movq(result, FieldOperand(string, String::kLengthOffset)); 3400} 3401 3402 3403void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { 3404 LOperand* input = instr->InputAt(0); 3405 ASSERT(input->IsRegister() || input->IsStackSlot()); 3406 LOperand* output = instr->result(); 3407 ASSERT(output->IsDoubleRegister()); 3408 if (input->IsRegister()) { 3409 __ cvtlsi2sd(ToDoubleRegister(output), ToRegister(input)); 3410 } else { 3411 __ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input)); 3412 } 3413} 3414 3415 3416void LCodeGen::DoNumberTagI(LNumberTagI* instr) { 3417 LOperand* input = instr->InputAt(0); 3418 ASSERT(input->IsRegister() && input->Equals(instr->result())); 3419 Register reg = ToRegister(input); 3420 3421 __ Integer32ToSmi(reg, reg); 3422} 3423 3424 3425void LCodeGen::DoNumberTagD(LNumberTagD* instr) { 3426 class DeferredNumberTagD: public LDeferredCode { 3427 public: 3428 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) 3429 : LDeferredCode(codegen), instr_(instr) { } 3430 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } 3431 virtual LInstruction* instr() { return instr_; } 3432 private: 3433 LNumberTagD* instr_; 3434 }; 3435 3436 XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); 3437 Register reg = ToRegister(instr->result()); 3438 Register tmp = ToRegister(instr->TempAt(0)); 3439 3440 DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); 3441 if (FLAG_inline_new) { 3442 __ AllocateHeapNumber(reg, tmp, deferred->entry()); 3443 } else { 3444 __ jmp(deferred->entry()); 3445 } 3446 __ bind(deferred->exit()); 3447 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); 3448} 3449 3450 3451void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { 3452 // TODO(3095996): Get rid of this. For now, we need to make the 3453 // result register contain a valid pointer because it is already 3454 // contained in the register pointer map. 3455 Register reg = ToRegister(instr->result()); 3456 __ Move(reg, Smi::FromInt(0)); 3457 3458 { 3459 PushSafepointRegistersScope scope(this); 3460 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); 3461 // Ensure that value in rax survives popping registers. 3462 __ movq(kScratchRegister, rax); 3463 } 3464 __ movq(reg, kScratchRegister); 3465} 3466 3467 3468void LCodeGen::DoSmiTag(LSmiTag* instr) { 3469 ASSERT(instr->InputAt(0)->Equals(instr->result())); 3470 Register input = ToRegister(instr->InputAt(0)); 3471 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); 3472 __ Integer32ToSmi(input, input); 3473} 3474 3475 3476void LCodeGen::DoSmiUntag(LSmiUntag* instr) { 3477 ASSERT(instr->InputAt(0)->Equals(instr->result())); 3478 Register input = ToRegister(instr->InputAt(0)); 3479 if (instr->needs_check()) { 3480 Condition is_smi = __ CheckSmi(input); 3481 DeoptimizeIf(NegateCondition(is_smi), instr->environment()); 3482 } 3483 __ SmiToInteger32(input, input); 3484} 3485 3486 3487void LCodeGen::EmitNumberUntagD(Register input_reg, 3488 XMMRegister result_reg, 3489 bool deoptimize_on_undefined, 3490 LEnvironment* env) { 3491 Label load_smi, done; 3492 3493 // Smi check. 3494 __ JumpIfSmi(input_reg, &load_smi, Label::kNear); 3495 3496 // Heap number map check. 3497 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), 3498 Heap::kHeapNumberMapRootIndex); 3499 if (deoptimize_on_undefined) { 3500 DeoptimizeIf(not_equal, env); 3501 } else { 3502 Label heap_number; 3503 __ j(equal, &heap_number, Label::kNear); 3504 3505 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); 3506 DeoptimizeIf(not_equal, env); 3507 3508 // Convert undefined to NaN. Compute NaN as 0/0. 3509 __ xorps(result_reg, result_reg); 3510 __ divsd(result_reg, result_reg); 3511 __ jmp(&done, Label::kNear); 3512 3513 __ bind(&heap_number); 3514 } 3515 // Heap number to XMM conversion. 3516 __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); 3517 __ jmp(&done, Label::kNear); 3518 3519 // Smi to XMM conversion 3520 __ bind(&load_smi); 3521 __ SmiToInteger32(kScratchRegister, input_reg); 3522 __ cvtlsi2sd(result_reg, kScratchRegister); 3523 __ bind(&done); 3524} 3525 3526 3527void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { 3528 Label done, heap_number; 3529 Register input_reg = ToRegister(instr->InputAt(0)); 3530 3531 // Heap number map check. 3532 __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), 3533 Heap::kHeapNumberMapRootIndex); 3534 3535 if (instr->truncating()) { 3536 __ j(equal, &heap_number, Label::kNear); 3537 // Check for undefined. Undefined is converted to zero for truncating 3538 // conversions. 3539 __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); 3540 DeoptimizeIf(not_equal, instr->environment()); 3541 __ Set(input_reg, 0); 3542 __ jmp(&done, Label::kNear); 3543 3544 __ bind(&heap_number); 3545 3546 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 3547 __ cvttsd2siq(input_reg, xmm0); 3548 __ Set(kScratchRegister, V8_UINT64_C(0x8000000000000000)); 3549 __ cmpq(input_reg, kScratchRegister); 3550 DeoptimizeIf(equal, instr->environment()); 3551 } else { 3552 // Deoptimize if we don't have a heap number. 3553 DeoptimizeIf(not_equal, instr->environment()); 3554 3555 XMMRegister xmm_temp = ToDoubleRegister(instr->TempAt(0)); 3556 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 3557 __ cvttsd2si(input_reg, xmm0); 3558 __ cvtlsi2sd(xmm_temp, input_reg); 3559 __ ucomisd(xmm0, xmm_temp); 3560 DeoptimizeIf(not_equal, instr->environment()); 3561 DeoptimizeIf(parity_even, instr->environment()); // NaN. 3562 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3563 __ testl(input_reg, input_reg); 3564 __ j(not_zero, &done); 3565 __ movmskpd(input_reg, xmm0); 3566 __ andl(input_reg, Immediate(1)); 3567 DeoptimizeIf(not_zero, instr->environment()); 3568 } 3569 } 3570 __ bind(&done); 3571} 3572 3573 3574void LCodeGen::DoTaggedToI(LTaggedToI* instr) { 3575 class DeferredTaggedToI: public LDeferredCode { 3576 public: 3577 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) 3578 : LDeferredCode(codegen), instr_(instr) { } 3579 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } 3580 virtual LInstruction* instr() { return instr_; } 3581 private: 3582 LTaggedToI* instr_; 3583 }; 3584 3585 LOperand* input = instr->InputAt(0); 3586 ASSERT(input->IsRegister()); 3587 ASSERT(input->Equals(instr->result())); 3588 3589 Register input_reg = ToRegister(input); 3590 DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr); 3591 __ JumpIfNotSmi(input_reg, deferred->entry()); 3592 __ SmiToInteger32(input_reg, input_reg); 3593 __ bind(deferred->exit()); 3594} 3595 3596 3597void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { 3598 LOperand* input = instr->InputAt(0); 3599 ASSERT(input->IsRegister()); 3600 LOperand* result = instr->result(); 3601 ASSERT(result->IsDoubleRegister()); 3602 3603 Register input_reg = ToRegister(input); 3604 XMMRegister result_reg = ToDoubleRegister(result); 3605 3606 EmitNumberUntagD(input_reg, result_reg, 3607 instr->hydrogen()->deoptimize_on_undefined(), 3608 instr->environment()); 3609} 3610 3611 3612void LCodeGen::DoDoubleToI(LDoubleToI* instr) { 3613 LOperand* input = instr->InputAt(0); 3614 ASSERT(input->IsDoubleRegister()); 3615 LOperand* result = instr->result(); 3616 ASSERT(result->IsRegister()); 3617 3618 XMMRegister input_reg = ToDoubleRegister(input); 3619 Register result_reg = ToRegister(result); 3620 3621 if (instr->truncating()) { 3622 // Performs a truncating conversion of a floating point number as used by 3623 // the JS bitwise operations. 3624 __ cvttsd2siq(result_reg, input_reg); 3625 __ movq(kScratchRegister, V8_INT64_C(0x8000000000000000), RelocInfo::NONE); 3626 __ cmpq(result_reg, kScratchRegister); 3627 DeoptimizeIf(equal, instr->environment()); 3628 } else { 3629 __ cvttsd2si(result_reg, input_reg); 3630 __ cvtlsi2sd(xmm0, result_reg); 3631 __ ucomisd(xmm0, input_reg); 3632 DeoptimizeIf(not_equal, instr->environment()); 3633 DeoptimizeIf(parity_even, instr->environment()); // NaN. 3634 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3635 Label done; 3636 // The integer converted back is equal to the original. We 3637 // only have to test if we got -0 as an input. 3638 __ testl(result_reg, result_reg); 3639 __ j(not_zero, &done, Label::kNear); 3640 __ movmskpd(result_reg, input_reg); 3641 // Bit 0 contains the sign of the double in input_reg. 3642 // If input was positive, we are ok and return 0, otherwise 3643 // deoptimize. 3644 __ andl(result_reg, Immediate(1)); 3645 DeoptimizeIf(not_zero, instr->environment()); 3646 __ bind(&done); 3647 } 3648 } 3649} 3650 3651 3652void LCodeGen::DoCheckSmi(LCheckSmi* instr) { 3653 LOperand* input = instr->InputAt(0); 3654 Condition cc = masm()->CheckSmi(ToRegister(input)); 3655 DeoptimizeIf(NegateCondition(cc), instr->environment()); 3656} 3657 3658 3659void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { 3660 LOperand* input = instr->InputAt(0); 3661 Condition cc = masm()->CheckSmi(ToRegister(input)); 3662 DeoptimizeIf(cc, instr->environment()); 3663} 3664 3665 3666void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { 3667 Register input = ToRegister(instr->InputAt(0)); 3668 3669 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); 3670 3671 if (instr->hydrogen()->is_interval_check()) { 3672 InstanceType first; 3673 InstanceType last; 3674 instr->hydrogen()->GetCheckInterval(&first, &last); 3675 3676 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), 3677 Immediate(static_cast<int8_t>(first))); 3678 3679 // If there is only one type in the interval check for equality. 3680 if (first == last) { 3681 DeoptimizeIf(not_equal, instr->environment()); 3682 } else { 3683 DeoptimizeIf(below, instr->environment()); 3684 // Omit check for the last type. 3685 if (last != LAST_TYPE) { 3686 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), 3687 Immediate(static_cast<int8_t>(last))); 3688 DeoptimizeIf(above, instr->environment()); 3689 } 3690 } 3691 } else { 3692 uint8_t mask; 3693 uint8_t tag; 3694 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); 3695 3696 if (IsPowerOf2(mask)) { 3697 ASSERT(tag == 0 || IsPowerOf2(tag)); 3698 __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), 3699 Immediate(mask)); 3700 DeoptimizeIf(tag == 0 ? not_zero : zero, instr->environment()); 3701 } else { 3702 __ movzxbl(kScratchRegister, 3703 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); 3704 __ andb(kScratchRegister, Immediate(mask)); 3705 __ cmpb(kScratchRegister, Immediate(tag)); 3706 DeoptimizeIf(not_equal, instr->environment()); 3707 } 3708 } 3709} 3710 3711 3712void LCodeGen::DoCheckFunction(LCheckFunction* instr) { 3713 ASSERT(instr->InputAt(0)->IsRegister()); 3714 Register reg = ToRegister(instr->InputAt(0)); 3715 __ Cmp(reg, instr->hydrogen()->target()); 3716 DeoptimizeIf(not_equal, instr->environment()); 3717} 3718 3719 3720void LCodeGen::DoCheckMap(LCheckMap* instr) { 3721 LOperand* input = instr->InputAt(0); 3722 ASSERT(input->IsRegister()); 3723 Register reg = ToRegister(input); 3724 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), 3725 instr->hydrogen()->map()); 3726 DeoptimizeIf(not_equal, instr->environment()); 3727} 3728 3729 3730void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { 3731 XMMRegister value_reg = ToDoubleRegister(instr->unclamped()); 3732 Register result_reg = ToRegister(instr->result()); 3733 Register temp_reg = ToRegister(instr->TempAt(0)); 3734 __ ClampDoubleToUint8(value_reg, xmm0, result_reg, temp_reg); 3735} 3736 3737 3738void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { 3739 ASSERT(instr->unclamped()->Equals(instr->result())); 3740 Register value_reg = ToRegister(instr->result()); 3741 __ ClampUint8(value_reg); 3742} 3743 3744 3745void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { 3746 ASSERT(instr->unclamped()->Equals(instr->result())); 3747 Register input_reg = ToRegister(instr->unclamped()); 3748 Register temp_reg = ToRegister(instr->TempAt(0)); 3749 XMMRegister temp_xmm_reg = ToDoubleRegister(instr->TempAt(1)); 3750 Label is_smi, done, heap_number; 3751 3752 __ JumpIfSmi(input_reg, &is_smi); 3753 3754 // Check for heap number 3755 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset), 3756 factory()->heap_number_map()); 3757 __ j(equal, &heap_number, Label::kNear); 3758 3759 // Check for undefined. Undefined is converted to zero for clamping 3760 // conversions. 3761 __ Cmp(input_reg, factory()->undefined_value()); 3762 DeoptimizeIf(not_equal, instr->environment()); 3763 __ movq(input_reg, Immediate(0)); 3764 __ jmp(&done, Label::kNear); 3765 3766 // Heap number 3767 __ bind(&heap_number); 3768 __ movsd(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset)); 3769 __ ClampDoubleToUint8(xmm0, temp_xmm_reg, input_reg, temp_reg); 3770 __ jmp(&done, Label::kNear); 3771 3772 // smi 3773 __ bind(&is_smi); 3774 __ SmiToInteger32(input_reg, input_reg); 3775 __ ClampUint8(input_reg); 3776 3777 __ bind(&done); 3778} 3779 3780 3781void LCodeGen::LoadHeapObject(Register result, Handle<HeapObject> object) { 3782 if (heap()->InNewSpace(*object)) { 3783 Handle<JSGlobalPropertyCell> cell = 3784 factory()->NewJSGlobalPropertyCell(object); 3785 __ movq(result, cell, RelocInfo::GLOBAL_PROPERTY_CELL); 3786 __ movq(result, Operand(result, 0)); 3787 } else { 3788 __ Move(result, object); 3789 } 3790} 3791 3792 3793void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) { 3794 Register reg = ToRegister(instr->TempAt(0)); 3795 3796 Handle<JSObject> holder = instr->holder(); 3797 Handle<JSObject> current_prototype = instr->prototype(); 3798 3799 // Load prototype object. 3800 LoadHeapObject(reg, current_prototype); 3801 3802 // Check prototype maps up to the holder. 3803 while (!current_prototype.is_identical_to(holder)) { 3804 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), 3805 Handle<Map>(current_prototype->map())); 3806 DeoptimizeIf(not_equal, instr->environment()); 3807 current_prototype = 3808 Handle<JSObject>(JSObject::cast(current_prototype->GetPrototype())); 3809 // Load next prototype object. 3810 LoadHeapObject(reg, current_prototype); 3811 } 3812 3813 // Check the holder map. 3814 __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), 3815 Handle<Map>(current_prototype->map())); 3816 DeoptimizeIf(not_equal, instr->environment()); 3817} 3818 3819 3820void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { 3821 Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements(); 3822 ASSERT_EQ(2, constant_elements->length()); 3823 ElementsKind constant_elements_kind = 3824 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); 3825 3826 // Setup the parameters to the stub/runtime call. 3827 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 3828 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); 3829 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); 3830 __ Push(instr->hydrogen()->constant_elements()); 3831 3832 // Pick the right runtime function or stub to call. 3833 int length = instr->hydrogen()->length(); 3834 if (instr->hydrogen()->IsCopyOnWrite()) { 3835 ASSERT(instr->hydrogen()->depth() == 1); 3836 FastCloneShallowArrayStub::Mode mode = 3837 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS; 3838 FastCloneShallowArrayStub stub(mode, length); 3839 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 3840 } else if (instr->hydrogen()->depth() > 1) { 3841 CallRuntime(Runtime::kCreateArrayLiteral, 3, instr); 3842 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { 3843 CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); 3844 } else { 3845 FastCloneShallowArrayStub::Mode mode = 3846 constant_elements_kind == FAST_DOUBLE_ELEMENTS 3847 ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS 3848 : FastCloneShallowArrayStub::CLONE_ELEMENTS; 3849 FastCloneShallowArrayStub stub(mode, length); 3850 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 3851 } 3852} 3853 3854 3855void LCodeGen::EmitDeepCopy(Handle<JSObject> object, 3856 Register result, 3857 Register source, 3858 int* offset) { 3859 ASSERT(!source.is(rcx)); 3860 ASSERT(!result.is(rcx)); 3861 3862 // Increase the offset so that subsequent objects end up right after 3863 // this one. 3864 int current_offset = *offset; 3865 int size = object->map()->instance_size(); 3866 *offset += size; 3867 3868 // Copy object header. 3869 ASSERT(object->properties()->length() == 0); 3870 ASSERT(object->elements()->length() == 0 || 3871 object->elements()->map() == isolate()->heap()->fixed_cow_array_map()); 3872 int inobject_properties = object->map()->inobject_properties(); 3873 int header_size = size - inobject_properties * kPointerSize; 3874 for (int i = 0; i < header_size; i += kPointerSize) { 3875 __ movq(rcx, FieldOperand(source, i)); 3876 __ movq(FieldOperand(result, current_offset + i), rcx); 3877 } 3878 3879 // Copy in-object properties. 3880 for (int i = 0; i < inobject_properties; i++) { 3881 int total_offset = current_offset + object->GetInObjectPropertyOffset(i); 3882 Handle<Object> value = Handle<Object>(object->InObjectPropertyAt(i)); 3883 if (value->IsJSObject()) { 3884 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 3885 __ lea(rcx, Operand(result, *offset)); 3886 __ movq(FieldOperand(result, total_offset), rcx); 3887 LoadHeapObject(source, value_object); 3888 EmitDeepCopy(value_object, result, source, offset); 3889 } else if (value->IsHeapObject()) { 3890 LoadHeapObject(rcx, Handle<HeapObject>::cast(value)); 3891 __ movq(FieldOperand(result, total_offset), rcx); 3892 } else { 3893 __ movq(rcx, value, RelocInfo::NONE); 3894 __ movq(FieldOperand(result, total_offset), rcx); 3895 } 3896 } 3897} 3898 3899 3900void LCodeGen::DoObjectLiteralFast(LObjectLiteralFast* instr) { 3901 int size = instr->hydrogen()->total_size(); 3902 3903 // Allocate all objects that are part of the literal in one big 3904 // allocation. This avoids multiple limit checks. 3905 Label allocated, runtime_allocate; 3906 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); 3907 __ jmp(&allocated); 3908 3909 __ bind(&runtime_allocate); 3910 __ Push(Smi::FromInt(size)); 3911 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); 3912 3913 __ bind(&allocated); 3914 int offset = 0; 3915 LoadHeapObject(rbx, instr->hydrogen()->boilerplate()); 3916 EmitDeepCopy(instr->hydrogen()->boilerplate(), rax, rbx, &offset); 3917 ASSERT_EQ(size, offset); 3918} 3919 3920 3921void LCodeGen::DoObjectLiteralGeneric(LObjectLiteralGeneric* instr) { 3922 Handle<FixedArray> constant_properties = 3923 instr->hydrogen()->constant_properties(); 3924 3925 // Setup the parameters to the stub/runtime call. 3926 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 3927 __ push(FieldOperand(rax, JSFunction::kLiteralsOffset)); 3928 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); 3929 __ Push(constant_properties); 3930 int flags = instr->hydrogen()->fast_elements() 3931 ? ObjectLiteral::kFastElements 3932 : ObjectLiteral::kNoFlags; 3933 flags |= instr->hydrogen()->has_function() 3934 ? ObjectLiteral::kHasFunction 3935 : ObjectLiteral::kNoFlags; 3936 __ Push(Smi::FromInt(flags)); 3937 3938 // Pick the right runtime function to call. 3939 int properties_count = constant_properties->length() / 2; 3940 if (instr->hydrogen()->depth() > 1) { 3941 CallRuntime(Runtime::kCreateObjectLiteral, 4, instr); 3942 } else if (flags != ObjectLiteral::kFastElements || 3943 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) { 3944 CallRuntime(Runtime::kCreateObjectLiteralShallow, 4, instr); 3945 } else { 3946 FastCloneShallowObjectStub stub(properties_count); 3947 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 3948 } 3949} 3950 3951 3952void LCodeGen::DoToFastProperties(LToFastProperties* instr) { 3953 ASSERT(ToRegister(instr->InputAt(0)).is(rax)); 3954 __ push(rax); 3955 CallRuntime(Runtime::kToFastProperties, 1, instr); 3956} 3957 3958 3959void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { 3960 Label materialized; 3961 // Registers will be used as follows: 3962 // rdi = JS function. 3963 // rcx = literals array. 3964 // rbx = regexp literal. 3965 // rax = regexp literal clone. 3966 __ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 3967 __ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset)); 3968 int literal_offset = FixedArray::kHeaderSize + 3969 instr->hydrogen()->literal_index() * kPointerSize; 3970 __ movq(rbx, FieldOperand(rcx, literal_offset)); 3971 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); 3972 __ j(not_equal, &materialized, Label::kNear); 3973 3974 // Create regexp literal using runtime function 3975 // Result will be in rax. 3976 __ push(rcx); 3977 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); 3978 __ Push(instr->hydrogen()->pattern()); 3979 __ Push(instr->hydrogen()->flags()); 3980 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); 3981 __ movq(rbx, rax); 3982 3983 __ bind(&materialized); 3984 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 3985 Label allocated, runtime_allocate; 3986 __ AllocateInNewSpace(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); 3987 __ jmp(&allocated); 3988 3989 __ bind(&runtime_allocate); 3990 __ push(rbx); 3991 __ Push(Smi::FromInt(size)); 3992 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); 3993 __ pop(rbx); 3994 3995 __ bind(&allocated); 3996 // Copy the content into the newly allocated memory. 3997 // (Unroll copy loop once for better throughput). 3998 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { 3999 __ movq(rdx, FieldOperand(rbx, i)); 4000 __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); 4001 __ movq(FieldOperand(rax, i), rdx); 4002 __ movq(FieldOperand(rax, i + kPointerSize), rcx); 4003 } 4004 if ((size % (2 * kPointerSize)) != 0) { 4005 __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); 4006 __ movq(FieldOperand(rax, size - kPointerSize), rdx); 4007 } 4008} 4009 4010 4011void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { 4012 // Use the fast case closure allocation code that allocates in new 4013 // space for nested functions that don't need literals cloning. 4014 Handle<SharedFunctionInfo> shared_info = instr->shared_info(); 4015 bool pretenure = instr->hydrogen()->pretenure(); 4016 if (!pretenure && shared_info->num_literals() == 0) { 4017 FastNewClosureStub stub(shared_info->language_mode()); 4018 __ Push(shared_info); 4019 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4020 } else { 4021 __ push(rsi); 4022 __ Push(shared_info); 4023 __ PushRoot(pretenure ? 4024 Heap::kTrueValueRootIndex : 4025 Heap::kFalseValueRootIndex); 4026 CallRuntime(Runtime::kNewClosure, 3, instr); 4027 } 4028} 4029 4030 4031void LCodeGen::DoTypeof(LTypeof* instr) { 4032 LOperand* input = instr->InputAt(0); 4033 EmitPushTaggedOperand(input); 4034 CallRuntime(Runtime::kTypeof, 1, instr); 4035} 4036 4037 4038void LCodeGen::EmitPushTaggedOperand(LOperand* operand) { 4039 ASSERT(!operand->IsDoubleRegister()); 4040 if (operand->IsConstantOperand()) { 4041 __ Push(ToHandle(LConstantOperand::cast(operand))); 4042 } else if (operand->IsRegister()) { 4043 __ push(ToRegister(operand)); 4044 } else { 4045 __ push(ToOperand(operand)); 4046 } 4047} 4048 4049 4050void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { 4051 Register input = ToRegister(instr->InputAt(0)); 4052 int true_block = chunk_->LookupDestination(instr->true_block_id()); 4053 int false_block = chunk_->LookupDestination(instr->false_block_id()); 4054 Label* true_label = chunk_->GetAssemblyLabel(true_block); 4055 Label* false_label = chunk_->GetAssemblyLabel(false_block); 4056 4057 Condition final_branch_condition = 4058 EmitTypeofIs(true_label, false_label, input, instr->type_literal()); 4059 if (final_branch_condition != no_condition) { 4060 EmitBranch(true_block, false_block, final_branch_condition); 4061 } 4062} 4063 4064 4065Condition LCodeGen::EmitTypeofIs(Label* true_label, 4066 Label* false_label, 4067 Register input, 4068 Handle<String> type_name) { 4069 Condition final_branch_condition = no_condition; 4070 if (type_name->Equals(heap()->number_symbol())) { 4071 __ JumpIfSmi(input, true_label); 4072 __ CompareRoot(FieldOperand(input, HeapObject::kMapOffset), 4073 Heap::kHeapNumberMapRootIndex); 4074 4075 final_branch_condition = equal; 4076 4077 } else if (type_name->Equals(heap()->string_symbol())) { 4078 __ JumpIfSmi(input, false_label); 4079 __ CmpObjectType(input, FIRST_NONSTRING_TYPE, input); 4080 __ j(above_equal, false_label); 4081 __ testb(FieldOperand(input, Map::kBitFieldOffset), 4082 Immediate(1 << Map::kIsUndetectable)); 4083 final_branch_condition = zero; 4084 4085 } else if (type_name->Equals(heap()->boolean_symbol())) { 4086 __ CompareRoot(input, Heap::kTrueValueRootIndex); 4087 __ j(equal, true_label); 4088 __ CompareRoot(input, Heap::kFalseValueRootIndex); 4089 final_branch_condition = equal; 4090 4091 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) { 4092 __ CompareRoot(input, Heap::kNullValueRootIndex); 4093 final_branch_condition = equal; 4094 4095 } else if (type_name->Equals(heap()->undefined_symbol())) { 4096 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); 4097 __ j(equal, true_label); 4098 __ JumpIfSmi(input, false_label); 4099 // Check for undetectable objects => true. 4100 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); 4101 __ testb(FieldOperand(input, Map::kBitFieldOffset), 4102 Immediate(1 << Map::kIsUndetectable)); 4103 final_branch_condition = not_zero; 4104 4105 } else if (type_name->Equals(heap()->function_symbol())) { 4106 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); 4107 __ JumpIfSmi(input, false_label); 4108 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); 4109 __ j(equal, true_label); 4110 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); 4111 final_branch_condition = equal; 4112 4113 } else if (type_name->Equals(heap()->object_symbol())) { 4114 __ JumpIfSmi(input, false_label); 4115 if (!FLAG_harmony_typeof) { 4116 __ CompareRoot(input, Heap::kNullValueRootIndex); 4117 __ j(equal, true_label); 4118 } 4119 __ CmpObjectType(input, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, input); 4120 __ j(below, false_label); 4121 __ CmpInstanceType(input, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); 4122 __ j(above, false_label); 4123 // Check for undetectable objects => false. 4124 __ testb(FieldOperand(input, Map::kBitFieldOffset), 4125 Immediate(1 << Map::kIsUndetectable)); 4126 final_branch_condition = zero; 4127 4128 } else { 4129 __ jmp(false_label); 4130 } 4131 4132 return final_branch_condition; 4133} 4134 4135 4136void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { 4137 Register temp = ToRegister(instr->TempAt(0)); 4138 int true_block = chunk_->LookupDestination(instr->true_block_id()); 4139 int false_block = chunk_->LookupDestination(instr->false_block_id()); 4140 4141 EmitIsConstructCall(temp); 4142 EmitBranch(true_block, false_block, equal); 4143} 4144 4145 4146void LCodeGen::EmitIsConstructCall(Register temp) { 4147 // Get the frame pointer for the calling frame. 4148 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 4149 4150 // Skip the arguments adaptor frame if it exists. 4151 Label check_frame_marker; 4152 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset), 4153 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 4154 __ j(not_equal, &check_frame_marker, Label::kNear); 4155 __ movq(temp, Operand(rax, StandardFrameConstants::kCallerFPOffset)); 4156 4157 // Check the marker in the calling frame. 4158 __ bind(&check_frame_marker); 4159 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), 4160 Smi::FromInt(StackFrame::CONSTRUCT)); 4161} 4162 4163 4164void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { 4165 // Ensure that we have enough space after the previous lazy-bailout 4166 // instruction for patching the code here. 4167 int current_pc = masm()->pc_offset(); 4168 if (current_pc < last_lazy_deopt_pc_ + space_needed) { 4169 int padding_size = last_lazy_deopt_pc_ + space_needed - current_pc; 4170 while (padding_size > 0) { 4171 int nop_size = padding_size > 9 ? 9 : padding_size; 4172 __ nop(nop_size); 4173 padding_size -= nop_size; 4174 } 4175 } 4176} 4177 4178 4179void LCodeGen::DoLazyBailout(LLazyBailout* instr) { 4180 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 4181 last_lazy_deopt_pc_ = masm()->pc_offset(); 4182 ASSERT(instr->HasEnvironment()); 4183 LEnvironment* env = instr->environment(); 4184 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 4185 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 4186} 4187 4188 4189void LCodeGen::DoDeoptimize(LDeoptimize* instr) { 4190 DeoptimizeIf(no_condition, instr->environment()); 4191} 4192 4193 4194void LCodeGen::DoDeleteProperty(LDeleteProperty* instr) { 4195 LOperand* obj = instr->object(); 4196 LOperand* key = instr->key(); 4197 EmitPushTaggedOperand(obj); 4198 EmitPushTaggedOperand(key); 4199 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); 4200 LPointerMap* pointers = instr->pointer_map(); 4201 RecordPosition(pointers->position()); 4202 // Create safepoint generator that will also ensure enough space in the 4203 // reloc info for patching in deoptimization (since this is invoking a 4204 // builtin) 4205 SafepointGenerator safepoint_generator( 4206 this, pointers, Safepoint::kLazyDeopt); 4207 __ Push(Smi::FromInt(strict_mode_flag())); 4208 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator); 4209} 4210 4211 4212void LCodeGen::DoIn(LIn* instr) { 4213 LOperand* obj = instr->object(); 4214 LOperand* key = instr->key(); 4215 EmitPushTaggedOperand(key); 4216 EmitPushTaggedOperand(obj); 4217 ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment()); 4218 LPointerMap* pointers = instr->pointer_map(); 4219 RecordPosition(pointers->position()); 4220 SafepointGenerator safepoint_generator( 4221 this, pointers, Safepoint::kLazyDeopt); 4222 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator); 4223} 4224 4225 4226void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { 4227 PushSafepointRegistersScope scope(this); 4228 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); 4229 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); 4230 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); 4231 ASSERT(instr->HasEnvironment()); 4232 LEnvironment* env = instr->environment(); 4233 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 4234} 4235 4236 4237void LCodeGen::DoStackCheck(LStackCheck* instr) { 4238 class DeferredStackCheck: public LDeferredCode { 4239 public: 4240 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) 4241 : LDeferredCode(codegen), instr_(instr) { } 4242 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } 4243 virtual LInstruction* instr() { return instr_; } 4244 private: 4245 LStackCheck* instr_; 4246 }; 4247 4248 ASSERT(instr->HasEnvironment()); 4249 LEnvironment* env = instr->environment(); 4250 // There is no LLazyBailout instruction for stack-checks. We have to 4251 // prepare for lazy deoptimization explicitly here. 4252 if (instr->hydrogen()->is_function_entry()) { 4253 // Perform stack overflow check. 4254 Label done; 4255 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 4256 __ j(above_equal, &done, Label::kNear); 4257 StackCheckStub stub; 4258 CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); 4259 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 4260 last_lazy_deopt_pc_ = masm()->pc_offset(); 4261 __ bind(&done); 4262 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 4263 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 4264 } else { 4265 ASSERT(instr->hydrogen()->is_backwards_branch()); 4266 // Perform stack overflow check if this goto needs it before jumping. 4267 DeferredStackCheck* deferred_stack_check = 4268 new DeferredStackCheck(this, instr); 4269 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); 4270 __ j(below, deferred_stack_check->entry()); 4271 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 4272 last_lazy_deopt_pc_ = masm()->pc_offset(); 4273 __ bind(instr->done_label()); 4274 deferred_stack_check->SetExit(instr->done_label()); 4275 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 4276 // Don't record a deoptimization index for the safepoint here. 4277 // This will be done explicitly when emitting call and the safepoint in 4278 // the deferred code. 4279 } 4280} 4281 4282 4283void LCodeGen::DoOsrEntry(LOsrEntry* instr) { 4284 // This is a pseudo-instruction that ensures that the environment here is 4285 // properly registered for deoptimization and records the assembler's PC 4286 // offset. 4287 LEnvironment* environment = instr->environment(); 4288 environment->SetSpilledRegisters(instr->SpilledRegisterArray(), 4289 instr->SpilledDoubleRegisterArray()); 4290 4291 // If the environment were already registered, we would have no way of 4292 // backpatching it with the spill slot operands. 4293 ASSERT(!environment->HasBeenRegistered()); 4294 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 4295 ASSERT(osr_pc_offset_ == -1); 4296 osr_pc_offset_ = masm()->pc_offset(); 4297} 4298 4299#undef __ 4300 4301} } // namespace v8::internal 4302 4303#endif // V8_TARGET_ARCH_X64 4304