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