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 #include "mips/lithium-codegen-mips.h" 31 #include "mips/lithium-gap-resolver-mips.h" 32 #include "code-stubs.h" 33 #include "stub-cache.h" 34 35 namespace v8 { 36 namespace internal { 37 38 39 class SafepointGenerator : public CallWrapper { 40 public: 41 SafepointGenerator(LCodeGen* codegen, 42 LPointerMap* pointers, 43 Safepoint::DeoptMode mode) 44 : codegen_(codegen), 45 pointers_(pointers), 46 deopt_mode_(mode) { } 47 virtual ~SafepointGenerator() { } 48 49 virtual void BeforeCall(int call_size) const { } 50 51 virtual void AfterCall() const { 52 codegen_->RecordSafepoint(pointers_, deopt_mode_); 53 } 54 55 private: 56 LCodeGen* codegen_; 57 LPointerMap* pointers_; 58 Safepoint::DeoptMode deopt_mode_; 59 }; 60 61 62 #define __ masm()-> 63 64 bool LCodeGen::GenerateCode() { 65 LPhase phase("Z_Code generation", chunk()); 66 ASSERT(is_unused()); 67 status_ = GENERATING; 68 69 // Open a frame scope to indicate that there is a frame on the stack. The 70 // NONE indicates that the scope shouldn't actually generate code to set up 71 // the frame (that is done in GeneratePrologue). 72 FrameScope frame_scope(masm_, StackFrame::NONE); 73 74 return GeneratePrologue() && 75 GenerateBody() && 76 GenerateDeferredCode() && 77 GenerateDeoptJumpTable() && 78 GenerateSafepointTable(); 79 } 80 81 82 void LCodeGen::FinishCode(Handle<Code> code) { 83 ASSERT(is_done()); 84 code->set_stack_slots(GetStackSlotCount()); 85 code->set_safepoint_table_offset(safepoints_.GetCodeOffset()); 86 if (FLAG_weak_embedded_maps_in_optimized_code) { 87 RegisterDependentCodeForEmbeddedMaps(code); 88 } 89 PopulateDeoptimizationData(code); 90 info()->CommitDependencies(code); 91 } 92 93 94 void LChunkBuilder::Abort(BailoutReason reason) { 95 info()->set_bailout_reason(reason); 96 status_ = ABORTED; 97 } 98 99 100 void LCodeGen::Comment(const char* format, ...) { 101 if (!FLAG_code_comments) return; 102 char buffer[4 * KB]; 103 StringBuilder builder(buffer, ARRAY_SIZE(buffer)); 104 va_list arguments; 105 va_start(arguments, format); 106 builder.AddFormattedList(format, arguments); 107 va_end(arguments); 108 109 // Copy the string before recording it in the assembler to avoid 110 // issues when the stack allocated buffer goes out of scope. 111 size_t length = builder.position(); 112 Vector<char> copy = Vector<char>::New(length + 1); 113 OS::MemCopy(copy.start(), builder.Finalize(), copy.length()); 114 masm()->RecordComment(copy.start()); 115 } 116 117 118 bool LCodeGen::GeneratePrologue() { 119 ASSERT(is_generating()); 120 121 if (info()->IsOptimizing()) { 122 ProfileEntryHookStub::MaybeCallEntryHook(masm_); 123 124 #ifdef DEBUG 125 if (strlen(FLAG_stop_at) > 0 && 126 info_->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { 127 __ stop("stop_at"); 128 } 129 #endif 130 131 // a1: Callee's JS function. 132 // cp: Callee's context. 133 // fp: Caller's frame pointer. 134 // lr: Caller's pc. 135 136 // Strict mode functions and builtins need to replace the receiver 137 // with undefined when called as functions (without an explicit 138 // receiver object). r5 is zero for method calls and non-zero for 139 // function calls. 140 if (!info_->is_classic_mode() || info_->is_native()) { 141 Label ok; 142 __ Branch(&ok, eq, t1, Operand(zero_reg)); 143 144 int receiver_offset = scope()->num_parameters() * kPointerSize; 145 __ LoadRoot(a2, Heap::kUndefinedValueRootIndex); 146 __ sw(a2, MemOperand(sp, receiver_offset)); 147 __ bind(&ok); 148 } 149 } 150 151 info()->set_prologue_offset(masm_->pc_offset()); 152 if (NeedsEagerFrame()) { 153 if (info()->IsStub()) { 154 __ Push(ra, fp, cp); 155 __ Push(Smi::FromInt(StackFrame::STUB)); 156 // Adjust FP to point to saved FP. 157 __ Addu(fp, sp, Operand(2 * kPointerSize)); 158 } else { 159 // The following three instructions must remain together and unmodified 160 // for code aging to work properly. 161 __ Push(ra, fp, cp, a1); 162 // Add unused nop to ensure prologue sequence is identical for 163 // full-codegen and lithium-codegen. 164 __ nop(Assembler::CODE_AGE_SEQUENCE_NOP); 165 // Adj. FP to point to saved FP. 166 __ Addu(fp, sp, Operand(2 * kPointerSize)); 167 } 168 frame_is_built_ = true; 169 info_->AddNoFrameRange(0, masm_->pc_offset()); 170 } 171 172 // Reserve space for the stack slots needed by the code. 173 int slots = GetStackSlotCount(); 174 if (slots > 0) { 175 if (FLAG_debug_code) { 176 __ Subu(sp, sp, Operand(slots * kPointerSize)); 177 __ push(a0); 178 __ push(a1); 179 __ Addu(a0, sp, Operand(slots * kPointerSize)); 180 __ li(a1, Operand(kSlotsZapValue)); 181 Label loop; 182 __ bind(&loop); 183 __ Subu(a0, a0, Operand(kPointerSize)); 184 __ sw(a1, MemOperand(a0, 2 * kPointerSize)); 185 __ Branch(&loop, ne, a0, Operand(sp)); 186 __ pop(a1); 187 __ pop(a0); 188 } else { 189 __ Subu(sp, sp, Operand(slots * kPointerSize)); 190 } 191 } 192 193 if (info()->saves_caller_doubles()) { 194 Comment(";;; Save clobbered callee double registers"); 195 int count = 0; 196 BitVector* doubles = chunk()->allocated_double_registers(); 197 BitVector::Iterator save_iterator(doubles); 198 while (!save_iterator.Done()) { 199 __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), 200 MemOperand(sp, count * kDoubleSize)); 201 save_iterator.Advance(); 202 count++; 203 } 204 } 205 206 // Possibly allocate a local context. 207 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 208 if (heap_slots > 0) { 209 Comment(";;; Allocate local context"); 210 // Argument to NewContext is the function, which is in a1. 211 __ push(a1); 212 if (heap_slots <= FastNewContextStub::kMaximumSlots) { 213 FastNewContextStub stub(heap_slots); 214 __ CallStub(&stub); 215 } else { 216 __ CallRuntime(Runtime::kNewFunctionContext, 1); 217 } 218 RecordSafepoint(Safepoint::kNoLazyDeopt); 219 // Context is returned in both v0 and cp. It replaces the context 220 // passed to us. It's saved in the stack and kept live in cp. 221 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 222 // Copy any necessary parameters into the context. 223 int num_parameters = scope()->num_parameters(); 224 for (int i = 0; i < num_parameters; i++) { 225 Variable* var = scope()->parameter(i); 226 if (var->IsContextSlot()) { 227 int parameter_offset = StandardFrameConstants::kCallerSPOffset + 228 (num_parameters - 1 - i) * kPointerSize; 229 // Load parameter from stack. 230 __ lw(a0, MemOperand(fp, parameter_offset)); 231 // Store it in the context. 232 MemOperand target = ContextOperand(cp, var->index()); 233 __ sw(a0, target); 234 // Update the write barrier. This clobbers a3 and a0. 235 __ RecordWriteContextSlot( 236 cp, target.offset(), a0, a3, GetRAState(), kSaveFPRegs); 237 } 238 } 239 Comment(";;; End allocate local context"); 240 } 241 242 // Trace the call. 243 if (FLAG_trace && info()->IsOptimizing()) { 244 __ CallRuntime(Runtime::kTraceEnter, 0); 245 } 246 return !is_aborted(); 247 } 248 249 250 bool LCodeGen::GenerateBody() { 251 ASSERT(is_generating()); 252 bool emit_instructions = true; 253 for (current_instruction_ = 0; 254 !is_aborted() && current_instruction_ < instructions_->length(); 255 current_instruction_++) { 256 LInstruction* instr = instructions_->at(current_instruction_); 257 258 // Don't emit code for basic blocks with a replacement. 259 if (instr->IsLabel()) { 260 emit_instructions = !LLabel::cast(instr)->HasReplacement(); 261 } 262 if (!emit_instructions) continue; 263 264 if (FLAG_code_comments && instr->HasInterestingComment(this)) { 265 Comment(";;; <@%d,#%d> %s", 266 current_instruction_, 267 instr->hydrogen_value()->id(), 268 instr->Mnemonic()); 269 } 270 271 RecordAndUpdatePosition(instr->position()); 272 273 instr->CompileToNative(this); 274 } 275 EnsureSpaceForLazyDeopt(); 276 last_lazy_deopt_pc_ = masm()->pc_offset(); 277 return !is_aborted(); 278 } 279 280 281 bool LCodeGen::GenerateDeferredCode() { 282 ASSERT(is_generating()); 283 if (deferred_.length() > 0) { 284 for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { 285 LDeferredCode* code = deferred_[i]; 286 287 int pos = instructions_->at(code->instruction_index())->position(); 288 RecordAndUpdatePosition(pos); 289 290 Comment(";;; <@%d,#%d> " 291 "-------------------- Deferred %s --------------------", 292 code->instruction_index(), 293 code->instr()->hydrogen_value()->id(), 294 code->instr()->Mnemonic()); 295 __ bind(code->entry()); 296 if (NeedsDeferredFrame()) { 297 Comment(";;; Build frame"); 298 ASSERT(!frame_is_built_); 299 ASSERT(info()->IsStub()); 300 frame_is_built_ = true; 301 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); 302 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); 303 __ push(scratch0()); 304 __ Addu(fp, sp, Operand(2 * kPointerSize)); 305 Comment(";;; Deferred code"); 306 } 307 code->Generate(); 308 if (NeedsDeferredFrame()) { 309 Comment(";;; Destroy frame"); 310 ASSERT(frame_is_built_); 311 __ pop(at); 312 __ MultiPop(cp.bit() | fp.bit() | ra.bit()); 313 frame_is_built_ = false; 314 } 315 __ jmp(code->exit()); 316 } 317 } 318 // Deferred code is the last part of the instruction sequence. Mark 319 // the generated code as done unless we bailed out. 320 if (!is_aborted()) status_ = DONE; 321 return !is_aborted(); 322 } 323 324 325 bool LCodeGen::GenerateDeoptJumpTable() { 326 // Check that the jump table is accessible from everywhere in the function 327 // code, i.e. that offsets to the table can be encoded in the 16bit signed 328 // immediate of a branch instruction. 329 // To simplify we consider the code size from the first instruction to the 330 // end of the jump table. 331 if (!is_int16((masm()->pc_offset() / Assembler::kInstrSize) + 332 deopt_jump_table_.length() * 12)) { 333 Abort(kGeneratedCodeIsTooLarge); 334 } 335 336 if (deopt_jump_table_.length() > 0) { 337 Comment(";;; -------------------- Jump table --------------------"); 338 } 339 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 340 Label table_start; 341 __ bind(&table_start); 342 Label needs_frame; 343 for (int i = 0; i < deopt_jump_table_.length(); i++) { 344 __ bind(&deopt_jump_table_[i].label); 345 Address entry = deopt_jump_table_[i].address; 346 Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type; 347 int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type); 348 if (id == Deoptimizer::kNotDeoptimizationEntry) { 349 Comment(";;; jump table entry %d.", i); 350 } else { 351 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); 352 } 353 __ li(t9, Operand(ExternalReference::ForDeoptEntry(entry))); 354 if (deopt_jump_table_[i].needs_frame) { 355 if (needs_frame.is_bound()) { 356 __ Branch(&needs_frame); 357 } else { 358 __ bind(&needs_frame); 359 __ MultiPush(cp.bit() | fp.bit() | ra.bit()); 360 // This variant of deopt can only be used with stubs. Since we don't 361 // have a function pointer to install in the stack frame that we're 362 // building, install a special marker there instead. 363 ASSERT(info()->IsStub()); 364 __ li(scratch0(), Operand(Smi::FromInt(StackFrame::STUB))); 365 __ push(scratch0()); 366 __ Addu(fp, sp, Operand(2 * kPointerSize)); 367 __ Call(t9); 368 } 369 } else { 370 __ Call(t9); 371 } 372 } 373 __ RecordComment("]"); 374 375 // The deoptimization jump table is the last part of the instruction 376 // sequence. Mark the generated code as done unless we bailed out. 377 if (!is_aborted()) status_ = DONE; 378 return !is_aborted(); 379 } 380 381 382 bool LCodeGen::GenerateSafepointTable() { 383 ASSERT(is_done()); 384 safepoints_.Emit(masm(), GetStackSlotCount()); 385 return !is_aborted(); 386 } 387 388 389 Register LCodeGen::ToRegister(int index) const { 390 return Register::FromAllocationIndex(index); 391 } 392 393 394 DoubleRegister LCodeGen::ToDoubleRegister(int index) const { 395 return DoubleRegister::FromAllocationIndex(index); 396 } 397 398 399 Register LCodeGen::ToRegister(LOperand* op) const { 400 ASSERT(op->IsRegister()); 401 return ToRegister(op->index()); 402 } 403 404 405 Register LCodeGen::EmitLoadRegister(LOperand* op, Register scratch) { 406 if (op->IsRegister()) { 407 return ToRegister(op->index()); 408 } else if (op->IsConstantOperand()) { 409 LConstantOperand* const_op = LConstantOperand::cast(op); 410 HConstant* constant = chunk_->LookupConstant(const_op); 411 Handle<Object> literal = constant->handle(); 412 Representation r = chunk_->LookupLiteralRepresentation(const_op); 413 if (r.IsInteger32()) { 414 ASSERT(literal->IsNumber()); 415 __ li(scratch, Operand(static_cast<int32_t>(literal->Number()))); 416 } else if (r.IsSmi()) { 417 ASSERT(constant->HasSmiValue()); 418 __ li(scratch, Operand(Smi::FromInt(constant->Integer32Value()))); 419 } else if (r.IsDouble()) { 420 Abort(kEmitLoadRegisterUnsupportedDoubleImmediate); 421 } else { 422 ASSERT(r.IsTagged()); 423 __ LoadObject(scratch, literal); 424 } 425 return scratch; 426 } else if (op->IsStackSlot() || op->IsArgument()) { 427 __ lw(scratch, ToMemOperand(op)); 428 return scratch; 429 } 430 UNREACHABLE(); 431 return scratch; 432 } 433 434 435 DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const { 436 ASSERT(op->IsDoubleRegister()); 437 return ToDoubleRegister(op->index()); 438 } 439 440 441 DoubleRegister LCodeGen::EmitLoadDoubleRegister(LOperand* op, 442 FloatRegister flt_scratch, 443 DoubleRegister dbl_scratch) { 444 if (op->IsDoubleRegister()) { 445 return ToDoubleRegister(op->index()); 446 } else if (op->IsConstantOperand()) { 447 LConstantOperand* const_op = LConstantOperand::cast(op); 448 HConstant* constant = chunk_->LookupConstant(const_op); 449 Handle<Object> literal = constant->handle(); 450 Representation r = chunk_->LookupLiteralRepresentation(const_op); 451 if (r.IsInteger32()) { 452 ASSERT(literal->IsNumber()); 453 __ li(at, Operand(static_cast<int32_t>(literal->Number()))); 454 __ mtc1(at, flt_scratch); 455 __ cvt_d_w(dbl_scratch, flt_scratch); 456 return dbl_scratch; 457 } else if (r.IsDouble()) { 458 Abort(kUnsupportedDoubleImmediate); 459 } else if (r.IsTagged()) { 460 Abort(kUnsupportedTaggedImmediate); 461 } 462 } else if (op->IsStackSlot() || op->IsArgument()) { 463 MemOperand mem_op = ToMemOperand(op); 464 __ ldc1(dbl_scratch, mem_op); 465 return dbl_scratch; 466 } 467 UNREACHABLE(); 468 return dbl_scratch; 469 } 470 471 472 Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const { 473 HConstant* constant = chunk_->LookupConstant(op); 474 ASSERT(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged()); 475 return constant->handle(); 476 } 477 478 479 bool LCodeGen::IsInteger32(LConstantOperand* op) const { 480 return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32(); 481 } 482 483 484 bool LCodeGen::IsSmi(LConstantOperand* op) const { 485 return chunk_->LookupLiteralRepresentation(op).IsSmi(); 486 } 487 488 489 int32_t LCodeGen::ToInteger32(LConstantOperand* op) const { 490 return ToRepresentation(op, Representation::Integer32()); 491 } 492 493 494 int32_t LCodeGen::ToRepresentation(LConstantOperand* op, 495 const Representation& r) const { 496 HConstant* constant = chunk_->LookupConstant(op); 497 int32_t value = constant->Integer32Value(); 498 if (r.IsInteger32()) return value; 499 ASSERT(r.IsSmiOrTagged()); 500 return reinterpret_cast<int32_t>(Smi::FromInt(value)); 501 } 502 503 504 Smi* LCodeGen::ToSmi(LConstantOperand* op) const { 505 HConstant* constant = chunk_->LookupConstant(op); 506 return Smi::FromInt(constant->Integer32Value()); 507 } 508 509 510 double LCodeGen::ToDouble(LConstantOperand* op) const { 511 HConstant* constant = chunk_->LookupConstant(op); 512 ASSERT(constant->HasDoubleValue()); 513 return constant->DoubleValue(); 514 } 515 516 517 Operand LCodeGen::ToOperand(LOperand* op) { 518 if (op->IsConstantOperand()) { 519 LConstantOperand* const_op = LConstantOperand::cast(op); 520 HConstant* constant = chunk()->LookupConstant(const_op); 521 Representation r = chunk_->LookupLiteralRepresentation(const_op); 522 if (r.IsSmi()) { 523 ASSERT(constant->HasSmiValue()); 524 return Operand(Smi::FromInt(constant->Integer32Value())); 525 } else if (r.IsInteger32()) { 526 ASSERT(constant->HasInteger32Value()); 527 return Operand(constant->Integer32Value()); 528 } else if (r.IsDouble()) { 529 Abort(kToOperandUnsupportedDoubleImmediate); 530 } 531 ASSERT(r.IsTagged()); 532 return Operand(constant->handle()); 533 } else if (op->IsRegister()) { 534 return Operand(ToRegister(op)); 535 } else if (op->IsDoubleRegister()) { 536 Abort(kToOperandIsDoubleRegisterUnimplemented); 537 return Operand(0); 538 } 539 // Stack slots not implemented, use ToMemOperand instead. 540 UNREACHABLE(); 541 return Operand(0); 542 } 543 544 545 MemOperand LCodeGen::ToMemOperand(LOperand* op) const { 546 ASSERT(!op->IsRegister()); 547 ASSERT(!op->IsDoubleRegister()); 548 ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot()); 549 return MemOperand(fp, StackSlotOffset(op->index())); 550 } 551 552 553 MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const { 554 ASSERT(op->IsDoubleStackSlot()); 555 return MemOperand(fp, StackSlotOffset(op->index()) + kPointerSize); 556 } 557 558 559 void LCodeGen::WriteTranslation(LEnvironment* environment, 560 Translation* translation) { 561 if (environment == NULL) return; 562 563 // The translation includes one command per value in the environment. 564 int translation_size = environment->translation_size(); 565 // The output frame height does not include the parameters. 566 int height = translation_size - environment->parameter_count(); 567 568 WriteTranslation(environment->outer(), translation); 569 bool has_closure_id = !info()->closure().is_null() && 570 !info()->closure().is_identical_to(environment->closure()); 571 int closure_id = has_closure_id 572 ? DefineDeoptimizationLiteral(environment->closure()) 573 : Translation::kSelfLiteralId; 574 575 switch (environment->frame_type()) { 576 case JS_FUNCTION: 577 translation->BeginJSFrame(environment->ast_id(), closure_id, height); 578 break; 579 case JS_CONSTRUCT: 580 translation->BeginConstructStubFrame(closure_id, translation_size); 581 break; 582 case JS_GETTER: 583 ASSERT(translation_size == 1); 584 ASSERT(height == 0); 585 translation->BeginGetterStubFrame(closure_id); 586 break; 587 case JS_SETTER: 588 ASSERT(translation_size == 2); 589 ASSERT(height == 0); 590 translation->BeginSetterStubFrame(closure_id); 591 break; 592 case STUB: 593 translation->BeginCompiledStubFrame(); 594 break; 595 case ARGUMENTS_ADAPTOR: 596 translation->BeginArgumentsAdaptorFrame(closure_id, translation_size); 597 break; 598 } 599 600 int object_index = 0; 601 int dematerialized_index = 0; 602 for (int i = 0; i < translation_size; ++i) { 603 LOperand* value = environment->values()->at(i); 604 AddToTranslation(environment, 605 translation, 606 value, 607 environment->HasTaggedValueAt(i), 608 environment->HasUint32ValueAt(i), 609 &object_index, 610 &dematerialized_index); 611 } 612 } 613 614 615 void LCodeGen::AddToTranslation(LEnvironment* environment, 616 Translation* translation, 617 LOperand* op, 618 bool is_tagged, 619 bool is_uint32, 620 int* object_index_pointer, 621 int* dematerialized_index_pointer) { 622 if (op == LEnvironment::materialization_marker()) { 623 int object_index = (*object_index_pointer)++; 624 if (environment->ObjectIsDuplicateAt(object_index)) { 625 int dupe_of = environment->ObjectDuplicateOfAt(object_index); 626 translation->DuplicateObject(dupe_of); 627 return; 628 } 629 int object_length = environment->ObjectLengthAt(object_index); 630 if (environment->ObjectIsArgumentsAt(object_index)) { 631 translation->BeginArgumentsObject(object_length); 632 } else { 633 translation->BeginCapturedObject(object_length); 634 } 635 int dematerialized_index = *dematerialized_index_pointer; 636 int env_offset = environment->translation_size() + dematerialized_index; 637 *dematerialized_index_pointer += object_length; 638 for (int i = 0; i < object_length; ++i) { 639 LOperand* value = environment->values()->at(env_offset + i); 640 AddToTranslation(environment, 641 translation, 642 value, 643 environment->HasTaggedValueAt(env_offset + i), 644 environment->HasUint32ValueAt(env_offset + i), 645 object_index_pointer, 646 dematerialized_index_pointer); 647 } 648 return; 649 } 650 651 if (op->IsStackSlot()) { 652 if (is_tagged) { 653 translation->StoreStackSlot(op->index()); 654 } else if (is_uint32) { 655 translation->StoreUint32StackSlot(op->index()); 656 } else { 657 translation->StoreInt32StackSlot(op->index()); 658 } 659 } else if (op->IsDoubleStackSlot()) { 660 translation->StoreDoubleStackSlot(op->index()); 661 } else if (op->IsArgument()) { 662 ASSERT(is_tagged); 663 int src_index = GetStackSlotCount() + op->index(); 664 translation->StoreStackSlot(src_index); 665 } else if (op->IsRegister()) { 666 Register reg = ToRegister(op); 667 if (is_tagged) { 668 translation->StoreRegister(reg); 669 } else if (is_uint32) { 670 translation->StoreUint32Register(reg); 671 } else { 672 translation->StoreInt32Register(reg); 673 } 674 } else if (op->IsDoubleRegister()) { 675 DoubleRegister reg = ToDoubleRegister(op); 676 translation->StoreDoubleRegister(reg); 677 } else if (op->IsConstantOperand()) { 678 HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op)); 679 int src_index = DefineDeoptimizationLiteral(constant->handle()); 680 translation->StoreLiteral(src_index); 681 } else { 682 UNREACHABLE(); 683 } 684 } 685 686 687 void LCodeGen::CallCode(Handle<Code> code, 688 RelocInfo::Mode mode, 689 LInstruction* instr) { 690 CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT); 691 } 692 693 694 void LCodeGen::CallCodeGeneric(Handle<Code> code, 695 RelocInfo::Mode mode, 696 LInstruction* instr, 697 SafepointMode safepoint_mode) { 698 EnsureSpaceForLazyDeopt(); 699 ASSERT(instr != NULL); 700 LPointerMap* pointers = instr->pointer_map(); 701 RecordPosition(pointers->position()); 702 __ Call(code, mode); 703 RecordSafepointWithLazyDeopt(instr, safepoint_mode); 704 } 705 706 707 void LCodeGen::CallRuntime(const Runtime::Function* function, 708 int num_arguments, 709 LInstruction* instr) { 710 ASSERT(instr != NULL); 711 LPointerMap* pointers = instr->pointer_map(); 712 ASSERT(pointers != NULL); 713 RecordPosition(pointers->position()); 714 715 __ CallRuntime(function, num_arguments); 716 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); 717 } 718 719 720 void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id, 721 int argc, 722 LInstruction* instr) { 723 __ CallRuntimeSaveDoubles(id); 724 RecordSafepointWithRegisters( 725 instr->pointer_map(), argc, Safepoint::kNoLazyDeopt); 726 } 727 728 729 void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment, 730 Safepoint::DeoptMode mode) { 731 if (!environment->HasBeenRegistered()) { 732 // Physical stack frame layout: 733 // -x ............. -4 0 ..................................... y 734 // [incoming arguments] [spill slots] [pushed outgoing arguments] 735 736 // Layout of the environment: 737 // 0 ..................................................... size-1 738 // [parameters] [locals] [expression stack including arguments] 739 740 // Layout of the translation: 741 // 0 ........................................................ size - 1 + 4 742 // [expression stack including arguments] [locals] [4 words] [parameters] 743 // |>------------ translation_size ------------<| 744 745 int frame_count = 0; 746 int jsframe_count = 0; 747 for (LEnvironment* e = environment; e != NULL; e = e->outer()) { 748 ++frame_count; 749 if (e->frame_type() == JS_FUNCTION) { 750 ++jsframe_count; 751 } 752 } 753 Translation translation(&translations_, frame_count, jsframe_count, zone()); 754 WriteTranslation(environment, &translation); 755 int deoptimization_index = deoptimizations_.length(); 756 int pc_offset = masm()->pc_offset(); 757 environment->Register(deoptimization_index, 758 translation.index(), 759 (mode == Safepoint::kLazyDeopt) ? pc_offset : -1); 760 deoptimizations_.Add(environment, zone()); 761 } 762 } 763 764 765 void LCodeGen::DeoptimizeIf(Condition condition, 766 LEnvironment* environment, 767 Deoptimizer::BailoutType bailout_type, 768 Register src1, 769 const Operand& src2) { 770 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 771 ASSERT(environment->HasBeenRegistered()); 772 int id = environment->deoptimization_index(); 773 ASSERT(info()->IsOptimizing() || info()->IsStub()); 774 Address entry = 775 Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type); 776 if (entry == NULL) { 777 Abort(kBailoutWasNotPrepared); 778 return; 779 } 780 781 ASSERT(FLAG_deopt_every_n_times < 2); // Other values not supported on MIPS. 782 if (FLAG_deopt_every_n_times == 1 && 783 !info()->IsStub() && 784 info()->opt_count() == id) { 785 ASSERT(frame_is_built_); 786 __ Call(entry, RelocInfo::RUNTIME_ENTRY); 787 return; 788 } 789 790 if (info()->ShouldTrapOnDeopt()) { 791 Label skip; 792 if (condition != al) { 793 __ Branch(&skip, NegateCondition(condition), src1, src2); 794 } 795 __ stop("trap_on_deopt"); 796 __ bind(&skip); 797 } 798 799 ASSERT(info()->IsStub() || frame_is_built_); 800 if (condition == al && frame_is_built_) { 801 __ Call(entry, RelocInfo::RUNTIME_ENTRY, condition, src1, src2); 802 } else { 803 // We often have several deopts to the same entry, reuse the last 804 // jump entry if this is the case. 805 if (deopt_jump_table_.is_empty() || 806 (deopt_jump_table_.last().address != entry) || 807 (deopt_jump_table_.last().bailout_type != bailout_type) || 808 (deopt_jump_table_.last().needs_frame != !frame_is_built_)) { 809 Deoptimizer::JumpTableEntry table_entry(entry, 810 bailout_type, 811 !frame_is_built_); 812 deopt_jump_table_.Add(table_entry, zone()); 813 } 814 __ Branch(&deopt_jump_table_.last().label, condition, src1, src2); 815 } 816 } 817 818 819 void LCodeGen::DeoptimizeIf(Condition condition, 820 LEnvironment* environment, 821 Register src1, 822 const Operand& src2) { 823 Deoptimizer::BailoutType bailout_type = info()->IsStub() 824 ? Deoptimizer::LAZY 825 : Deoptimizer::EAGER; 826 DeoptimizeIf(condition, environment, bailout_type, src1, src2); 827 } 828 829 830 void LCodeGen::RegisterDependentCodeForEmbeddedMaps(Handle<Code> code) { 831 ZoneList<Handle<Map> > maps(1, zone()); 832 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 833 for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) { 834 RelocInfo::Mode mode = it.rinfo()->rmode(); 835 if (mode == RelocInfo::EMBEDDED_OBJECT && 836 it.rinfo()->target_object()->IsMap()) { 837 Handle<Map> map(Map::cast(it.rinfo()->target_object())); 838 if (map->CanTransition()) { 839 maps.Add(map, zone()); 840 } 841 } 842 } 843 #ifdef VERIFY_HEAP 844 // This disables verification of weak embedded maps after full GC. 845 // AddDependentCode can cause a GC, which would observe the state where 846 // this code is not yet in the depended code lists of the embedded maps. 847 NoWeakEmbeddedMapsVerificationScope disable_verification_of_embedded_maps; 848 #endif 849 for (int i = 0; i < maps.length(); i++) { 850 maps.at(i)->AddDependentCode(DependentCode::kWeaklyEmbeddedGroup, code); 851 } 852 } 853 854 855 void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) { 856 int length = deoptimizations_.length(); 857 if (length == 0) return; 858 Handle<DeoptimizationInputData> data = 859 factory()->NewDeoptimizationInputData(length, TENURED); 860 861 Handle<ByteArray> translations = 862 translations_.CreateByteArray(isolate()->factory()); 863 data->SetTranslationByteArray(*translations); 864 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); 865 866 Handle<FixedArray> literals = 867 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED); 868 { AllowDeferredHandleDereference copy_handles; 869 for (int i = 0; i < deoptimization_literals_.length(); i++) { 870 literals->set(i, *deoptimization_literals_[i]); 871 } 872 data->SetLiteralArray(*literals); 873 } 874 875 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt())); 876 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); 877 878 // Populate the deoptimization entries. 879 for (int i = 0; i < length; i++) { 880 LEnvironment* env = deoptimizations_[i]; 881 data->SetAstId(i, env->ast_id()); 882 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); 883 data->SetArgumentsStackHeight(i, 884 Smi::FromInt(env->arguments_stack_height())); 885 data->SetPc(i, Smi::FromInt(env->pc_offset())); 886 } 887 code->set_deoptimization_data(*data); 888 } 889 890 891 int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) { 892 int result = deoptimization_literals_.length(); 893 for (int i = 0; i < deoptimization_literals_.length(); ++i) { 894 if (deoptimization_literals_[i].is_identical_to(literal)) return i; 895 } 896 deoptimization_literals_.Add(literal, zone()); 897 return result; 898 } 899 900 901 void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() { 902 ASSERT(deoptimization_literals_.length() == 0); 903 904 const ZoneList<Handle<JSFunction> >* inlined_closures = 905 chunk()->inlined_closures(); 906 907 for (int i = 0, length = inlined_closures->length(); 908 i < length; 909 i++) { 910 DefineDeoptimizationLiteral(inlined_closures->at(i)); 911 } 912 913 inlined_function_count_ = deoptimization_literals_.length(); 914 } 915 916 917 void LCodeGen::RecordSafepointWithLazyDeopt( 918 LInstruction* instr, SafepointMode safepoint_mode) { 919 if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) { 920 RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt); 921 } else { 922 ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 923 RecordSafepointWithRegisters( 924 instr->pointer_map(), 0, Safepoint::kLazyDeopt); 925 } 926 } 927 928 929 void LCodeGen::RecordSafepoint( 930 LPointerMap* pointers, 931 Safepoint::Kind kind, 932 int arguments, 933 Safepoint::DeoptMode deopt_mode) { 934 ASSERT(expected_safepoint_kind_ == kind); 935 936 const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); 937 Safepoint safepoint = safepoints_.DefineSafepoint(masm(), 938 kind, arguments, deopt_mode); 939 for (int i = 0; i < operands->length(); i++) { 940 LOperand* pointer = operands->at(i); 941 if (pointer->IsStackSlot()) { 942 safepoint.DefinePointerSlot(pointer->index(), zone()); 943 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { 944 safepoint.DefinePointerRegister(ToRegister(pointer), zone()); 945 } 946 } 947 if (kind & Safepoint::kWithRegisters) { 948 // Register cp always contains a pointer to the context. 949 safepoint.DefinePointerRegister(cp, zone()); 950 } 951 } 952 953 954 void LCodeGen::RecordSafepoint(LPointerMap* pointers, 955 Safepoint::DeoptMode deopt_mode) { 956 RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode); 957 } 958 959 960 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) { 961 LPointerMap empty_pointers(RelocInfo::kNoPosition, zone()); 962 RecordSafepoint(&empty_pointers, deopt_mode); 963 } 964 965 966 void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers, 967 int arguments, 968 Safepoint::DeoptMode deopt_mode) { 969 RecordSafepoint( 970 pointers, Safepoint::kWithRegisters, arguments, deopt_mode); 971 } 972 973 974 void LCodeGen::RecordSafepointWithRegistersAndDoubles( 975 LPointerMap* pointers, 976 int arguments, 977 Safepoint::DeoptMode deopt_mode) { 978 RecordSafepoint( 979 pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode); 980 } 981 982 983 void LCodeGen::RecordPosition(int position) { 984 if (position == RelocInfo::kNoPosition) return; 985 masm()->positions_recorder()->RecordPosition(position); 986 } 987 988 989 void LCodeGen::RecordAndUpdatePosition(int position) { 990 if (position >= 0 && position != old_position_) { 991 masm()->positions_recorder()->RecordPosition(position); 992 old_position_ = position; 993 } 994 } 995 996 997 static const char* LabelType(LLabel* label) { 998 if (label->is_loop_header()) return " (loop header)"; 999 if (label->is_osr_entry()) return " (OSR entry)"; 1000 return ""; 1001 } 1002 1003 1004 void LCodeGen::DoLabel(LLabel* label) { 1005 Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------", 1006 current_instruction_, 1007 label->hydrogen_value()->id(), 1008 label->block_id(), 1009 LabelType(label)); 1010 __ bind(label->label()); 1011 current_block_ = label->block_id(); 1012 DoGap(label); 1013 } 1014 1015 1016 void LCodeGen::DoParallelMove(LParallelMove* move) { 1017 resolver_.Resolve(move); 1018 } 1019 1020 1021 void LCodeGen::DoGap(LGap* gap) { 1022 for (int i = LGap::FIRST_INNER_POSITION; 1023 i <= LGap::LAST_INNER_POSITION; 1024 i++) { 1025 LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i); 1026 LParallelMove* move = gap->GetParallelMove(inner_pos); 1027 if (move != NULL) DoParallelMove(move); 1028 } 1029 } 1030 1031 1032 void LCodeGen::DoInstructionGap(LInstructionGap* instr) { 1033 DoGap(instr); 1034 } 1035 1036 1037 void LCodeGen::DoParameter(LParameter* instr) { 1038 // Nothing to do. 1039 } 1040 1041 1042 void LCodeGen::DoCallStub(LCallStub* instr) { 1043 ASSERT(ToRegister(instr->result()).is(v0)); 1044 switch (instr->hydrogen()->major_key()) { 1045 case CodeStub::RegExpConstructResult: { 1046 RegExpConstructResultStub stub; 1047 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1048 break; 1049 } 1050 case CodeStub::RegExpExec: { 1051 RegExpExecStub stub; 1052 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1053 break; 1054 } 1055 case CodeStub::SubString: { 1056 SubStringStub stub; 1057 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1058 break; 1059 } 1060 case CodeStub::NumberToString: { 1061 NumberToStringStub stub; 1062 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1063 break; 1064 } 1065 case CodeStub::StringCompare: { 1066 StringCompareStub stub; 1067 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1068 break; 1069 } 1070 case CodeStub::TranscendentalCache: { 1071 __ lw(a0, MemOperand(sp, 0)); 1072 TranscendentalCacheStub stub(instr->transcendental_type(), 1073 TranscendentalCacheStub::TAGGED); 1074 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1075 break; 1076 } 1077 default: 1078 UNREACHABLE(); 1079 } 1080 } 1081 1082 1083 void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) { 1084 // Record the address of the first unknown OSR value as the place to enter. 1085 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); 1086 } 1087 1088 1089 void LCodeGen::DoModI(LModI* instr) { 1090 HMod* hmod = instr->hydrogen(); 1091 HValue* left = hmod->left(); 1092 HValue* right = hmod->right(); 1093 if (hmod->HasPowerOf2Divisor()) { 1094 const Register left_reg = ToRegister(instr->left()); 1095 const Register result_reg = ToRegister(instr->result()); 1096 1097 // Note: The code below even works when right contains kMinInt. 1098 int32_t divisor = Abs(right->GetInteger32Constant()); 1099 1100 Label left_is_not_negative, done; 1101 if (left->CanBeNegative()) { 1102 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT, 1103 &left_is_not_negative, ge, left_reg, Operand(zero_reg)); 1104 __ subu(result_reg, zero_reg, left_reg); 1105 __ And(result_reg, result_reg, divisor - 1); 1106 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1107 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); 1108 } 1109 __ Branch(USE_DELAY_SLOT, &done); 1110 __ subu(result_reg, zero_reg, result_reg); 1111 } 1112 1113 __ bind(&left_is_not_negative); 1114 __ And(result_reg, left_reg, divisor - 1); 1115 __ bind(&done); 1116 1117 } else if (hmod->fixed_right_arg().has_value) { 1118 const Register left_reg = ToRegister(instr->left()); 1119 const Register result_reg = ToRegister(instr->result()); 1120 const Register right_reg = ToRegister(instr->right()); 1121 1122 int32_t divisor = hmod->fixed_right_arg().value; 1123 ASSERT(IsPowerOf2(divisor)); 1124 1125 // Check if our assumption of a fixed right operand still holds. 1126 DeoptimizeIf(ne, instr->environment(), right_reg, Operand(divisor)); 1127 1128 Label left_is_not_negative, done; 1129 if (left->CanBeNegative()) { 1130 __ Branch(left_reg.is(result_reg) ? PROTECT : USE_DELAY_SLOT, 1131 &left_is_not_negative, ge, left_reg, Operand(zero_reg)); 1132 __ subu(result_reg, zero_reg, left_reg); 1133 __ And(result_reg, result_reg, divisor - 1); 1134 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1135 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); 1136 } 1137 __ Branch(USE_DELAY_SLOT, &done); 1138 __ subu(result_reg, zero_reg, result_reg); 1139 } 1140 1141 __ bind(&left_is_not_negative); 1142 __ And(result_reg, left_reg, divisor - 1); 1143 __ bind(&done); 1144 1145 } else { 1146 const Register scratch = scratch0(); 1147 const Register left_reg = ToRegister(instr->left()); 1148 const Register result_reg = ToRegister(instr->result()); 1149 1150 // div runs in the background while we check for special cases. 1151 Register right_reg = EmitLoadRegister(instr->right(), scratch); 1152 __ div(left_reg, right_reg); 1153 1154 Label done; 1155 // Check for x % 0, we have to deopt in this case because we can't return a 1156 // NaN. 1157 if (right->CanBeZero()) { 1158 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(zero_reg)); 1159 } 1160 1161 // Check for kMinInt % -1, we have to deopt if we care about -0, because we 1162 // can't return that. 1163 if (left->RangeCanInclude(kMinInt) && right->RangeCanInclude(-1)) { 1164 Label left_not_min_int; 1165 __ Branch(&left_not_min_int, ne, left_reg, Operand(kMinInt)); 1166 // TODO(svenpanne) Don't deopt when we don't care about -0. 1167 DeoptimizeIf(eq, instr->environment(), right_reg, Operand(-1)); 1168 __ bind(&left_not_min_int); 1169 } 1170 1171 // TODO(svenpanne) Only emit the test/deopt if we have to. 1172 __ Branch(USE_DELAY_SLOT, &done, ge, left_reg, Operand(zero_reg)); 1173 __ mfhi(result_reg); 1174 1175 if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) { 1176 DeoptimizeIf(eq, instr->environment(), result_reg, Operand(zero_reg)); 1177 } 1178 __ bind(&done); 1179 } 1180 } 1181 1182 1183 void LCodeGen::EmitSignedIntegerDivisionByConstant( 1184 Register result, 1185 Register dividend, 1186 int32_t divisor, 1187 Register remainder, 1188 Register scratch, 1189 LEnvironment* environment) { 1190 ASSERT(!AreAliased(dividend, scratch, at, no_reg)); 1191 1192 uint32_t divisor_abs = abs(divisor); 1193 1194 int32_t power_of_2_factor = 1195 CompilerIntrinsics::CountTrailingZeros(divisor_abs); 1196 1197 switch (divisor_abs) { 1198 case 0: 1199 DeoptimizeIf(al, environment); 1200 return; 1201 1202 case 1: 1203 if (divisor > 0) { 1204 __ Move(result, dividend); 1205 } else { 1206 __ SubuAndCheckForOverflow(result, zero_reg, dividend, scratch); 1207 DeoptimizeIf(lt, environment, scratch, Operand(zero_reg)); 1208 } 1209 // Compute the remainder. 1210 __ Move(remainder, zero_reg); 1211 return; 1212 1213 default: 1214 if (IsPowerOf2(divisor_abs)) { 1215 // Branch and condition free code for integer division by a power 1216 // of two. 1217 int32_t power = WhichPowerOf2(divisor_abs); 1218 if (power > 1) { 1219 __ sra(scratch, dividend, power - 1); 1220 } 1221 __ srl(scratch, scratch, 32 - power); 1222 __ Addu(scratch, dividend, Operand(scratch)); 1223 __ sra(result, scratch, power); 1224 // Negate if necessary. 1225 // We don't need to check for overflow because the case '-1' is 1226 // handled separately. 1227 if (divisor < 0) { 1228 ASSERT(divisor != -1); 1229 __ Subu(result, zero_reg, Operand(result)); 1230 } 1231 // Compute the remainder. 1232 if (divisor > 0) { 1233 __ sll(scratch, result, power); 1234 __ Subu(remainder, dividend, Operand(scratch)); 1235 } else { 1236 __ sll(scratch, result, power); 1237 __ Addu(remainder, dividend, Operand(scratch)); 1238 } 1239 return; 1240 } else if (LChunkBuilder::HasMagicNumberForDivisor(divisor)) { 1241 // Use magic numbers for a few specific divisors. 1242 // Details and proofs can be found in: 1243 // - Hacker's Delight, Henry S. Warren, Jr. 1244 // - The PowerPC Compiler Writer's Guide 1245 // and probably many others. 1246 // 1247 // We handle 1248 // <divisor with magic numbers> * <power of 2> 1249 // but not 1250 // <divisor with magic numbers> * <other divisor with magic numbers> 1251 DivMagicNumbers magic_numbers = 1252 DivMagicNumberFor(divisor_abs >> power_of_2_factor); 1253 // Branch and condition free code for integer division by a power 1254 // of two. 1255 const int32_t M = magic_numbers.M; 1256 const int32_t s = magic_numbers.s + power_of_2_factor; 1257 1258 __ li(scratch, Operand(M)); 1259 __ mult(dividend, scratch); 1260 __ mfhi(scratch); 1261 if (M < 0) { 1262 __ Addu(scratch, scratch, Operand(dividend)); 1263 } 1264 if (s > 0) { 1265 __ sra(scratch, scratch, s); 1266 __ mov(scratch, scratch); 1267 } 1268 __ srl(at, dividend, 31); 1269 __ Addu(result, scratch, Operand(at)); 1270 if (divisor < 0) __ Subu(result, zero_reg, Operand(result)); 1271 // Compute the remainder. 1272 __ li(scratch, Operand(divisor)); 1273 __ Mul(scratch, result, Operand(scratch)); 1274 __ Subu(remainder, dividend, Operand(scratch)); 1275 } else { 1276 __ li(scratch, Operand(divisor)); 1277 __ div(dividend, scratch); 1278 __ mfhi(remainder); 1279 __ mflo(result); 1280 } 1281 } 1282 } 1283 1284 1285 void LCodeGen::DoDivI(LDivI* instr) { 1286 const Register left = ToRegister(instr->left()); 1287 const Register right = ToRegister(instr->right()); 1288 const Register result = ToRegister(instr->result()); 1289 1290 // On MIPS div is asynchronous - it will run in the background while we 1291 // check for special cases. 1292 __ div(left, right); 1293 1294 // Check for x / 0. 1295 if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) { 1296 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); 1297 } 1298 1299 // Check for (0 / -x) that will produce negative zero. 1300 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1301 Label left_not_zero; 1302 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); 1303 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); 1304 __ bind(&left_not_zero); 1305 } 1306 1307 // Check for (kMinInt / -1). 1308 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1309 Label left_not_min_int; 1310 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); 1311 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); 1312 __ bind(&left_not_min_int); 1313 } 1314 1315 if (!instr->hydrogen()->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) { 1316 __ mfhi(result); 1317 DeoptimizeIf(ne, instr->environment(), result, Operand(zero_reg)); 1318 } 1319 __ mflo(result); 1320 } 1321 1322 1323 void LCodeGen::DoMultiplyAddD(LMultiplyAddD* instr) { 1324 DoubleRegister addend = ToDoubleRegister(instr->addend()); 1325 DoubleRegister multiplier = ToDoubleRegister(instr->multiplier()); 1326 DoubleRegister multiplicand = ToDoubleRegister(instr->multiplicand()); 1327 1328 // This is computed in-place. 1329 ASSERT(addend.is(ToDoubleRegister(instr->result()))); 1330 1331 __ madd_d(addend, addend, multiplier, multiplicand); 1332 } 1333 1334 1335 void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) { 1336 const Register result = ToRegister(instr->result()); 1337 const Register left = ToRegister(instr->left()); 1338 const Register remainder = ToRegister(instr->temp()); 1339 const Register scratch = scratch0(); 1340 1341 if (instr->right()->IsConstantOperand()) { 1342 Label done; 1343 int32_t divisor = ToInteger32(LConstantOperand::cast(instr->right())); 1344 if (divisor < 0) { 1345 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg)); 1346 } 1347 EmitSignedIntegerDivisionByConstant(result, 1348 left, 1349 divisor, 1350 remainder, 1351 scratch, 1352 instr->environment()); 1353 // We performed a truncating division. Correct the result if necessary. 1354 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); 1355 __ Xor(scratch , remainder, Operand(divisor)); 1356 __ Branch(&done, ge, scratch, Operand(zero_reg)); 1357 __ Subu(result, result, Operand(1)); 1358 __ bind(&done); 1359 } else { 1360 Label done; 1361 const Register right = ToRegister(instr->right()); 1362 1363 // On MIPS div is asynchronous - it will run in the background while we 1364 // check for special cases. 1365 __ div(left, right); 1366 1367 // Check for x / 0. 1368 DeoptimizeIf(eq, instr->environment(), right, Operand(zero_reg)); 1369 1370 // Check for (0 / -x) that will produce negative zero. 1371 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 1372 Label left_not_zero; 1373 __ Branch(&left_not_zero, ne, left, Operand(zero_reg)); 1374 DeoptimizeIf(lt, instr->environment(), right, Operand(zero_reg)); 1375 __ bind(&left_not_zero); 1376 } 1377 1378 // Check for (kMinInt / -1). 1379 if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) { 1380 Label left_not_min_int; 1381 __ Branch(&left_not_min_int, ne, left, Operand(kMinInt)); 1382 DeoptimizeIf(eq, instr->environment(), right, Operand(-1)); 1383 __ bind(&left_not_min_int); 1384 } 1385 1386 __ mfhi(remainder); 1387 __ mflo(result); 1388 1389 // We performed a truncating division. Correct the result if necessary. 1390 __ Branch(&done, eq, remainder, Operand(zero_reg), USE_DELAY_SLOT); 1391 __ Xor(scratch , remainder, Operand(right)); 1392 __ Branch(&done, ge, scratch, Operand(zero_reg)); 1393 __ Subu(result, result, Operand(1)); 1394 __ bind(&done); 1395 } 1396 } 1397 1398 1399 void LCodeGen::DoMulI(LMulI* instr) { 1400 Register scratch = scratch0(); 1401 Register result = ToRegister(instr->result()); 1402 // Note that result may alias left. 1403 Register left = ToRegister(instr->left()); 1404 LOperand* right_op = instr->right(); 1405 1406 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 1407 bool bailout_on_minus_zero = 1408 instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero); 1409 1410 if (right_op->IsConstantOperand() && !can_overflow) { 1411 // Use optimized code for specific constants. 1412 int32_t constant = ToRepresentation( 1413 LConstantOperand::cast(right_op), 1414 instr->hydrogen()->right()->representation()); 1415 1416 if (bailout_on_minus_zero && (constant < 0)) { 1417 // The case of a null constant will be handled separately. 1418 // If constant is negative and left is null, the result should be -0. 1419 DeoptimizeIf(eq, instr->environment(), left, Operand(zero_reg)); 1420 } 1421 1422 switch (constant) { 1423 case -1: 1424 __ Subu(result, zero_reg, left); 1425 break; 1426 case 0: 1427 if (bailout_on_minus_zero) { 1428 // If left is strictly negative and the constant is null, the 1429 // result is -0. Deoptimize if required, otherwise return 0. 1430 DeoptimizeIf(lt, instr->environment(), left, Operand(zero_reg)); 1431 } 1432 __ mov(result, zero_reg); 1433 break; 1434 case 1: 1435 // Nothing to do. 1436 __ Move(result, left); 1437 break; 1438 default: 1439 // Multiplying by powers of two and powers of two plus or minus 1440 // one can be done faster with shifted operands. 1441 // For other constants we emit standard code. 1442 int32_t mask = constant >> 31; 1443 uint32_t constant_abs = (constant + mask) ^ mask; 1444 1445 if (IsPowerOf2(constant_abs) || 1446 IsPowerOf2(constant_abs - 1) || 1447 IsPowerOf2(constant_abs + 1)) { 1448 if (IsPowerOf2(constant_abs)) { 1449 int32_t shift = WhichPowerOf2(constant_abs); 1450 __ sll(result, left, shift); 1451 } else if (IsPowerOf2(constant_abs - 1)) { 1452 int32_t shift = WhichPowerOf2(constant_abs - 1); 1453 __ sll(scratch, left, shift); 1454 __ Addu(result, scratch, left); 1455 } else if (IsPowerOf2(constant_abs + 1)) { 1456 int32_t shift = WhichPowerOf2(constant_abs + 1); 1457 __ sll(scratch, left, shift); 1458 __ Subu(result, scratch, left); 1459 } 1460 1461 // Correct the sign of the result is the constant is negative. 1462 if (constant < 0) { 1463 __ Subu(result, zero_reg, result); 1464 } 1465 1466 } else { 1467 // Generate standard code. 1468 __ li(at, constant); 1469 __ Mul(result, left, at); 1470 } 1471 } 1472 1473 } else { 1474 Register right = EmitLoadRegister(right_op, scratch); 1475 if (bailout_on_minus_zero) { 1476 __ Or(ToRegister(instr->temp()), left, right); 1477 } 1478 1479 if (can_overflow) { 1480 // hi:lo = left * right. 1481 if (instr->hydrogen()->representation().IsSmi()) { 1482 __ SmiUntag(result, left); 1483 __ mult(result, right); 1484 __ mfhi(scratch); 1485 __ mflo(result); 1486 } else { 1487 __ mult(left, right); 1488 __ mfhi(scratch); 1489 __ mflo(result); 1490 } 1491 __ sra(at, result, 31); 1492 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at)); 1493 } else { 1494 if (instr->hydrogen()->representation().IsSmi()) { 1495 __ SmiUntag(result, left); 1496 __ Mul(result, result, right); 1497 } else { 1498 __ Mul(result, left, right); 1499 } 1500 } 1501 1502 if (bailout_on_minus_zero) { 1503 // Bail out if the result is supposed to be negative zero. 1504 Label done; 1505 __ Branch(&done, ne, result, Operand(zero_reg)); 1506 DeoptimizeIf(lt, 1507 instr->environment(), 1508 ToRegister(instr->temp()), 1509 Operand(zero_reg)); 1510 __ bind(&done); 1511 } 1512 } 1513 } 1514 1515 1516 void LCodeGen::DoBitI(LBitI* instr) { 1517 LOperand* left_op = instr->left(); 1518 LOperand* right_op = instr->right(); 1519 ASSERT(left_op->IsRegister()); 1520 Register left = ToRegister(left_op); 1521 Register result = ToRegister(instr->result()); 1522 Operand right(no_reg); 1523 1524 if (right_op->IsStackSlot() || right_op->IsArgument()) { 1525 right = Operand(EmitLoadRegister(right_op, at)); 1526 } else { 1527 ASSERT(right_op->IsRegister() || right_op->IsConstantOperand()); 1528 right = ToOperand(right_op); 1529 } 1530 1531 switch (instr->op()) { 1532 case Token::BIT_AND: 1533 __ And(result, left, right); 1534 break; 1535 case Token::BIT_OR: 1536 __ Or(result, left, right); 1537 break; 1538 case Token::BIT_XOR: 1539 if (right_op->IsConstantOperand() && right.immediate() == int32_t(~0)) { 1540 __ Nor(result, zero_reg, left); 1541 } else { 1542 __ Xor(result, left, right); 1543 } 1544 break; 1545 default: 1546 UNREACHABLE(); 1547 break; 1548 } 1549 } 1550 1551 1552 void LCodeGen::DoShiftI(LShiftI* instr) { 1553 // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so 1554 // result may alias either of them. 1555 LOperand* right_op = instr->right(); 1556 Register left = ToRegister(instr->left()); 1557 Register result = ToRegister(instr->result()); 1558 Register scratch = scratch0(); 1559 1560 if (right_op->IsRegister()) { 1561 // No need to mask the right operand on MIPS, it is built into the variable 1562 // shift instructions. 1563 switch (instr->op()) { 1564 case Token::ROR: 1565 __ Ror(result, left, Operand(ToRegister(right_op))); 1566 break; 1567 case Token::SAR: 1568 __ srav(result, left, ToRegister(right_op)); 1569 break; 1570 case Token::SHR: 1571 __ srlv(result, left, ToRegister(right_op)); 1572 if (instr->can_deopt()) { 1573 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg)); 1574 } 1575 break; 1576 case Token::SHL: 1577 __ sllv(result, left, ToRegister(right_op)); 1578 break; 1579 default: 1580 UNREACHABLE(); 1581 break; 1582 } 1583 } else { 1584 // Mask the right_op operand. 1585 int value = ToInteger32(LConstantOperand::cast(right_op)); 1586 uint8_t shift_count = static_cast<uint8_t>(value & 0x1F); 1587 switch (instr->op()) { 1588 case Token::ROR: 1589 if (shift_count != 0) { 1590 __ Ror(result, left, Operand(shift_count)); 1591 } else { 1592 __ Move(result, left); 1593 } 1594 break; 1595 case Token::SAR: 1596 if (shift_count != 0) { 1597 __ sra(result, left, shift_count); 1598 } else { 1599 __ Move(result, left); 1600 } 1601 break; 1602 case Token::SHR: 1603 if (shift_count != 0) { 1604 __ srl(result, left, shift_count); 1605 } else { 1606 if (instr->can_deopt()) { 1607 __ And(at, left, Operand(0x80000000)); 1608 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); 1609 } 1610 __ Move(result, left); 1611 } 1612 break; 1613 case Token::SHL: 1614 if (shift_count != 0) { 1615 if (instr->hydrogen_value()->representation().IsSmi() && 1616 instr->can_deopt()) { 1617 if (shift_count != 1) { 1618 __ sll(result, left, shift_count - 1); 1619 __ SmiTagCheckOverflow(result, result, scratch); 1620 } else { 1621 __ SmiTagCheckOverflow(result, left, scratch); 1622 } 1623 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg)); 1624 } else { 1625 __ sll(result, left, shift_count); 1626 } 1627 } else { 1628 __ Move(result, left); 1629 } 1630 break; 1631 default: 1632 UNREACHABLE(); 1633 break; 1634 } 1635 } 1636 } 1637 1638 1639 void LCodeGen::DoSubI(LSubI* instr) { 1640 LOperand* left = instr->left(); 1641 LOperand* right = instr->right(); 1642 LOperand* result = instr->result(); 1643 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 1644 1645 if (!can_overflow) { 1646 if (right->IsStackSlot() || right->IsArgument()) { 1647 Register right_reg = EmitLoadRegister(right, at); 1648 __ Subu(ToRegister(result), ToRegister(left), Operand(right_reg)); 1649 } else { 1650 ASSERT(right->IsRegister() || right->IsConstantOperand()); 1651 __ Subu(ToRegister(result), ToRegister(left), ToOperand(right)); 1652 } 1653 } else { // can_overflow. 1654 Register overflow = scratch0(); 1655 Register scratch = scratch1(); 1656 if (right->IsStackSlot() || 1657 right->IsArgument() || 1658 right->IsConstantOperand()) { 1659 Register right_reg = EmitLoadRegister(right, scratch); 1660 __ SubuAndCheckForOverflow(ToRegister(result), 1661 ToRegister(left), 1662 right_reg, 1663 overflow); // Reg at also used as scratch. 1664 } else { 1665 ASSERT(right->IsRegister()); 1666 // Due to overflow check macros not supporting constant operands, 1667 // handling the IsConstantOperand case was moved to prev if clause. 1668 __ SubuAndCheckForOverflow(ToRegister(result), 1669 ToRegister(left), 1670 ToRegister(right), 1671 overflow); // Reg at also used as scratch. 1672 } 1673 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg)); 1674 } 1675 } 1676 1677 1678 void LCodeGen::DoConstantI(LConstantI* instr) { 1679 __ li(ToRegister(instr->result()), Operand(instr->value())); 1680 } 1681 1682 1683 void LCodeGen::DoConstantS(LConstantS* instr) { 1684 __ li(ToRegister(instr->result()), Operand(instr->value())); 1685 } 1686 1687 1688 void LCodeGen::DoConstantD(LConstantD* instr) { 1689 ASSERT(instr->result()->IsDoubleRegister()); 1690 DoubleRegister result = ToDoubleRegister(instr->result()); 1691 double v = instr->value(); 1692 __ Move(result, v); 1693 } 1694 1695 1696 void LCodeGen::DoConstantE(LConstantE* instr) { 1697 __ li(ToRegister(instr->result()), Operand(instr->value())); 1698 } 1699 1700 1701 void LCodeGen::DoConstantT(LConstantT* instr) { 1702 Handle<Object> value = instr->value(); 1703 AllowDeferredHandleDereference smi_check; 1704 __ LoadObject(ToRegister(instr->result()), value); 1705 } 1706 1707 1708 void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) { 1709 Register result = ToRegister(instr->result()); 1710 Register map = ToRegister(instr->value()); 1711 __ EnumLength(result, map); 1712 } 1713 1714 1715 void LCodeGen::DoElementsKind(LElementsKind* instr) { 1716 Register result = ToRegister(instr->result()); 1717 Register input = ToRegister(instr->value()); 1718 1719 // Load map into |result|. 1720 __ lw(result, FieldMemOperand(input, HeapObject::kMapOffset)); 1721 // Load the map's "bit field 2" into |result|. We only need the first byte, 1722 // but the following bit field extraction takes care of that anyway. 1723 __ lbu(result, FieldMemOperand(result, Map::kBitField2Offset)); 1724 // Retrieve elements_kind from bit field 2. 1725 __ Ext(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount); 1726 } 1727 1728 1729 void LCodeGen::DoValueOf(LValueOf* instr) { 1730 Register input = ToRegister(instr->value()); 1731 Register result = ToRegister(instr->result()); 1732 Register map = ToRegister(instr->temp()); 1733 Label done; 1734 1735 if (!instr->hydrogen()->value()->IsHeapObject()) { 1736 // If the object is a smi return the object. 1737 __ Move(result, input); 1738 __ JumpIfSmi(input, &done); 1739 } 1740 1741 // If the object is not a value type, return the object. 1742 __ GetObjectType(input, map, map); 1743 __ Branch(&done, ne, map, Operand(JS_VALUE_TYPE)); 1744 __ lw(result, FieldMemOperand(input, JSValue::kValueOffset)); 1745 1746 __ bind(&done); 1747 } 1748 1749 1750 void LCodeGen::DoDateField(LDateField* instr) { 1751 Register object = ToRegister(instr->date()); 1752 Register result = ToRegister(instr->result()); 1753 Register scratch = ToRegister(instr->temp()); 1754 Smi* index = instr->index(); 1755 Label runtime, done; 1756 ASSERT(object.is(a0)); 1757 ASSERT(result.is(v0)); 1758 ASSERT(!scratch.is(scratch0())); 1759 ASSERT(!scratch.is(object)); 1760 1761 __ And(at, object, Operand(kSmiTagMask)); 1762 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); 1763 __ GetObjectType(object, scratch, scratch); 1764 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_DATE_TYPE)); 1765 1766 if (index->value() == 0) { 1767 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset)); 1768 } else { 1769 if (index->value() < JSDate::kFirstUncachedField) { 1770 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); 1771 __ li(scratch, Operand(stamp)); 1772 __ lw(scratch, MemOperand(scratch)); 1773 __ lw(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset)); 1774 __ Branch(&runtime, ne, scratch, Operand(scratch0())); 1775 __ lw(result, FieldMemOperand(object, JSDate::kValueOffset + 1776 kPointerSize * index->value())); 1777 __ jmp(&done); 1778 } 1779 __ bind(&runtime); 1780 __ PrepareCallCFunction(2, scratch); 1781 __ li(a1, Operand(index)); 1782 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); 1783 __ bind(&done); 1784 } 1785 } 1786 1787 1788 void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) { 1789 Register string = ToRegister(instr->string()); 1790 Register index = ToRegister(instr->index()); 1791 Register value = ToRegister(instr->value()); 1792 Register scratch = scratch0(); 1793 String::Encoding encoding = instr->encoding(); 1794 1795 if (FLAG_debug_code) { 1796 __ lw(at, FieldMemOperand(string, HeapObject::kMapOffset)); 1797 __ lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset)); 1798 1799 __ And(at, at, Operand(kStringRepresentationMask | kStringEncodingMask)); 1800 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; 1801 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; 1802 __ Subu(at, at, Operand(encoding == String::ONE_BYTE_ENCODING 1803 ? one_byte_seq_type : two_byte_seq_type)); 1804 __ Check(eq, kUnexpectedStringType, at, Operand(zero_reg)); 1805 } 1806 1807 __ Addu(scratch, 1808 string, 1809 Operand(SeqString::kHeaderSize - kHeapObjectTag)); 1810 if (encoding == String::ONE_BYTE_ENCODING) { 1811 __ Addu(at, scratch, index); 1812 __ sb(value, MemOperand(at)); 1813 } else { 1814 __ sll(at, index, 1); 1815 __ Addu(at, scratch, at); 1816 __ sh(value, MemOperand(at)); 1817 } 1818 } 1819 1820 1821 void LCodeGen::DoThrow(LThrow* instr) { 1822 Register input_reg = EmitLoadRegister(instr->value(), at); 1823 __ push(input_reg); 1824 CallRuntime(Runtime::kThrow, 1, instr); 1825 1826 if (FLAG_debug_code) { 1827 __ stop("Unreachable code."); 1828 } 1829 } 1830 1831 1832 void LCodeGen::DoAddI(LAddI* instr) { 1833 LOperand* left = instr->left(); 1834 LOperand* right = instr->right(); 1835 LOperand* result = instr->result(); 1836 bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow); 1837 1838 if (!can_overflow) { 1839 if (right->IsStackSlot() || right->IsArgument()) { 1840 Register right_reg = EmitLoadRegister(right, at); 1841 __ Addu(ToRegister(result), ToRegister(left), Operand(right_reg)); 1842 } else { 1843 ASSERT(right->IsRegister() || right->IsConstantOperand()); 1844 __ Addu(ToRegister(result), ToRegister(left), ToOperand(right)); 1845 } 1846 } else { // can_overflow. 1847 Register overflow = scratch0(); 1848 Register scratch = scratch1(); 1849 if (right->IsStackSlot() || 1850 right->IsArgument() || 1851 right->IsConstantOperand()) { 1852 Register right_reg = EmitLoadRegister(right, scratch); 1853 __ AdduAndCheckForOverflow(ToRegister(result), 1854 ToRegister(left), 1855 right_reg, 1856 overflow); // Reg at also used as scratch. 1857 } else { 1858 ASSERT(right->IsRegister()); 1859 // Due to overflow check macros not supporting constant operands, 1860 // handling the IsConstantOperand case was moved to prev if clause. 1861 __ AdduAndCheckForOverflow(ToRegister(result), 1862 ToRegister(left), 1863 ToRegister(right), 1864 overflow); // Reg at also used as scratch. 1865 } 1866 DeoptimizeIf(lt, instr->environment(), overflow, Operand(zero_reg)); 1867 } 1868 } 1869 1870 1871 void LCodeGen::DoMathMinMax(LMathMinMax* instr) { 1872 LOperand* left = instr->left(); 1873 LOperand* right = instr->right(); 1874 HMathMinMax::Operation operation = instr->hydrogen()->operation(); 1875 Condition condition = (operation == HMathMinMax::kMathMin) ? le : ge; 1876 if (instr->hydrogen()->representation().IsSmiOrInteger32()) { 1877 Register left_reg = ToRegister(left); 1878 Operand right_op = (right->IsRegister() || right->IsConstantOperand()) 1879 ? ToOperand(right) 1880 : Operand(EmitLoadRegister(right, at)); 1881 Register result_reg = ToRegister(instr->result()); 1882 Label return_right, done; 1883 if (!result_reg.is(left_reg)) { 1884 __ Branch(&return_right, NegateCondition(condition), left_reg, right_op); 1885 __ mov(result_reg, left_reg); 1886 __ Branch(&done); 1887 } 1888 __ Branch(&done, condition, left_reg, right_op); 1889 __ bind(&return_right); 1890 __ Addu(result_reg, zero_reg, right_op); 1891 __ bind(&done); 1892 } else { 1893 ASSERT(instr->hydrogen()->representation().IsDouble()); 1894 FPURegister left_reg = ToDoubleRegister(left); 1895 FPURegister right_reg = ToDoubleRegister(right); 1896 FPURegister result_reg = ToDoubleRegister(instr->result()); 1897 Label check_nan_left, check_zero, return_left, return_right, done; 1898 __ BranchF(&check_zero, &check_nan_left, eq, left_reg, right_reg); 1899 __ BranchF(&return_left, NULL, condition, left_reg, right_reg); 1900 __ Branch(&return_right); 1901 1902 __ bind(&check_zero); 1903 // left == right != 0. 1904 __ BranchF(&return_left, NULL, ne, left_reg, kDoubleRegZero); 1905 // At this point, both left and right are either 0 or -0. 1906 if (operation == HMathMinMax::kMathMin) { 1907 __ neg_d(left_reg, left_reg); 1908 __ sub_d(result_reg, left_reg, right_reg); 1909 __ neg_d(result_reg, result_reg); 1910 } else { 1911 __ add_d(result_reg, left_reg, right_reg); 1912 } 1913 __ Branch(&done); 1914 1915 __ bind(&check_nan_left); 1916 // left == NaN. 1917 __ BranchF(NULL, &return_left, eq, left_reg, left_reg); 1918 __ bind(&return_right); 1919 if (!right_reg.is(result_reg)) { 1920 __ mov_d(result_reg, right_reg); 1921 } 1922 __ Branch(&done); 1923 1924 __ bind(&return_left); 1925 if (!left_reg.is(result_reg)) { 1926 __ mov_d(result_reg, left_reg); 1927 } 1928 __ bind(&done); 1929 } 1930 } 1931 1932 1933 void LCodeGen::DoArithmeticD(LArithmeticD* instr) { 1934 DoubleRegister left = ToDoubleRegister(instr->left()); 1935 DoubleRegister right = ToDoubleRegister(instr->right()); 1936 DoubleRegister result = ToDoubleRegister(instr->result()); 1937 switch (instr->op()) { 1938 case Token::ADD: 1939 __ add_d(result, left, right); 1940 break; 1941 case Token::SUB: 1942 __ sub_d(result, left, right); 1943 break; 1944 case Token::MUL: 1945 __ mul_d(result, left, right); 1946 break; 1947 case Token::DIV: 1948 __ div_d(result, left, right); 1949 break; 1950 case Token::MOD: { 1951 // Save a0-a3 on the stack. 1952 RegList saved_regs = a0.bit() | a1.bit() | a2.bit() | a3.bit(); 1953 __ MultiPush(saved_regs); 1954 1955 __ PrepareCallCFunction(0, 2, scratch0()); 1956 __ SetCallCDoubleArguments(left, right); 1957 __ CallCFunction( 1958 ExternalReference::double_fp_operation(Token::MOD, isolate()), 1959 0, 2); 1960 // Move the result in the double result register. 1961 __ GetCFunctionDoubleResult(result); 1962 1963 // Restore saved register. 1964 __ MultiPop(saved_regs); 1965 break; 1966 } 1967 default: 1968 UNREACHABLE(); 1969 break; 1970 } 1971 } 1972 1973 1974 void LCodeGen::DoArithmeticT(LArithmeticT* instr) { 1975 ASSERT(ToRegister(instr->left()).is(a1)); 1976 ASSERT(ToRegister(instr->right()).is(a0)); 1977 ASSERT(ToRegister(instr->result()).is(v0)); 1978 1979 BinaryOpStub stub(instr->op(), NO_OVERWRITE); 1980 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 1981 // Other arch use a nop here, to signal that there is no inlined 1982 // patchable code. Mips does not need the nop, since our marker 1983 // instruction (andi zero_reg) will never be used in normal code. 1984 } 1985 1986 1987 int LCodeGen::GetNextEmittedBlock() const { 1988 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { 1989 if (!chunk_->GetLabel(i)->HasReplacement()) return i; 1990 } 1991 return -1; 1992 } 1993 1994 template<class InstrType> 1995 void LCodeGen::EmitBranch(InstrType instr, 1996 Condition condition, 1997 Register src1, 1998 const Operand& src2) { 1999 int left_block = instr->TrueDestination(chunk_); 2000 int right_block = instr->FalseDestination(chunk_); 2001 2002 int next_block = GetNextEmittedBlock(); 2003 if (right_block == left_block || condition == al) { 2004 EmitGoto(left_block); 2005 } else if (left_block == next_block) { 2006 __ Branch(chunk_->GetAssemblyLabel(right_block), 2007 NegateCondition(condition), src1, src2); 2008 } else if (right_block == next_block) { 2009 __ Branch(chunk_->GetAssemblyLabel(left_block), condition, src1, src2); 2010 } else { 2011 __ Branch(chunk_->GetAssemblyLabel(left_block), condition, src1, src2); 2012 __ Branch(chunk_->GetAssemblyLabel(right_block)); 2013 } 2014 } 2015 2016 2017 template<class InstrType> 2018 void LCodeGen::EmitBranchF(InstrType instr, 2019 Condition condition, 2020 FPURegister src1, 2021 FPURegister src2) { 2022 int right_block = instr->FalseDestination(chunk_); 2023 int left_block = instr->TrueDestination(chunk_); 2024 2025 int next_block = GetNextEmittedBlock(); 2026 if (right_block == left_block) { 2027 EmitGoto(left_block); 2028 } else if (left_block == next_block) { 2029 __ BranchF(chunk_->GetAssemblyLabel(right_block), NULL, 2030 NegateCondition(condition), src1, src2); 2031 } else if (right_block == next_block) { 2032 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, 2033 condition, src1, src2); 2034 } else { 2035 __ BranchF(chunk_->GetAssemblyLabel(left_block), NULL, 2036 condition, src1, src2); 2037 __ Branch(chunk_->GetAssemblyLabel(right_block)); 2038 } 2039 } 2040 2041 2042 template<class InstrType> 2043 void LCodeGen::EmitFalseBranchF(InstrType instr, 2044 Condition condition, 2045 FPURegister src1, 2046 FPURegister src2) { 2047 int false_block = instr->FalseDestination(chunk_); 2048 __ BranchF(chunk_->GetAssemblyLabel(false_block), NULL, 2049 condition, src1, src2); 2050 } 2051 2052 2053 void LCodeGen::DoDebugBreak(LDebugBreak* instr) { 2054 __ stop("LDebugBreak"); 2055 } 2056 2057 2058 void LCodeGen::DoIsNumberAndBranch(LIsNumberAndBranch* instr) { 2059 Representation r = instr->hydrogen()->value()->representation(); 2060 if (r.IsSmiOrInteger32() || r.IsDouble()) { 2061 EmitBranch(instr, al, zero_reg, Operand(zero_reg)); 2062 } else { 2063 ASSERT(r.IsTagged()); 2064 Register reg = ToRegister(instr->value()); 2065 HType type = instr->hydrogen()->value()->type(); 2066 if (type.IsTaggedNumber()) { 2067 EmitBranch(instr, al, zero_reg, Operand(zero_reg)); 2068 } 2069 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); 2070 __ lw(scratch0(), FieldMemOperand(reg, HeapObject::kMapOffset)); 2071 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 2072 EmitBranch(instr, eq, scratch0(), Operand(at)); 2073 } 2074 } 2075 2076 2077 void LCodeGen::DoBranch(LBranch* instr) { 2078 Representation r = instr->hydrogen()->value()->representation(); 2079 if (r.IsInteger32() || r.IsSmi()) { 2080 ASSERT(!info()->IsStub()); 2081 Register reg = ToRegister(instr->value()); 2082 EmitBranch(instr, ne, reg, Operand(zero_reg)); 2083 } else if (r.IsDouble()) { 2084 ASSERT(!info()->IsStub()); 2085 DoubleRegister reg = ToDoubleRegister(instr->value()); 2086 // Test the double value. Zero and NaN are false. 2087 EmitBranchF(instr, nue, reg, kDoubleRegZero); 2088 } else { 2089 ASSERT(r.IsTagged()); 2090 Register reg = ToRegister(instr->value()); 2091 HType type = instr->hydrogen()->value()->type(); 2092 if (type.IsBoolean()) { 2093 ASSERT(!info()->IsStub()); 2094 __ LoadRoot(at, Heap::kTrueValueRootIndex); 2095 EmitBranch(instr, eq, reg, Operand(at)); 2096 } else if (type.IsSmi()) { 2097 ASSERT(!info()->IsStub()); 2098 EmitBranch(instr, ne, reg, Operand(zero_reg)); 2099 } else if (type.IsJSArray()) { 2100 ASSERT(!info()->IsStub()); 2101 EmitBranch(instr, al, zero_reg, Operand(zero_reg)); 2102 } else if (type.IsHeapNumber()) { 2103 ASSERT(!info()->IsStub()); 2104 DoubleRegister dbl_scratch = double_scratch0(); 2105 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset)); 2106 // Test the double value. Zero and NaN are false. 2107 EmitBranchF(instr, nue, dbl_scratch, kDoubleRegZero); 2108 } else if (type.IsString()) { 2109 ASSERT(!info()->IsStub()); 2110 __ lw(at, FieldMemOperand(reg, String::kLengthOffset)); 2111 EmitBranch(instr, ne, at, Operand(zero_reg)); 2112 } else { 2113 ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types(); 2114 // Avoid deopts in the case where we've never executed this path before. 2115 if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic(); 2116 2117 if (expected.Contains(ToBooleanStub::UNDEFINED)) { 2118 // undefined -> false. 2119 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); 2120 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); 2121 } 2122 if (expected.Contains(ToBooleanStub::BOOLEAN)) { 2123 // Boolean -> its value. 2124 __ LoadRoot(at, Heap::kTrueValueRootIndex); 2125 __ Branch(instr->TrueLabel(chunk_), eq, reg, Operand(at)); 2126 __ LoadRoot(at, Heap::kFalseValueRootIndex); 2127 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); 2128 } 2129 if (expected.Contains(ToBooleanStub::NULL_TYPE)) { 2130 // 'null' -> false. 2131 __ LoadRoot(at, Heap::kNullValueRootIndex); 2132 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(at)); 2133 } 2134 2135 if (expected.Contains(ToBooleanStub::SMI)) { 2136 // Smis: 0 -> false, all other -> true. 2137 __ Branch(instr->FalseLabel(chunk_), eq, reg, Operand(zero_reg)); 2138 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); 2139 } else if (expected.NeedsMap()) { 2140 // If we need a map later and have a Smi -> deopt. 2141 __ And(at, reg, Operand(kSmiTagMask)); 2142 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); 2143 } 2144 2145 const Register map = scratch0(); 2146 if (expected.NeedsMap()) { 2147 __ lw(map, FieldMemOperand(reg, HeapObject::kMapOffset)); 2148 if (expected.CanBeUndetectable()) { 2149 // Undetectable -> false. 2150 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); 2151 __ And(at, at, Operand(1 << Map::kIsUndetectable)); 2152 __ Branch(instr->FalseLabel(chunk_), ne, at, Operand(zero_reg)); 2153 } 2154 } 2155 2156 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { 2157 // spec object -> true. 2158 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset)); 2159 __ Branch(instr->TrueLabel(chunk_), 2160 ge, at, Operand(FIRST_SPEC_OBJECT_TYPE)); 2161 } 2162 2163 if (expected.Contains(ToBooleanStub::STRING)) { 2164 // String value -> false iff empty. 2165 Label not_string; 2166 __ lbu(at, FieldMemOperand(map, Map::kInstanceTypeOffset)); 2167 __ Branch(¬_string, ge , at, Operand(FIRST_NONSTRING_TYPE)); 2168 __ lw(at, FieldMemOperand(reg, String::kLengthOffset)); 2169 __ Branch(instr->TrueLabel(chunk_), ne, at, Operand(zero_reg)); 2170 __ Branch(instr->FalseLabel(chunk_)); 2171 __ bind(¬_string); 2172 } 2173 2174 if (expected.Contains(ToBooleanStub::SYMBOL)) { 2175 // Symbol value -> true. 2176 const Register scratch = scratch1(); 2177 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); 2178 __ Branch(instr->TrueLabel(chunk_), eq, scratch, Operand(SYMBOL_TYPE)); 2179 } 2180 2181 if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) { 2182 // heap number -> false iff +0, -0, or NaN. 2183 DoubleRegister dbl_scratch = double_scratch0(); 2184 Label not_heap_number; 2185 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 2186 __ Branch(¬_heap_number, ne, map, Operand(at)); 2187 __ ldc1(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset)); 2188 __ BranchF(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), 2189 ne, dbl_scratch, kDoubleRegZero); 2190 // Falls through if dbl_scratch == 0. 2191 __ Branch(instr->FalseLabel(chunk_)); 2192 __ bind(¬_heap_number); 2193 } 2194 2195 if (!expected.IsGeneric()) { 2196 // We've seen something for the first time -> deopt. 2197 // This can only happen if we are not generic already. 2198 DeoptimizeIf(al, instr->environment(), zero_reg, Operand(zero_reg)); 2199 } 2200 } 2201 } 2202 } 2203 2204 2205 void LCodeGen::EmitGoto(int block) { 2206 if (!IsNextEmittedBlock(block)) { 2207 __ jmp(chunk_->GetAssemblyLabel(LookupDestination(block))); 2208 } 2209 } 2210 2211 2212 void LCodeGen::DoGoto(LGoto* instr) { 2213 EmitGoto(instr->block_id()); 2214 } 2215 2216 2217 Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) { 2218 Condition cond = kNoCondition; 2219 switch (op) { 2220 case Token::EQ: 2221 case Token::EQ_STRICT: 2222 cond = eq; 2223 break; 2224 case Token::LT: 2225 cond = is_unsigned ? lo : lt; 2226 break; 2227 case Token::GT: 2228 cond = is_unsigned ? hi : gt; 2229 break; 2230 case Token::LTE: 2231 cond = is_unsigned ? ls : le; 2232 break; 2233 case Token::GTE: 2234 cond = is_unsigned ? hs : ge; 2235 break; 2236 case Token::IN: 2237 case Token::INSTANCEOF: 2238 default: 2239 UNREACHABLE(); 2240 } 2241 return cond; 2242 } 2243 2244 2245 void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) { 2246 LOperand* left = instr->left(); 2247 LOperand* right = instr->right(); 2248 Condition cond = TokenToCondition(instr->op(), false); 2249 2250 if (left->IsConstantOperand() && right->IsConstantOperand()) { 2251 // We can statically evaluate the comparison. 2252 double left_val = ToDouble(LConstantOperand::cast(left)); 2253 double right_val = ToDouble(LConstantOperand::cast(right)); 2254 int next_block = EvalComparison(instr->op(), left_val, right_val) ? 2255 instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_); 2256 EmitGoto(next_block); 2257 } else { 2258 if (instr->is_double()) { 2259 // Compare left and right as doubles and load the 2260 // resulting flags into the normal status register. 2261 FPURegister left_reg = ToDoubleRegister(left); 2262 FPURegister right_reg = ToDoubleRegister(right); 2263 2264 // If a NaN is involved, i.e. the result is unordered, 2265 // jump to false block label. 2266 __ BranchF(NULL, instr->FalseLabel(chunk_), eq, 2267 left_reg, right_reg); 2268 2269 EmitBranchF(instr, cond, left_reg, right_reg); 2270 } else { 2271 Register cmp_left; 2272 Operand cmp_right = Operand(0); 2273 2274 if (right->IsConstantOperand()) { 2275 int32_t value = ToInteger32(LConstantOperand::cast(right)); 2276 if (instr->hydrogen_value()->representation().IsSmi()) { 2277 cmp_left = ToRegister(left); 2278 cmp_right = Operand(Smi::FromInt(value)); 2279 } else { 2280 cmp_left = ToRegister(left); 2281 cmp_right = Operand(value); 2282 } 2283 } else if (left->IsConstantOperand()) { 2284 int32_t value = ToInteger32(LConstantOperand::cast(left)); 2285 if (instr->hydrogen_value()->representation().IsSmi()) { 2286 cmp_left = ToRegister(right); 2287 cmp_right = Operand(Smi::FromInt(value)); 2288 } else { 2289 cmp_left = ToRegister(right); 2290 cmp_right = Operand(value); 2291 } 2292 // We transposed the operands. Reverse the condition. 2293 cond = ReverseCondition(cond); 2294 } else { 2295 cmp_left = ToRegister(left); 2296 cmp_right = Operand(ToRegister(right)); 2297 } 2298 2299 EmitBranch(instr, cond, cmp_left, cmp_right); 2300 } 2301 } 2302 } 2303 2304 2305 void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) { 2306 Register left = ToRegister(instr->left()); 2307 Register right = ToRegister(instr->right()); 2308 2309 EmitBranch(instr, eq, left, Operand(right)); 2310 } 2311 2312 2313 void LCodeGen::DoCmpHoleAndBranch(LCmpHoleAndBranch* instr) { 2314 if (instr->hydrogen()->representation().IsTagged()) { 2315 Register input_reg = ToRegister(instr->object()); 2316 __ li(at, Operand(factory()->the_hole_value())); 2317 EmitBranch(instr, eq, input_reg, Operand(at)); 2318 return; 2319 } 2320 2321 DoubleRegister input_reg = ToDoubleRegister(instr->object()); 2322 EmitFalseBranchF(instr, eq, input_reg, input_reg); 2323 2324 Register scratch = scratch0(); 2325 __ FmoveHigh(scratch, input_reg); 2326 EmitBranch(instr, eq, scratch, Operand(kHoleNanUpper32)); 2327 } 2328 2329 2330 Condition LCodeGen::EmitIsObject(Register input, 2331 Register temp1, 2332 Register temp2, 2333 Label* is_not_object, 2334 Label* is_object) { 2335 __ JumpIfSmi(input, is_not_object); 2336 2337 __ LoadRoot(temp2, Heap::kNullValueRootIndex); 2338 __ Branch(is_object, eq, input, Operand(temp2)); 2339 2340 // Load map. 2341 __ lw(temp1, FieldMemOperand(input, HeapObject::kMapOffset)); 2342 // Undetectable objects behave like undefined. 2343 __ lbu(temp2, FieldMemOperand(temp1, Map::kBitFieldOffset)); 2344 __ And(temp2, temp2, Operand(1 << Map::kIsUndetectable)); 2345 __ Branch(is_not_object, ne, temp2, Operand(zero_reg)); 2346 2347 // Load instance type and check that it is in object type range. 2348 __ lbu(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset)); 2349 __ Branch(is_not_object, 2350 lt, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 2351 2352 return le; 2353 } 2354 2355 2356 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { 2357 Register reg = ToRegister(instr->value()); 2358 Register temp1 = ToRegister(instr->temp()); 2359 Register temp2 = scratch0(); 2360 2361 Condition true_cond = 2362 EmitIsObject(reg, temp1, temp2, 2363 instr->FalseLabel(chunk_), instr->TrueLabel(chunk_)); 2364 2365 EmitBranch(instr, true_cond, temp2, 2366 Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); 2367 } 2368 2369 2370 Condition LCodeGen::EmitIsString(Register input, 2371 Register temp1, 2372 Label* is_not_string, 2373 SmiCheck check_needed = INLINE_SMI_CHECK) { 2374 if (check_needed == INLINE_SMI_CHECK) { 2375 __ JumpIfSmi(input, is_not_string); 2376 } 2377 __ GetObjectType(input, temp1, temp1); 2378 2379 return lt; 2380 } 2381 2382 2383 void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) { 2384 Register reg = ToRegister(instr->value()); 2385 Register temp1 = ToRegister(instr->temp()); 2386 2387 SmiCheck check_needed = 2388 instr->hydrogen()->value()->IsHeapObject() 2389 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 2390 Condition true_cond = 2391 EmitIsString(reg, temp1, instr->FalseLabel(chunk_), check_needed); 2392 2393 EmitBranch(instr, true_cond, temp1, 2394 Operand(FIRST_NONSTRING_TYPE)); 2395 } 2396 2397 2398 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) { 2399 Register input_reg = EmitLoadRegister(instr->value(), at); 2400 __ And(at, input_reg, kSmiTagMask); 2401 EmitBranch(instr, eq, at, Operand(zero_reg)); 2402 } 2403 2404 2405 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { 2406 Register input = ToRegister(instr->value()); 2407 Register temp = ToRegister(instr->temp()); 2408 2409 if (!instr->hydrogen()->value()->IsHeapObject()) { 2410 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); 2411 } 2412 __ lw(temp, FieldMemOperand(input, HeapObject::kMapOffset)); 2413 __ lbu(temp, FieldMemOperand(temp, Map::kBitFieldOffset)); 2414 __ And(at, temp, Operand(1 << Map::kIsUndetectable)); 2415 EmitBranch(instr, ne, at, Operand(zero_reg)); 2416 } 2417 2418 2419 static Condition ComputeCompareCondition(Token::Value op) { 2420 switch (op) { 2421 case Token::EQ_STRICT: 2422 case Token::EQ: 2423 return eq; 2424 case Token::LT: 2425 return lt; 2426 case Token::GT: 2427 return gt; 2428 case Token::LTE: 2429 return le; 2430 case Token::GTE: 2431 return ge; 2432 default: 2433 UNREACHABLE(); 2434 return kNoCondition; 2435 } 2436 } 2437 2438 2439 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { 2440 Token::Value op = instr->op(); 2441 2442 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); 2443 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2444 2445 Condition condition = ComputeCompareCondition(op); 2446 2447 EmitBranch(instr, condition, v0, Operand(zero_reg)); 2448 } 2449 2450 2451 static InstanceType TestType(HHasInstanceTypeAndBranch* instr) { 2452 InstanceType from = instr->from(); 2453 InstanceType to = instr->to(); 2454 if (from == FIRST_TYPE) return to; 2455 ASSERT(from == to || to == LAST_TYPE); 2456 return from; 2457 } 2458 2459 2460 static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) { 2461 InstanceType from = instr->from(); 2462 InstanceType to = instr->to(); 2463 if (from == to) return eq; 2464 if (to == LAST_TYPE) return hs; 2465 if (from == FIRST_TYPE) return ls; 2466 UNREACHABLE(); 2467 return eq; 2468 } 2469 2470 2471 void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) { 2472 Register scratch = scratch0(); 2473 Register input = ToRegister(instr->value()); 2474 2475 if (!instr->hydrogen()->value()->IsHeapObject()) { 2476 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); 2477 } 2478 2479 __ GetObjectType(input, scratch, scratch); 2480 EmitBranch(instr, 2481 BranchCondition(instr->hydrogen()), 2482 scratch, 2483 Operand(TestType(instr->hydrogen()))); 2484 } 2485 2486 2487 void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) { 2488 Register input = ToRegister(instr->value()); 2489 Register result = ToRegister(instr->result()); 2490 2491 __ AssertString(input); 2492 2493 __ lw(result, FieldMemOperand(input, String::kHashFieldOffset)); 2494 __ IndexFromHash(result, result); 2495 } 2496 2497 2498 void LCodeGen::DoHasCachedArrayIndexAndBranch( 2499 LHasCachedArrayIndexAndBranch* instr) { 2500 Register input = ToRegister(instr->value()); 2501 Register scratch = scratch0(); 2502 2503 __ lw(scratch, 2504 FieldMemOperand(input, String::kHashFieldOffset)); 2505 __ And(at, scratch, Operand(String::kContainsCachedArrayIndexMask)); 2506 EmitBranch(instr, eq, at, Operand(zero_reg)); 2507 } 2508 2509 2510 // Branches to a label or falls through with the answer in flags. Trashes 2511 // the temp registers, but not the input. 2512 void LCodeGen::EmitClassOfTest(Label* is_true, 2513 Label* is_false, 2514 Handle<String>class_name, 2515 Register input, 2516 Register temp, 2517 Register temp2) { 2518 ASSERT(!input.is(temp)); 2519 ASSERT(!input.is(temp2)); 2520 ASSERT(!temp.is(temp2)); 2521 2522 __ JumpIfSmi(input, is_false); 2523 2524 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Function"))) { 2525 // Assuming the following assertions, we can use the same compares to test 2526 // for both being a function type and being in the object type range. 2527 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); 2528 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == 2529 FIRST_SPEC_OBJECT_TYPE + 1); 2530 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == 2531 LAST_SPEC_OBJECT_TYPE - 1); 2532 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 2533 2534 __ GetObjectType(input, temp, temp2); 2535 __ Branch(is_false, lt, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); 2536 __ Branch(is_true, eq, temp2, Operand(FIRST_SPEC_OBJECT_TYPE)); 2537 __ Branch(is_true, eq, temp2, Operand(LAST_SPEC_OBJECT_TYPE)); 2538 } else { 2539 // Faster code path to avoid two compares: subtract lower bound from the 2540 // actual type and do a signed compare with the width of the type range. 2541 __ GetObjectType(input, temp, temp2); 2542 __ Subu(temp2, temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 2543 __ Branch(is_false, gt, temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - 2544 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 2545 } 2546 2547 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. 2548 // Check if the constructor in the map is a function. 2549 __ lw(temp, FieldMemOperand(temp, Map::kConstructorOffset)); 2550 2551 // Objects with a non-function constructor have class 'Object'. 2552 __ GetObjectType(temp, temp2, temp2); 2553 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) { 2554 __ Branch(is_true, ne, temp2, Operand(JS_FUNCTION_TYPE)); 2555 } else { 2556 __ Branch(is_false, ne, temp2, Operand(JS_FUNCTION_TYPE)); 2557 } 2558 2559 // temp now contains the constructor function. Grab the 2560 // instance class name from there. 2561 __ lw(temp, FieldMemOperand(temp, JSFunction::kSharedFunctionInfoOffset)); 2562 __ lw(temp, FieldMemOperand(temp, 2563 SharedFunctionInfo::kInstanceClassNameOffset)); 2564 // The class name we are testing against is internalized since it's a literal. 2565 // The name in the constructor is internalized because of the way the context 2566 // is booted. This routine isn't expected to work for random API-created 2567 // classes and it doesn't have to because you can't access it with natives 2568 // syntax. Since both sides are internalized it is sufficient to use an 2569 // identity comparison. 2570 2571 // End with the address of this class_name instance in temp register. 2572 // On MIPS, the caller must do the comparison with Handle<String>class_name. 2573 } 2574 2575 2576 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { 2577 Register input = ToRegister(instr->value()); 2578 Register temp = scratch0(); 2579 Register temp2 = ToRegister(instr->temp()); 2580 Handle<String> class_name = instr->hydrogen()->class_name(); 2581 2582 EmitClassOfTest(instr->TrueLabel(chunk_), instr->FalseLabel(chunk_), 2583 class_name, input, temp, temp2); 2584 2585 EmitBranch(instr, eq, temp, Operand(class_name)); 2586 } 2587 2588 2589 void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { 2590 Register reg = ToRegister(instr->value()); 2591 Register temp = ToRegister(instr->temp()); 2592 2593 __ lw(temp, FieldMemOperand(reg, HeapObject::kMapOffset)); 2594 EmitBranch(instr, eq, temp, Operand(instr->map())); 2595 } 2596 2597 2598 void LCodeGen::DoInstanceOf(LInstanceOf* instr) { 2599 Label true_label, done; 2600 ASSERT(ToRegister(instr->left()).is(a0)); // Object is in a0. 2601 ASSERT(ToRegister(instr->right()).is(a1)); // Function is in a1. 2602 Register result = ToRegister(instr->result()); 2603 ASSERT(result.is(v0)); 2604 2605 InstanceofStub stub(InstanceofStub::kArgsInRegisters); 2606 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 2607 2608 __ Branch(&true_label, eq, result, Operand(zero_reg)); 2609 __ li(result, Operand(factory()->false_value())); 2610 __ Branch(&done); 2611 __ bind(&true_label); 2612 __ li(result, Operand(factory()->true_value())); 2613 __ bind(&done); 2614 } 2615 2616 2617 void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) { 2618 class DeferredInstanceOfKnownGlobal: public LDeferredCode { 2619 public: 2620 DeferredInstanceOfKnownGlobal(LCodeGen* codegen, 2621 LInstanceOfKnownGlobal* instr) 2622 : LDeferredCode(codegen), instr_(instr) { } 2623 virtual void Generate() { 2624 codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_); 2625 } 2626 virtual LInstruction* instr() { return instr_; } 2627 Label* map_check() { return &map_check_; } 2628 2629 private: 2630 LInstanceOfKnownGlobal* instr_; 2631 Label map_check_; 2632 }; 2633 2634 DeferredInstanceOfKnownGlobal* deferred; 2635 deferred = new(zone()) DeferredInstanceOfKnownGlobal(this, instr); 2636 2637 Label done, false_result; 2638 Register object = ToRegister(instr->value()); 2639 Register temp = ToRegister(instr->temp()); 2640 Register result = ToRegister(instr->result()); 2641 2642 ASSERT(object.is(a0)); 2643 ASSERT(result.is(v0)); 2644 2645 // A Smi is not instance of anything. 2646 __ JumpIfSmi(object, &false_result); 2647 2648 // This is the inlined call site instanceof cache. The two occurences of the 2649 // hole value will be patched to the last map/result pair generated by the 2650 // instanceof stub. 2651 Label cache_miss; 2652 Register map = temp; 2653 __ lw(map, FieldMemOperand(object, HeapObject::kMapOffset)); 2654 2655 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 2656 __ bind(deferred->map_check()); // Label for calculating code patching. 2657 // We use Factory::the_hole_value() on purpose instead of loading from the 2658 // root array to force relocation to be able to later patch with 2659 // the cached map. 2660 Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value()); 2661 __ li(at, Operand(Handle<Object>(cell))); 2662 __ lw(at, FieldMemOperand(at, PropertyCell::kValueOffset)); 2663 __ Branch(&cache_miss, ne, map, Operand(at)); 2664 // We use Factory::the_hole_value() on purpose instead of loading from the 2665 // root array to force relocation to be able to later patch 2666 // with true or false. 2667 __ li(result, Operand(factory()->the_hole_value()), CONSTANT_SIZE); 2668 __ Branch(&done); 2669 2670 // The inlined call site cache did not match. Check null and string before 2671 // calling the deferred code. 2672 __ bind(&cache_miss); 2673 // Null is not instance of anything. 2674 __ LoadRoot(temp, Heap::kNullValueRootIndex); 2675 __ Branch(&false_result, eq, object, Operand(temp)); 2676 2677 // String values is not instance of anything. 2678 Condition cc = __ IsObjectStringType(object, temp, temp); 2679 __ Branch(&false_result, cc, temp, Operand(zero_reg)); 2680 2681 // Go to the deferred code. 2682 __ Branch(deferred->entry()); 2683 2684 __ bind(&false_result); 2685 __ LoadRoot(result, Heap::kFalseValueRootIndex); 2686 2687 // Here result has either true or false. Deferred code also produces true or 2688 // false object. 2689 __ bind(deferred->exit()); 2690 __ bind(&done); 2691 } 2692 2693 2694 void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr, 2695 Label* map_check) { 2696 Register result = ToRegister(instr->result()); 2697 ASSERT(result.is(v0)); 2698 2699 InstanceofStub::Flags flags = InstanceofStub::kNoFlags; 2700 flags = static_cast<InstanceofStub::Flags>( 2701 flags | InstanceofStub::kArgsInRegisters); 2702 flags = static_cast<InstanceofStub::Flags>( 2703 flags | InstanceofStub::kCallSiteInlineCheck); 2704 flags = static_cast<InstanceofStub::Flags>( 2705 flags | InstanceofStub::kReturnTrueFalseObject); 2706 InstanceofStub stub(flags); 2707 2708 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 2709 2710 // Get the temp register reserved by the instruction. This needs to be t0 as 2711 // its slot of the pushing of safepoint registers is used to communicate the 2712 // offset to the location of the map check. 2713 Register temp = ToRegister(instr->temp()); 2714 ASSERT(temp.is(t0)); 2715 __ LoadHeapObject(InstanceofStub::right(), instr->function()); 2716 static const int kAdditionalDelta = 7; 2717 int delta = masm_->InstructionsGeneratedSince(map_check) + kAdditionalDelta; 2718 Label before_push_delta; 2719 __ bind(&before_push_delta); 2720 { 2721 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 2722 __ li(temp, Operand(delta * kPointerSize), CONSTANT_SIZE); 2723 __ StoreToSafepointRegisterSlot(temp, temp); 2724 } 2725 CallCodeGeneric(stub.GetCode(isolate()), 2726 RelocInfo::CODE_TARGET, 2727 instr, 2728 RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 2729 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); 2730 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 2731 // Put the result value into the result register slot and 2732 // restore all registers. 2733 __ StoreToSafepointRegisterSlot(result, result); 2734 } 2735 2736 2737 void LCodeGen::DoInstanceSize(LInstanceSize* instr) { 2738 Register object = ToRegister(instr->object()); 2739 Register result = ToRegister(instr->result()); 2740 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset)); 2741 __ lbu(result, FieldMemOperand(result, Map::kInstanceSizeOffset)); 2742 } 2743 2744 2745 void LCodeGen::DoCmpT(LCmpT* instr) { 2746 Token::Value op = instr->op(); 2747 2748 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); 2749 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2750 // On MIPS there is no need for a "no inlined smi code" marker (nop). 2751 2752 Condition condition = ComputeCompareCondition(op); 2753 // A minor optimization that relies on LoadRoot always emitting one 2754 // instruction. 2755 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); 2756 Label done, check; 2757 __ Branch(USE_DELAY_SLOT, &done, condition, v0, Operand(zero_reg)); 2758 __ bind(&check); 2759 __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex); 2760 ASSERT_EQ(1, masm()->InstructionsGeneratedSince(&check)); 2761 __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex); 2762 __ bind(&done); 2763 } 2764 2765 2766 void LCodeGen::DoReturn(LReturn* instr) { 2767 if (FLAG_trace && info()->IsOptimizing()) { 2768 // Push the return value on the stack as the parameter. 2769 // Runtime::TraceExit returns its parameter in v0. 2770 __ push(v0); 2771 __ CallRuntime(Runtime::kTraceExit, 1); 2772 } 2773 if (info()->saves_caller_doubles()) { 2774 ASSERT(NeedsEagerFrame()); 2775 BitVector* doubles = chunk()->allocated_double_registers(); 2776 BitVector::Iterator save_iterator(doubles); 2777 int count = 0; 2778 while (!save_iterator.Done()) { 2779 __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), 2780 MemOperand(sp, count * kDoubleSize)); 2781 save_iterator.Advance(); 2782 count++; 2783 } 2784 } 2785 int no_frame_start = -1; 2786 if (NeedsEagerFrame()) { 2787 __ mov(sp, fp); 2788 no_frame_start = masm_->pc_offset(); 2789 __ Pop(ra, fp); 2790 } 2791 if (instr->has_constant_parameter_count()) { 2792 int parameter_count = ToInteger32(instr->constant_parameter_count()); 2793 int32_t sp_delta = (parameter_count + 1) * kPointerSize; 2794 if (sp_delta != 0) { 2795 __ Addu(sp, sp, Operand(sp_delta)); 2796 } 2797 } else { 2798 Register reg = ToRegister(instr->parameter_count()); 2799 // The argument count parameter is a smi 2800 __ SmiUntag(reg); 2801 __ sll(at, reg, kPointerSizeLog2); 2802 __ Addu(sp, sp, at); 2803 } 2804 2805 __ Jump(ra); 2806 2807 if (no_frame_start != -1) { 2808 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset()); 2809 } 2810 } 2811 2812 2813 void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) { 2814 Register result = ToRegister(instr->result()); 2815 __ li(at, Operand(Handle<Object>(instr->hydrogen()->cell()))); 2816 __ lw(result, FieldMemOperand(at, Cell::kValueOffset)); 2817 if (instr->hydrogen()->RequiresHoleCheck()) { 2818 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 2819 DeoptimizeIf(eq, instr->environment(), result, Operand(at)); 2820 } 2821 } 2822 2823 2824 void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) { 2825 ASSERT(ToRegister(instr->global_object()).is(a0)); 2826 ASSERT(ToRegister(instr->result()).is(v0)); 2827 2828 __ li(a2, Operand(instr->name())); 2829 RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET 2830 : RelocInfo::CODE_TARGET_CONTEXT; 2831 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 2832 CallCode(ic, mode, instr); 2833 } 2834 2835 2836 void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { 2837 Register value = ToRegister(instr->value()); 2838 Register cell = scratch0(); 2839 2840 // Load the cell. 2841 __ li(cell, Operand(instr->hydrogen()->cell())); 2842 2843 // If the cell we are storing to contains the hole it could have 2844 // been deleted from the property dictionary. In that case, we need 2845 // to update the property details in the property dictionary to mark 2846 // it as no longer deleted. 2847 if (instr->hydrogen()->RequiresHoleCheck()) { 2848 // We use a temp to check the payload. 2849 Register payload = ToRegister(instr->temp()); 2850 __ lw(payload, FieldMemOperand(cell, Cell::kValueOffset)); 2851 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 2852 DeoptimizeIf(eq, instr->environment(), payload, Operand(at)); 2853 } 2854 2855 // Store the value. 2856 __ sw(value, FieldMemOperand(cell, Cell::kValueOffset)); 2857 // Cells are always rescanned, so no write barrier here. 2858 } 2859 2860 2861 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { 2862 ASSERT(ToRegister(instr->global_object()).is(a1)); 2863 ASSERT(ToRegister(instr->value()).is(a0)); 2864 2865 __ li(a2, Operand(instr->name())); 2866 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) 2867 ? isolate()->builtins()->StoreIC_Initialize_Strict() 2868 : isolate()->builtins()->StoreIC_Initialize(); 2869 CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr); 2870 } 2871 2872 2873 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { 2874 Register context = ToRegister(instr->context()); 2875 Register result = ToRegister(instr->result()); 2876 2877 __ lw(result, ContextOperand(context, instr->slot_index())); 2878 if (instr->hydrogen()->RequiresHoleCheck()) { 2879 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 2880 2881 if (instr->hydrogen()->DeoptimizesOnHole()) { 2882 DeoptimizeIf(eq, instr->environment(), result, Operand(at)); 2883 } else { 2884 Label is_not_hole; 2885 __ Branch(&is_not_hole, ne, result, Operand(at)); 2886 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); 2887 __ bind(&is_not_hole); 2888 } 2889 } 2890 } 2891 2892 2893 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { 2894 Register context = ToRegister(instr->context()); 2895 Register value = ToRegister(instr->value()); 2896 Register scratch = scratch0(); 2897 MemOperand target = ContextOperand(context, instr->slot_index()); 2898 2899 Label skip_assignment; 2900 2901 if (instr->hydrogen()->RequiresHoleCheck()) { 2902 __ lw(scratch, target); 2903 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 2904 2905 if (instr->hydrogen()->DeoptimizesOnHole()) { 2906 DeoptimizeIf(eq, instr->environment(), scratch, Operand(at)); 2907 } else { 2908 __ Branch(&skip_assignment, ne, scratch, Operand(at)); 2909 } 2910 } 2911 2912 __ sw(value, target); 2913 if (instr->hydrogen()->NeedsWriteBarrier()) { 2914 SmiCheck check_needed = 2915 instr->hydrogen()->value()->IsHeapObject() 2916 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 2917 __ RecordWriteContextSlot(context, 2918 target.offset(), 2919 value, 2920 scratch0(), 2921 GetRAState(), 2922 kSaveFPRegs, 2923 EMIT_REMEMBERED_SET, 2924 check_needed); 2925 } 2926 2927 __ bind(&skip_assignment); 2928 } 2929 2930 2931 void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) { 2932 HObjectAccess access = instr->hydrogen()->access(); 2933 int offset = access.offset(); 2934 Register object = ToRegister(instr->object()); 2935 2936 if (access.IsExternalMemory()) { 2937 Register result = ToRegister(instr->result()); 2938 __ lw(result, MemOperand(object, offset)); 2939 return; 2940 } 2941 2942 if (instr->hydrogen()->representation().IsDouble()) { 2943 DoubleRegister result = ToDoubleRegister(instr->result()); 2944 __ ldc1(result, FieldMemOperand(object, offset)); 2945 return; 2946 } 2947 2948 Register result = ToRegister(instr->result()); 2949 if (access.IsInobject()) { 2950 __ lw(result, FieldMemOperand(object, offset)); 2951 } else { 2952 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); 2953 __ lw(result, FieldMemOperand(result, offset)); 2954 } 2955 } 2956 2957 2958 void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) { 2959 ASSERT(ToRegister(instr->object()).is(a0)); 2960 ASSERT(ToRegister(instr->result()).is(v0)); 2961 2962 // Name is always in a2. 2963 __ li(a2, Operand(instr->name())); 2964 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); 2965 CallCode(ic, RelocInfo::CODE_TARGET, instr); 2966 } 2967 2968 2969 void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) { 2970 Register scratch = scratch0(); 2971 Register function = ToRegister(instr->function()); 2972 Register result = ToRegister(instr->result()); 2973 2974 // Check that the function really is a function. Load map into the 2975 // result register. 2976 __ GetObjectType(function, result, scratch); 2977 DeoptimizeIf(ne, instr->environment(), scratch, Operand(JS_FUNCTION_TYPE)); 2978 2979 // Make sure that the function has an instance prototype. 2980 Label non_instance; 2981 __ lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset)); 2982 __ And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype)); 2983 __ Branch(&non_instance, ne, scratch, Operand(zero_reg)); 2984 2985 // Get the prototype or initial map from the function. 2986 __ lw(result, 2987 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); 2988 2989 // Check that the function has a prototype or an initial map. 2990 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); 2991 DeoptimizeIf(eq, instr->environment(), result, Operand(at)); 2992 2993 // If the function does not have an initial map, we're done. 2994 Label done; 2995 __ GetObjectType(result, scratch, scratch); 2996 __ Branch(&done, ne, scratch, Operand(MAP_TYPE)); 2997 2998 // Get the prototype from the initial map. 2999 __ lw(result, FieldMemOperand(result, Map::kPrototypeOffset)); 3000 __ Branch(&done); 3001 3002 // Non-instance prototype: Fetch prototype from constructor field 3003 // in initial map. 3004 __ bind(&non_instance); 3005 __ lw(result, FieldMemOperand(result, Map::kConstructorOffset)); 3006 3007 // All done. 3008 __ bind(&done); 3009 } 3010 3011 3012 void LCodeGen::DoLoadExternalArrayPointer( 3013 LLoadExternalArrayPointer* instr) { 3014 Register to_reg = ToRegister(instr->result()); 3015 Register from_reg = ToRegister(instr->object()); 3016 __ lw(to_reg, FieldMemOperand(from_reg, 3017 ExternalArray::kExternalPointerOffset)); 3018 } 3019 3020 3021 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { 3022 Register arguments = ToRegister(instr->arguments()); 3023 Register result = ToRegister(instr->result()); 3024 if (instr->length()->IsConstantOperand() && 3025 instr->index()->IsConstantOperand()) { 3026 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); 3027 int const_length = ToInteger32(LConstantOperand::cast(instr->length())); 3028 int index = (const_length - const_index) + 1; 3029 __ lw(result, MemOperand(arguments, index * kPointerSize)); 3030 } else { 3031 Register length = ToRegister(instr->length()); 3032 Register index = ToRegister(instr->index()); 3033 // There are two words between the frame pointer and the last argument. 3034 // Subtracting from length accounts for one of them, add one more. 3035 __ subu(length, length, index); 3036 __ Addu(length, length, Operand(1)); 3037 __ sll(length, length, kPointerSizeLog2); 3038 __ Addu(at, arguments, Operand(length)); 3039 __ lw(result, MemOperand(at, 0)); 3040 } 3041 } 3042 3043 3044 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { 3045 Register external_pointer = ToRegister(instr->elements()); 3046 Register key = no_reg; 3047 ElementsKind elements_kind = instr->elements_kind(); 3048 bool key_is_constant = instr->key()->IsConstantOperand(); 3049 int constant_key = 0; 3050 if (key_is_constant) { 3051 constant_key = ToInteger32(LConstantOperand::cast(instr->key())); 3052 if (constant_key & 0xF0000000) { 3053 Abort(kArrayIndexConstantValueTooBig); 3054 } 3055 } else { 3056 key = ToRegister(instr->key()); 3057 } 3058 int element_size_shift = ElementsKindToShiftSize(elements_kind); 3059 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) 3060 ? (element_size_shift - kSmiTagSize) : element_size_shift; 3061 int additional_offset = instr->additional_index() << element_size_shift; 3062 3063 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || 3064 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 3065 FPURegister result = ToDoubleRegister(instr->result()); 3066 if (key_is_constant) { 3067 __ Addu(scratch0(), external_pointer, constant_key << element_size_shift); 3068 } else { 3069 __ sll(scratch0(), key, shift_size); 3070 __ Addu(scratch0(), scratch0(), external_pointer); 3071 } 3072 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { 3073 __ lwc1(result, MemOperand(scratch0(), additional_offset)); 3074 __ cvt_d_s(result, result); 3075 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS 3076 __ ldc1(result, MemOperand(scratch0(), additional_offset)); 3077 } 3078 } else { 3079 Register result = ToRegister(instr->result()); 3080 MemOperand mem_operand = PrepareKeyedOperand( 3081 key, external_pointer, key_is_constant, constant_key, 3082 element_size_shift, shift_size, 3083 instr->additional_index(), additional_offset); 3084 switch (elements_kind) { 3085 case EXTERNAL_BYTE_ELEMENTS: 3086 __ lb(result, mem_operand); 3087 break; 3088 case EXTERNAL_PIXEL_ELEMENTS: 3089 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 3090 __ lbu(result, mem_operand); 3091 break; 3092 case EXTERNAL_SHORT_ELEMENTS: 3093 __ lh(result, mem_operand); 3094 break; 3095 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 3096 __ lhu(result, mem_operand); 3097 break; 3098 case EXTERNAL_INT_ELEMENTS: 3099 __ lw(result, mem_operand); 3100 break; 3101 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 3102 __ lw(result, mem_operand); 3103 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { 3104 DeoptimizeIf(Ugreater_equal, instr->environment(), 3105 result, Operand(0x80000000)); 3106 } 3107 break; 3108 case EXTERNAL_FLOAT_ELEMENTS: 3109 case EXTERNAL_DOUBLE_ELEMENTS: 3110 case FAST_DOUBLE_ELEMENTS: 3111 case FAST_ELEMENTS: 3112 case FAST_SMI_ELEMENTS: 3113 case FAST_HOLEY_DOUBLE_ELEMENTS: 3114 case FAST_HOLEY_ELEMENTS: 3115 case FAST_HOLEY_SMI_ELEMENTS: 3116 case DICTIONARY_ELEMENTS: 3117 case NON_STRICT_ARGUMENTS_ELEMENTS: 3118 UNREACHABLE(); 3119 break; 3120 } 3121 } 3122 } 3123 3124 3125 void LCodeGen::DoLoadKeyedFixedDoubleArray(LLoadKeyed* instr) { 3126 Register elements = ToRegister(instr->elements()); 3127 bool key_is_constant = instr->key()->IsConstantOperand(); 3128 Register key = no_reg; 3129 DoubleRegister result = ToDoubleRegister(instr->result()); 3130 Register scratch = scratch0(); 3131 3132 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); 3133 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) 3134 ? (element_size_shift - kSmiTagSize) : element_size_shift; 3135 int constant_key = 0; 3136 if (key_is_constant) { 3137 constant_key = ToInteger32(LConstantOperand::cast(instr->key())); 3138 if (constant_key & 0xF0000000) { 3139 Abort(kArrayIndexConstantValueTooBig); 3140 } 3141 } else { 3142 key = ToRegister(instr->key()); 3143 } 3144 3145 int base_offset = (FixedDoubleArray::kHeaderSize - kHeapObjectTag) + 3146 ((constant_key + instr->additional_index()) << element_size_shift); 3147 if (!key_is_constant) { 3148 __ sll(scratch, key, shift_size); 3149 __ Addu(elements, elements, scratch); 3150 } 3151 __ Addu(elements, elements, Operand(base_offset)); 3152 __ ldc1(result, MemOperand(elements)); 3153 if (instr->hydrogen()->RequiresHoleCheck()) { 3154 __ lw(scratch, MemOperand(elements, sizeof(kHoleNanLower32))); 3155 DeoptimizeIf(eq, instr->environment(), scratch, Operand(kHoleNanUpper32)); 3156 } 3157 } 3158 3159 3160 void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { 3161 Register elements = ToRegister(instr->elements()); 3162 Register result = ToRegister(instr->result()); 3163 Register scratch = scratch0(); 3164 Register store_base = scratch; 3165 int offset = 0; 3166 3167 if (instr->key()->IsConstantOperand()) { 3168 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); 3169 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + 3170 instr->additional_index()); 3171 store_base = elements; 3172 } else { 3173 Register key = EmitLoadRegister(instr->key(), scratch0()); 3174 // Even though the HLoadKeyed instruction forces the input 3175 // representation for the key to be an integer, the input gets replaced 3176 // during bound check elimination with the index argument to the bounds 3177 // check, which can be tagged, so that case must be handled here, too. 3178 if (instr->hydrogen()->key()->representation().IsSmi()) { 3179 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize); 3180 __ addu(scratch, elements, scratch); 3181 } else { 3182 __ sll(scratch, key, kPointerSizeLog2); 3183 __ addu(scratch, elements, scratch); 3184 } 3185 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); 3186 } 3187 __ lw(result, FieldMemOperand(store_base, offset)); 3188 3189 // Check for the hole value. 3190 if (instr->hydrogen()->RequiresHoleCheck()) { 3191 if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) { 3192 __ And(scratch, result, Operand(kSmiTagMask)); 3193 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); 3194 } else { 3195 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); 3196 DeoptimizeIf(eq, instr->environment(), result, Operand(scratch)); 3197 } 3198 } 3199 } 3200 3201 3202 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { 3203 if (instr->is_external()) { 3204 DoLoadKeyedExternalArray(instr); 3205 } else if (instr->hydrogen()->representation().IsDouble()) { 3206 DoLoadKeyedFixedDoubleArray(instr); 3207 } else { 3208 DoLoadKeyedFixedArray(instr); 3209 } 3210 } 3211 3212 3213 MemOperand LCodeGen::PrepareKeyedOperand(Register key, 3214 Register base, 3215 bool key_is_constant, 3216 int constant_key, 3217 int element_size, 3218 int shift_size, 3219 int additional_index, 3220 int additional_offset) { 3221 if (additional_index != 0 && !key_is_constant) { 3222 additional_index *= 1 << (element_size - shift_size); 3223 __ Addu(scratch0(), key, Operand(additional_index)); 3224 } 3225 3226 if (key_is_constant) { 3227 return MemOperand(base, 3228 (constant_key << element_size) + additional_offset); 3229 } 3230 3231 if (additional_index == 0) { 3232 if (shift_size >= 0) { 3233 __ sll(scratch0(), key, shift_size); 3234 __ Addu(scratch0(), base, scratch0()); 3235 return MemOperand(scratch0()); 3236 } else { 3237 ASSERT_EQ(-1, shift_size); 3238 __ srl(scratch0(), key, 1); 3239 __ Addu(scratch0(), base, scratch0()); 3240 return MemOperand(scratch0()); 3241 } 3242 } 3243 3244 if (shift_size >= 0) { 3245 __ sll(scratch0(), scratch0(), shift_size); 3246 __ Addu(scratch0(), base, scratch0()); 3247 return MemOperand(scratch0()); 3248 } else { 3249 ASSERT_EQ(-1, shift_size); 3250 __ srl(scratch0(), scratch0(), 1); 3251 __ Addu(scratch0(), base, scratch0()); 3252 return MemOperand(scratch0()); 3253 } 3254 } 3255 3256 3257 void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) { 3258 ASSERT(ToRegister(instr->object()).is(a1)); 3259 ASSERT(ToRegister(instr->key()).is(a0)); 3260 3261 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); 3262 CallCode(ic, RelocInfo::CODE_TARGET, instr); 3263 } 3264 3265 3266 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { 3267 Register scratch = scratch0(); 3268 Register temp = scratch1(); 3269 Register result = ToRegister(instr->result()); 3270 3271 if (instr->hydrogen()->from_inlined()) { 3272 __ Subu(result, sp, 2 * kPointerSize); 3273 } else { 3274 // Check if the calling frame is an arguments adaptor frame. 3275 Label done, adapted; 3276 __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 3277 __ lw(result, MemOperand(scratch, StandardFrameConstants::kContextOffset)); 3278 __ Xor(temp, result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3279 3280 // Result is the frame pointer for the frame if not adapted and for the real 3281 // frame below the adaptor frame if adapted. 3282 __ Movn(result, fp, temp); // Move only if temp is not equal to zero (ne). 3283 __ Movz(result, scratch, temp); // Move only if temp is equal to zero (eq). 3284 } 3285 } 3286 3287 3288 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { 3289 Register elem = ToRegister(instr->elements()); 3290 Register result = ToRegister(instr->result()); 3291 3292 Label done; 3293 3294 // If no arguments adaptor frame the number of arguments is fixed. 3295 __ Addu(result, zero_reg, Operand(scope()->num_parameters())); 3296 __ Branch(&done, eq, fp, Operand(elem)); 3297 3298 // Arguments adaptor frame present. Get argument length from there. 3299 __ lw(result, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 3300 __ lw(result, 3301 MemOperand(result, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3302 __ SmiUntag(result); 3303 3304 // Argument length is in result register. 3305 __ bind(&done); 3306 } 3307 3308 3309 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { 3310 Register receiver = ToRegister(instr->receiver()); 3311 Register function = ToRegister(instr->function()); 3312 Register scratch = scratch0(); 3313 3314 // If the receiver is null or undefined, we have to pass the global 3315 // object as a receiver to normal functions. Values have to be 3316 // passed unchanged to builtins and strict-mode functions. 3317 Label global_object, receiver_ok; 3318 3319 // Do not transform the receiver to object for strict mode 3320 // functions. 3321 __ lw(scratch, 3322 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset)); 3323 __ lw(scratch, 3324 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset)); 3325 3326 // Do not transform the receiver to object for builtins. 3327 int32_t strict_mode_function_mask = 3328 1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize); 3329 int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize); 3330 __ And(scratch, scratch, Operand(strict_mode_function_mask | native_mask)); 3331 __ Branch(&receiver_ok, ne, scratch, Operand(zero_reg)); 3332 3333 // Normal function. Replace undefined or null with global receiver. 3334 __ LoadRoot(scratch, Heap::kNullValueRootIndex); 3335 __ Branch(&global_object, eq, receiver, Operand(scratch)); 3336 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); 3337 __ Branch(&global_object, eq, receiver, Operand(scratch)); 3338 3339 // Deoptimize if the receiver is not a JS object. 3340 __ And(scratch, receiver, Operand(kSmiTagMask)); 3341 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); 3342 3343 __ GetObjectType(receiver, scratch, scratch); 3344 DeoptimizeIf(lt, instr->environment(), 3345 scratch, Operand(FIRST_SPEC_OBJECT_TYPE)); 3346 __ Branch(&receiver_ok); 3347 3348 __ bind(&global_object); 3349 __ lw(receiver, GlobalObjectOperand()); 3350 __ lw(receiver, 3351 FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset)); 3352 __ bind(&receiver_ok); 3353 } 3354 3355 3356 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { 3357 Register receiver = ToRegister(instr->receiver()); 3358 Register function = ToRegister(instr->function()); 3359 Register length = ToRegister(instr->length()); 3360 Register elements = ToRegister(instr->elements()); 3361 Register scratch = scratch0(); 3362 ASSERT(receiver.is(a0)); // Used for parameter count. 3363 ASSERT(function.is(a1)); // Required by InvokeFunction. 3364 ASSERT(ToRegister(instr->result()).is(v0)); 3365 3366 // Copy the arguments to this function possibly from the 3367 // adaptor frame below it. 3368 const uint32_t kArgumentsLimit = 1 * KB; 3369 DeoptimizeIf(hi, instr->environment(), length, Operand(kArgumentsLimit)); 3370 3371 // Push the receiver and use the register to keep the original 3372 // number of arguments. 3373 __ push(receiver); 3374 __ Move(receiver, length); 3375 // The arguments are at a one pointer size offset from elements. 3376 __ Addu(elements, elements, Operand(1 * kPointerSize)); 3377 3378 // Loop through the arguments pushing them onto the execution 3379 // stack. 3380 Label invoke, loop; 3381 // length is a small non-negative integer, due to the test above. 3382 __ Branch(USE_DELAY_SLOT, &invoke, eq, length, Operand(zero_reg)); 3383 __ sll(scratch, length, 2); 3384 __ bind(&loop); 3385 __ Addu(scratch, elements, scratch); 3386 __ lw(scratch, MemOperand(scratch)); 3387 __ push(scratch); 3388 __ Subu(length, length, Operand(1)); 3389 __ Branch(USE_DELAY_SLOT, &loop, ne, length, Operand(zero_reg)); 3390 __ sll(scratch, length, 2); 3391 3392 __ bind(&invoke); 3393 ASSERT(instr->HasPointerMap()); 3394 LPointerMap* pointers = instr->pointer_map(); 3395 RecordPosition(pointers->position()); 3396 SafepointGenerator safepoint_generator( 3397 this, pointers, Safepoint::kLazyDeopt); 3398 // The number of arguments is stored in receiver which is a0, as expected 3399 // by InvokeFunction. 3400 ParameterCount actual(receiver); 3401 __ InvokeFunction(function, actual, CALL_FUNCTION, 3402 safepoint_generator, CALL_AS_METHOD); 3403 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3404 } 3405 3406 3407 void LCodeGen::DoPushArgument(LPushArgument* instr) { 3408 LOperand* argument = instr->value(); 3409 if (argument->IsDoubleRegister() || argument->IsDoubleStackSlot()) { 3410 Abort(kDoPushArgumentNotImplementedForDoubleType); 3411 } else { 3412 Register argument_reg = EmitLoadRegister(argument, at); 3413 __ push(argument_reg); 3414 } 3415 } 3416 3417 3418 void LCodeGen::DoDrop(LDrop* instr) { 3419 __ Drop(instr->count()); 3420 } 3421 3422 3423 void LCodeGen::DoThisFunction(LThisFunction* instr) { 3424 Register result = ToRegister(instr->result()); 3425 __ lw(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 3426 } 3427 3428 3429 void LCodeGen::DoContext(LContext* instr) { 3430 // If there is a non-return use, the context must be moved to a register. 3431 Register result = ToRegister(instr->result()); 3432 for (HUseIterator it(instr->hydrogen()->uses()); !it.Done(); it.Advance()) { 3433 if (!it.value()->IsReturn()) { 3434 __ mov(result, cp); 3435 return; 3436 } 3437 } 3438 } 3439 3440 3441 void LCodeGen::DoOuterContext(LOuterContext* instr) { 3442 Register context = ToRegister(instr->context()); 3443 Register result = ToRegister(instr->result()); 3444 __ lw(result, 3445 MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX))); 3446 } 3447 3448 3449 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { 3450 __ LoadHeapObject(scratch0(), instr->hydrogen()->pairs()); 3451 __ li(scratch1(), Operand(Smi::FromInt(instr->hydrogen()->flags()))); 3452 // The context is the first argument. 3453 __ Push(cp, scratch0(), scratch1()); 3454 CallRuntime(Runtime::kDeclareGlobals, 3, instr); 3455 } 3456 3457 3458 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { 3459 Register result = ToRegister(instr->result()); 3460 __ lw(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); 3461 } 3462 3463 3464 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { 3465 Register global = ToRegister(instr->global_object()); 3466 Register result = ToRegister(instr->result()); 3467 __ lw(result, FieldMemOperand(global, GlobalObject::kGlobalReceiverOffset)); 3468 } 3469 3470 3471 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, 3472 int formal_parameter_count, 3473 int arity, 3474 LInstruction* instr, 3475 CallKind call_kind, 3476 A1State a1_state) { 3477 bool dont_adapt_arguments = 3478 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; 3479 bool can_invoke_directly = 3480 dont_adapt_arguments || formal_parameter_count == arity; 3481 3482 LPointerMap* pointers = instr->pointer_map(); 3483 RecordPosition(pointers->position()); 3484 3485 if (can_invoke_directly) { 3486 if (a1_state == A1_UNINITIALIZED) { 3487 __ LoadHeapObject(a1, function); 3488 } 3489 3490 // Change context. 3491 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); 3492 3493 // Set r0 to arguments count if adaption is not needed. Assumes that r0 3494 // is available to write to at this point. 3495 if (dont_adapt_arguments) { 3496 __ li(a0, Operand(arity)); 3497 } 3498 3499 // Invoke function. 3500 __ SetCallKind(t1, call_kind); 3501 __ lw(at, FieldMemOperand(a1, JSFunction::kCodeEntryOffset)); 3502 __ Call(at); 3503 3504 // Set up deoptimization. 3505 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT); 3506 } else { 3507 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); 3508 ParameterCount count(arity); 3509 ParameterCount expected(formal_parameter_count); 3510 __ InvokeFunction( 3511 function, expected, count, CALL_FUNCTION, generator, call_kind); 3512 } 3513 3514 // Restore context. 3515 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3516 } 3517 3518 3519 void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) { 3520 ASSERT(ToRegister(instr->result()).is(v0)); 3521 __ mov(a0, v0); 3522 CallKnownFunction(instr->hydrogen()->function(), 3523 instr->hydrogen()->formal_parameter_count(), 3524 instr->arity(), 3525 instr, 3526 CALL_AS_METHOD, 3527 A1_UNINITIALIZED); 3528 } 3529 3530 3531 void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr) { 3532 Register input = ToRegister(instr->value()); 3533 Register result = ToRegister(instr->result()); 3534 Register scratch = scratch0(); 3535 3536 // Deoptimize if not a heap number. 3537 __ lw(scratch, FieldMemOperand(input, HeapObject::kMapOffset)); 3538 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 3539 DeoptimizeIf(ne, instr->environment(), scratch, Operand(at)); 3540 3541 Label done; 3542 Register exponent = scratch0(); 3543 scratch = no_reg; 3544 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); 3545 // Check the sign of the argument. If the argument is positive, just 3546 // return it. 3547 __ Move(result, input); 3548 __ And(at, exponent, Operand(HeapNumber::kSignMask)); 3549 __ Branch(&done, eq, at, Operand(zero_reg)); 3550 3551 // Input is negative. Reverse its sign. 3552 // Preserve the value of all registers. 3553 { 3554 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 3555 3556 // Registers were saved at the safepoint, so we can use 3557 // many scratch registers. 3558 Register tmp1 = input.is(a1) ? a0 : a1; 3559 Register tmp2 = input.is(a2) ? a0 : a2; 3560 Register tmp3 = input.is(a3) ? a0 : a3; 3561 Register tmp4 = input.is(t0) ? a0 : t0; 3562 3563 // exponent: floating point exponent value. 3564 3565 Label allocated, slow; 3566 __ LoadRoot(tmp4, Heap::kHeapNumberMapRootIndex); 3567 __ AllocateHeapNumber(tmp1, tmp2, tmp3, tmp4, &slow); 3568 __ Branch(&allocated); 3569 3570 // Slow case: Call the runtime system to do the number allocation. 3571 __ bind(&slow); 3572 3573 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); 3574 // Set the pointer to the new heap number in tmp. 3575 if (!tmp1.is(v0)) 3576 __ mov(tmp1, v0); 3577 // Restore input_reg after call to runtime. 3578 __ LoadFromSafepointRegisterSlot(input, input); 3579 __ lw(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset)); 3580 3581 __ bind(&allocated); 3582 // exponent: floating point exponent value. 3583 // tmp1: allocated heap number. 3584 __ And(exponent, exponent, Operand(~HeapNumber::kSignMask)); 3585 __ sw(exponent, FieldMemOperand(tmp1, HeapNumber::kExponentOffset)); 3586 __ lw(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset)); 3587 __ sw(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset)); 3588 3589 __ StoreToSafepointRegisterSlot(tmp1, result); 3590 } 3591 3592 __ bind(&done); 3593 } 3594 3595 3596 void LCodeGen::EmitIntegerMathAbs(LMathAbs* instr) { 3597 Register input = ToRegister(instr->value()); 3598 Register result = ToRegister(instr->result()); 3599 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); 3600 Label done; 3601 __ Branch(USE_DELAY_SLOT, &done, ge, input, Operand(zero_reg)); 3602 __ mov(result, input); 3603 __ subu(result, zero_reg, input); 3604 // Overflow if result is still negative, i.e. 0x80000000. 3605 DeoptimizeIf(lt, instr->environment(), result, Operand(zero_reg)); 3606 __ bind(&done); 3607 } 3608 3609 3610 void LCodeGen::DoMathAbs(LMathAbs* instr) { 3611 // Class for deferred case. 3612 class DeferredMathAbsTaggedHeapNumber: public LDeferredCode { 3613 public: 3614 DeferredMathAbsTaggedHeapNumber(LCodeGen* codegen, LMathAbs* instr) 3615 : LDeferredCode(codegen), instr_(instr) { } 3616 virtual void Generate() { 3617 codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); 3618 } 3619 virtual LInstruction* instr() { return instr_; } 3620 private: 3621 LMathAbs* instr_; 3622 }; 3623 3624 Representation r = instr->hydrogen()->value()->representation(); 3625 if (r.IsDouble()) { 3626 FPURegister input = ToDoubleRegister(instr->value()); 3627 FPURegister result = ToDoubleRegister(instr->result()); 3628 __ abs_d(result, input); 3629 } else if (r.IsSmiOrInteger32()) { 3630 EmitIntegerMathAbs(instr); 3631 } else { 3632 // Representation is tagged. 3633 DeferredMathAbsTaggedHeapNumber* deferred = 3634 new(zone()) DeferredMathAbsTaggedHeapNumber(this, instr); 3635 Register input = ToRegister(instr->value()); 3636 // Smi check. 3637 __ JumpIfNotSmi(input, deferred->entry()); 3638 // If smi, handle it directly. 3639 EmitIntegerMathAbs(instr); 3640 __ bind(deferred->exit()); 3641 } 3642 } 3643 3644 3645 void LCodeGen::DoMathFloor(LMathFloor* instr) { 3646 DoubleRegister input = ToDoubleRegister(instr->value()); 3647 Register result = ToRegister(instr->result()); 3648 Register scratch1 = scratch0(); 3649 Register except_flag = ToRegister(instr->temp()); 3650 3651 __ EmitFPUTruncate(kRoundToMinusInf, 3652 result, 3653 input, 3654 scratch1, 3655 double_scratch0(), 3656 except_flag); 3657 3658 // Deopt if the operation did not succeed. 3659 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); 3660 3661 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3662 // Test for -0. 3663 Label done; 3664 __ Branch(&done, ne, result, Operand(zero_reg)); 3665 __ mfc1(scratch1, input.high()); 3666 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask)); 3667 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg)); 3668 __ bind(&done); 3669 } 3670 } 3671 3672 3673 void LCodeGen::DoMathRound(LMathRound* instr) { 3674 DoubleRegister input = ToDoubleRegister(instr->value()); 3675 Register result = ToRegister(instr->result()); 3676 DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp()); 3677 Register scratch = scratch0(); 3678 Label done, check_sign_on_zero; 3679 3680 // Extract exponent bits. 3681 __ mfc1(result, input.high()); 3682 __ Ext(scratch, 3683 result, 3684 HeapNumber::kExponentShift, 3685 HeapNumber::kExponentBits); 3686 3687 // If the number is in ]-0.5, +0.5[, the result is +/- 0. 3688 Label skip1; 3689 __ Branch(&skip1, gt, scratch, Operand(HeapNumber::kExponentBias - 2)); 3690 __ mov(result, zero_reg); 3691 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3692 __ Branch(&check_sign_on_zero); 3693 } else { 3694 __ Branch(&done); 3695 } 3696 __ bind(&skip1); 3697 3698 // The following conversion will not work with numbers 3699 // outside of ]-2^32, 2^32[. 3700 DeoptimizeIf(ge, instr->environment(), scratch, 3701 Operand(HeapNumber::kExponentBias + 32)); 3702 3703 // Save the original sign for later comparison. 3704 __ And(scratch, result, Operand(HeapNumber::kSignMask)); 3705 3706 __ Move(double_scratch0(), 0.5); 3707 __ add_d(double_scratch0(), input, double_scratch0()); 3708 3709 // Check sign of the result: if the sign changed, the input 3710 // value was in ]0.5, 0[ and the result should be -0. 3711 __ mfc1(result, double_scratch0().high()); 3712 __ Xor(result, result, Operand(scratch)); 3713 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3714 // ARM uses 'mi' here, which is 'lt' 3715 DeoptimizeIf(lt, instr->environment(), result, 3716 Operand(zero_reg)); 3717 } else { 3718 Label skip2; 3719 // ARM uses 'mi' here, which is 'lt' 3720 // Negating it results in 'ge' 3721 __ Branch(&skip2, ge, result, Operand(zero_reg)); 3722 __ mov(result, zero_reg); 3723 __ Branch(&done); 3724 __ bind(&skip2); 3725 } 3726 3727 Register except_flag = scratch; 3728 __ EmitFPUTruncate(kRoundToMinusInf, 3729 result, 3730 double_scratch0(), 3731 at, 3732 double_scratch1, 3733 except_flag); 3734 3735 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); 3736 3737 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 3738 // Test for -0. 3739 __ Branch(&done, ne, result, Operand(zero_reg)); 3740 __ bind(&check_sign_on_zero); 3741 __ mfc1(scratch, input.high()); 3742 __ And(scratch, scratch, Operand(HeapNumber::kSignMask)); 3743 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); 3744 } 3745 __ bind(&done); 3746 } 3747 3748 3749 void LCodeGen::DoMathSqrt(LMathSqrt* instr) { 3750 DoubleRegister input = ToDoubleRegister(instr->value()); 3751 DoubleRegister result = ToDoubleRegister(instr->result()); 3752 __ sqrt_d(result, input); 3753 } 3754 3755 3756 void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) { 3757 DoubleRegister input = ToDoubleRegister(instr->value()); 3758 DoubleRegister result = ToDoubleRegister(instr->result()); 3759 DoubleRegister temp = ToDoubleRegister(instr->temp()); 3760 3761 ASSERT(!input.is(result)); 3762 3763 // Note that according to ECMA-262 15.8.2.13: 3764 // Math.pow(-Infinity, 0.5) == Infinity 3765 // Math.sqrt(-Infinity) == NaN 3766 Label done; 3767 __ Move(temp, -V8_INFINITY); 3768 __ BranchF(USE_DELAY_SLOT, &done, NULL, eq, temp, input); 3769 // Set up Infinity in the delay slot. 3770 // result is overwritten if the branch is not taken. 3771 __ neg_d(result, temp); 3772 3773 // Add +0 to convert -0 to +0. 3774 __ add_d(result, input, kDoubleRegZero); 3775 __ sqrt_d(result, result); 3776 __ bind(&done); 3777 } 3778 3779 3780 void LCodeGen::DoPower(LPower* instr) { 3781 Representation exponent_type = instr->hydrogen()->right()->representation(); 3782 // Having marked this as a call, we can use any registers. 3783 // Just make sure that the input/output registers are the expected ones. 3784 ASSERT(!instr->right()->IsDoubleRegister() || 3785 ToDoubleRegister(instr->right()).is(f4)); 3786 ASSERT(!instr->right()->IsRegister() || 3787 ToRegister(instr->right()).is(a2)); 3788 ASSERT(ToDoubleRegister(instr->left()).is(f2)); 3789 ASSERT(ToDoubleRegister(instr->result()).is(f0)); 3790 3791 if (exponent_type.IsSmi()) { 3792 MathPowStub stub(MathPowStub::TAGGED); 3793 __ CallStub(&stub); 3794 } else if (exponent_type.IsTagged()) { 3795 Label no_deopt; 3796 __ JumpIfSmi(a2, &no_deopt); 3797 __ lw(t3, FieldMemOperand(a2, HeapObject::kMapOffset)); 3798 DeoptimizeIf(ne, instr->environment(), t3, Operand(at)); 3799 __ bind(&no_deopt); 3800 MathPowStub stub(MathPowStub::TAGGED); 3801 __ CallStub(&stub); 3802 } else if (exponent_type.IsInteger32()) { 3803 MathPowStub stub(MathPowStub::INTEGER); 3804 __ CallStub(&stub); 3805 } else { 3806 ASSERT(exponent_type.IsDouble()); 3807 MathPowStub stub(MathPowStub::DOUBLE); 3808 __ CallStub(&stub); 3809 } 3810 } 3811 3812 3813 void LCodeGen::DoRandom(LRandom* instr) { 3814 class DeferredDoRandom: public LDeferredCode { 3815 public: 3816 DeferredDoRandom(LCodeGen* codegen, LRandom* instr) 3817 : LDeferredCode(codegen), instr_(instr) { } 3818 virtual void Generate() { codegen()->DoDeferredRandom(instr_); } 3819 virtual LInstruction* instr() { return instr_; } 3820 private: 3821 LRandom* instr_; 3822 }; 3823 3824 DeferredDoRandom* deferred = new(zone()) DeferredDoRandom(this, instr); 3825 // Having marked this instruction as a call we can use any 3826 // registers. 3827 ASSERT(ToDoubleRegister(instr->result()).is(f0)); 3828 ASSERT(ToRegister(instr->global_object()).is(a0)); 3829 3830 static const int kSeedSize = sizeof(uint32_t); 3831 STATIC_ASSERT(kPointerSize == kSeedSize); 3832 3833 __ lw(a0, FieldMemOperand(a0, GlobalObject::kNativeContextOffset)); 3834 static const int kRandomSeedOffset = 3835 FixedArray::kHeaderSize + Context::RANDOM_SEED_INDEX * kPointerSize; 3836 __ lw(a2, FieldMemOperand(a0, kRandomSeedOffset)); 3837 // a2: FixedArray of the native context's random seeds 3838 3839 // Load state[0]. 3840 __ lw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize)); 3841 __ Branch(deferred->entry(), eq, a1, Operand(zero_reg)); 3842 // Load state[1]. 3843 __ lw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize)); 3844 // a1: state[0]. 3845 // a0: state[1]. 3846 3847 // state[0] = 18273 * (state[0] & 0xFFFF) + (state[0] >> 16) 3848 __ And(a3, a1, Operand(0xFFFF)); 3849 __ li(t0, Operand(18273)); 3850 __ Mul(a3, a3, t0); 3851 __ srl(a1, a1, 16); 3852 __ Addu(a1, a3, a1); 3853 // Save state[0]. 3854 __ sw(a1, FieldMemOperand(a2, ByteArray::kHeaderSize)); 3855 3856 // state[1] = 36969 * (state[1] & 0xFFFF) + (state[1] >> 16) 3857 __ And(a3, a0, Operand(0xFFFF)); 3858 __ li(t0, Operand(36969)); 3859 __ Mul(a3, a3, t0); 3860 __ srl(a0, a0, 16), 3861 __ Addu(a0, a3, a0); 3862 // Save state[1]. 3863 __ sw(a0, FieldMemOperand(a2, ByteArray::kHeaderSize + kSeedSize)); 3864 3865 // Random bit pattern = (state[0] << 14) + (state[1] & 0x3FFFF) 3866 __ And(a0, a0, Operand(0x3FFFF)); 3867 __ sll(a1, a1, 14); 3868 __ Addu(v0, a0, a1); 3869 3870 __ bind(deferred->exit()); 3871 3872 // 0x41300000 is the top half of 1.0 x 2^20 as a double. 3873 __ li(a2, Operand(0x41300000)); 3874 // Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU. 3875 __ Move(f12, v0, a2); 3876 // Move 0x4130000000000000 to FPU. 3877 __ Move(f14, zero_reg, a2); 3878 // Subtract to get the result. 3879 __ sub_d(f0, f12, f14); 3880 } 3881 3882 3883 void LCodeGen::DoDeferredRandom(LRandom* instr) { 3884 __ PrepareCallCFunction(1, scratch0()); 3885 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1); 3886 // Return value is in v0. 3887 } 3888 3889 3890 void LCodeGen::DoMathExp(LMathExp* instr) { 3891 DoubleRegister input = ToDoubleRegister(instr->value()); 3892 DoubleRegister result = ToDoubleRegister(instr->result()); 3893 DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp()); 3894 DoubleRegister double_scratch2 = double_scratch0(); 3895 Register temp1 = ToRegister(instr->temp1()); 3896 Register temp2 = ToRegister(instr->temp2()); 3897 3898 MathExpGenerator::EmitMathExp( 3899 masm(), input, result, double_scratch1, double_scratch2, 3900 temp1, temp2, scratch0()); 3901 } 3902 3903 3904 void LCodeGen::DoMathLog(LMathLog* instr) { 3905 ASSERT(ToDoubleRegister(instr->result()).is(f4)); 3906 TranscendentalCacheStub stub(TranscendentalCache::LOG, 3907 TranscendentalCacheStub::UNTAGGED); 3908 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 3909 } 3910 3911 3912 void LCodeGen::DoMathTan(LMathTan* instr) { 3913 ASSERT(ToDoubleRegister(instr->result()).is(f4)); 3914 TranscendentalCacheStub stub(TranscendentalCache::TAN, 3915 TranscendentalCacheStub::UNTAGGED); 3916 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 3917 } 3918 3919 3920 void LCodeGen::DoMathCos(LMathCos* instr) { 3921 ASSERT(ToDoubleRegister(instr->result()).is(f4)); 3922 TranscendentalCacheStub stub(TranscendentalCache::COS, 3923 TranscendentalCacheStub::UNTAGGED); 3924 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 3925 } 3926 3927 3928 void LCodeGen::DoMathSin(LMathSin* instr) { 3929 ASSERT(ToDoubleRegister(instr->result()).is(f4)); 3930 TranscendentalCacheStub stub(TranscendentalCache::SIN, 3931 TranscendentalCacheStub::UNTAGGED); 3932 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 3933 } 3934 3935 3936 void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) { 3937 ASSERT(ToRegister(instr->function()).is(a1)); 3938 ASSERT(instr->HasPointerMap()); 3939 3940 Handle<JSFunction> known_function = instr->hydrogen()->known_function(); 3941 if (known_function.is_null()) { 3942 LPointerMap* pointers = instr->pointer_map(); 3943 RecordPosition(pointers->position()); 3944 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); 3945 ParameterCount count(instr->arity()); 3946 __ InvokeFunction(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD); 3947 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3948 } else { 3949 CallKnownFunction(known_function, 3950 instr->hydrogen()->formal_parameter_count(), 3951 instr->arity(), 3952 instr, 3953 CALL_AS_METHOD, 3954 A1_CONTAINS_TARGET); 3955 } 3956 } 3957 3958 3959 void LCodeGen::DoCallKeyed(LCallKeyed* instr) { 3960 ASSERT(ToRegister(instr->result()).is(v0)); 3961 3962 int arity = instr->arity(); 3963 Handle<Code> ic = 3964 isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); 3965 CallCode(ic, RelocInfo::CODE_TARGET, instr); 3966 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3967 } 3968 3969 3970 void LCodeGen::DoCallNamed(LCallNamed* instr) { 3971 ASSERT(ToRegister(instr->result()).is(v0)); 3972 3973 int arity = instr->arity(); 3974 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; 3975 Handle<Code> ic = 3976 isolate()->stub_cache()->ComputeCallInitialize(arity, mode); 3977 __ li(a2, Operand(instr->name())); 3978 CallCode(ic, mode, instr); 3979 // Restore context register. 3980 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3981 } 3982 3983 3984 void LCodeGen::DoCallFunction(LCallFunction* instr) { 3985 ASSERT(ToRegister(instr->function()).is(a1)); 3986 ASSERT(ToRegister(instr->result()).is(v0)); 3987 3988 int arity = instr->arity(); 3989 CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); 3990 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 3991 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 3992 } 3993 3994 3995 void LCodeGen::DoCallGlobal(LCallGlobal* instr) { 3996 ASSERT(ToRegister(instr->result()).is(v0)); 3997 3998 int arity = instr->arity(); 3999 RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT; 4000 Handle<Code> ic = 4001 isolate()->stub_cache()->ComputeCallInitialize(arity, mode); 4002 __ li(a2, Operand(instr->name())); 4003 CallCode(ic, mode, instr); 4004 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 4005 } 4006 4007 4008 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) { 4009 ASSERT(ToRegister(instr->result()).is(v0)); 4010 CallKnownFunction(instr->hydrogen()->target(), 4011 instr->hydrogen()->formal_parameter_count(), 4012 instr->arity(), 4013 instr, 4014 CALL_AS_FUNCTION, 4015 A1_UNINITIALIZED); 4016 } 4017 4018 4019 void LCodeGen::DoCallNew(LCallNew* instr) { 4020 ASSERT(ToRegister(instr->constructor()).is(a1)); 4021 ASSERT(ToRegister(instr->result()).is(v0)); 4022 4023 __ li(a0, Operand(instr->arity())); 4024 // No cell in a2 for construct type feedback in optimized code 4025 Handle<Object> undefined_value(isolate()->factory()->undefined_value()); 4026 __ li(a2, Operand(undefined_value)); 4027 CallConstructStub stub(NO_CALL_FUNCTION_FLAGS); 4028 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); 4029 } 4030 4031 4032 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { 4033 ASSERT(ToRegister(instr->constructor()).is(a1)); 4034 ASSERT(ToRegister(instr->result()).is(v0)); 4035 4036 __ li(a0, Operand(instr->arity())); 4037 __ li(a2, Operand(instr->hydrogen()->property_cell())); 4038 ElementsKind kind = instr->hydrogen()->elements_kind(); 4039 AllocationSiteOverrideMode override_mode = 4040 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) 4041 ? DISABLE_ALLOCATION_SITES 4042 : DONT_OVERRIDE; 4043 ContextCheckMode context_mode = CONTEXT_CHECK_NOT_REQUIRED; 4044 4045 if (instr->arity() == 0) { 4046 ArrayNoArgumentConstructorStub stub(kind, context_mode, override_mode); 4047 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); 4048 } else if (instr->arity() == 1) { 4049 Label done; 4050 if (IsFastPackedElementsKind(kind)) { 4051 Label packed_case; 4052 // We might need a change here, 4053 // look at the first argument. 4054 __ lw(t1, MemOperand(sp, 0)); 4055 __ Branch(&packed_case, eq, t1, Operand(zero_reg)); 4056 4057 ElementsKind holey_kind = GetHoleyElementsKind(kind); 4058 ArraySingleArgumentConstructorStub stub(holey_kind, context_mode, 4059 override_mode); 4060 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); 4061 __ jmp(&done); 4062 __ bind(&packed_case); 4063 } 4064 4065 ArraySingleArgumentConstructorStub stub(kind, context_mode, override_mode); 4066 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); 4067 __ bind(&done); 4068 } else { 4069 ArrayNArgumentsConstructorStub stub(kind, context_mode, override_mode); 4070 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); 4071 } 4072 } 4073 4074 4075 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { 4076 CallRuntime(instr->function(), instr->arity(), instr); 4077 } 4078 4079 4080 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) { 4081 Register result = ToRegister(instr->result()); 4082 Register base = ToRegister(instr->base_object()); 4083 __ Addu(result, base, Operand(instr->offset())); 4084 } 4085 4086 4087 void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { 4088 Representation representation = instr->representation(); 4089 4090 Register object = ToRegister(instr->object()); 4091 Register scratch = scratch0(); 4092 HObjectAccess access = instr->hydrogen()->access(); 4093 int offset = access.offset(); 4094 4095 if (access.IsExternalMemory()) { 4096 Register value = ToRegister(instr->value()); 4097 __ sw(value, MemOperand(object, offset)); 4098 return; 4099 } 4100 4101 Handle<Map> transition = instr->transition(); 4102 4103 if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { 4104 Register value = ToRegister(instr->value()); 4105 if (!instr->hydrogen()->value()->type().IsHeapObject()) { 4106 __ And(scratch, value, Operand(kSmiTagMask)); 4107 DeoptimizeIf(eq, instr->environment(), scratch, Operand(zero_reg)); 4108 } 4109 } else if (FLAG_track_double_fields && representation.IsDouble()) { 4110 ASSERT(transition.is_null()); 4111 ASSERT(access.IsInobject()); 4112 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); 4113 DoubleRegister value = ToDoubleRegister(instr->value()); 4114 __ sdc1(value, FieldMemOperand(object, offset)); 4115 return; 4116 } 4117 4118 if (!transition.is_null()) { 4119 __ li(scratch, Operand(transition)); 4120 __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset)); 4121 if (instr->hydrogen()->NeedsWriteBarrierForMap()) { 4122 Register temp = ToRegister(instr->temp()); 4123 // Update the write barrier for the map field. 4124 __ RecordWriteField(object, 4125 HeapObject::kMapOffset, 4126 scratch, 4127 temp, 4128 GetRAState(), 4129 kSaveFPRegs, 4130 OMIT_REMEMBERED_SET, 4131 OMIT_SMI_CHECK); 4132 } 4133 } 4134 4135 // Do the store. 4136 Register value = ToRegister(instr->value()); 4137 ASSERT(!object.is(value)); 4138 SmiCheck check_needed = 4139 instr->hydrogen()->value()->IsHeapObject() 4140 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 4141 if (access.IsInobject()) { 4142 __ sw(value, FieldMemOperand(object, offset)); 4143 if (instr->hydrogen()->NeedsWriteBarrier()) { 4144 // Update the write barrier for the object for in-object properties. 4145 __ RecordWriteField(object, 4146 offset, 4147 value, 4148 scratch, 4149 GetRAState(), 4150 kSaveFPRegs, 4151 EMIT_REMEMBERED_SET, 4152 check_needed); 4153 } 4154 } else { 4155 __ lw(scratch, FieldMemOperand(object, JSObject::kPropertiesOffset)); 4156 __ sw(value, FieldMemOperand(scratch, offset)); 4157 if (instr->hydrogen()->NeedsWriteBarrier()) { 4158 // Update the write barrier for the properties array. 4159 // object is used as a scratch register. 4160 __ RecordWriteField(scratch, 4161 offset, 4162 value, 4163 object, 4164 GetRAState(), 4165 kSaveFPRegs, 4166 EMIT_REMEMBERED_SET, 4167 check_needed); 4168 } 4169 } 4170 } 4171 4172 4173 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { 4174 ASSERT(ToRegister(instr->object()).is(a1)); 4175 ASSERT(ToRegister(instr->value()).is(a0)); 4176 4177 // Name is always in a2. 4178 __ li(a2, Operand(instr->name())); 4179 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) 4180 ? isolate()->builtins()->StoreIC_Initialize_Strict() 4181 : isolate()->builtins()->StoreIC_Initialize(); 4182 CallCode(ic, RelocInfo::CODE_TARGET, instr); 4183 } 4184 4185 4186 void LCodeGen::ApplyCheckIf(Condition condition, 4187 LBoundsCheck* check, 4188 Register src1, 4189 const Operand& src2) { 4190 if (FLAG_debug_code && check->hydrogen()->skip_check()) { 4191 Label done; 4192 __ Branch(&done, NegateCondition(condition), src1, src2); 4193 __ stop("eliminated bounds check failed"); 4194 __ bind(&done); 4195 } else { 4196 DeoptimizeIf(condition, check->environment(), src1, src2); 4197 } 4198 } 4199 4200 4201 void LCodeGen::DoBoundsCheck(LBoundsCheck* instr) { 4202 if (instr->hydrogen()->skip_check()) return; 4203 4204 Condition condition = instr->hydrogen()->allow_equality() ? hi : hs; 4205 if (instr->index()->IsConstantOperand()) { 4206 int constant_index = 4207 ToInteger32(LConstantOperand::cast(instr->index())); 4208 if (instr->hydrogen()->length()->representation().IsSmi()) { 4209 __ li(at, Operand(Smi::FromInt(constant_index))); 4210 } else { 4211 __ li(at, Operand(constant_index)); 4212 } 4213 ApplyCheckIf(condition, 4214 instr, 4215 at, 4216 Operand(ToRegister(instr->length()))); 4217 } else { 4218 ApplyCheckIf(condition, 4219 instr, 4220 ToRegister(instr->index()), 4221 Operand(ToRegister(instr->length()))); 4222 } 4223 } 4224 4225 4226 void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { 4227 Register external_pointer = ToRegister(instr->elements()); 4228 Register key = no_reg; 4229 ElementsKind elements_kind = instr->elements_kind(); 4230 bool key_is_constant = instr->key()->IsConstantOperand(); 4231 int constant_key = 0; 4232 if (key_is_constant) { 4233 constant_key = ToInteger32(LConstantOperand::cast(instr->key())); 4234 if (constant_key & 0xF0000000) { 4235 Abort(kArrayIndexConstantValueTooBig); 4236 } 4237 } else { 4238 key = ToRegister(instr->key()); 4239 } 4240 int element_size_shift = ElementsKindToShiftSize(elements_kind); 4241 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) 4242 ? (element_size_shift - kSmiTagSize) : element_size_shift; 4243 int additional_offset = instr->additional_index() << element_size_shift; 4244 4245 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || 4246 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 4247 FPURegister value(ToDoubleRegister(instr->value())); 4248 if (key_is_constant) { 4249 __ Addu(scratch0(), external_pointer, constant_key << 4250 element_size_shift); 4251 } else { 4252 __ sll(scratch0(), key, shift_size); 4253 __ Addu(scratch0(), scratch0(), external_pointer); 4254 } 4255 4256 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { 4257 __ cvt_s_d(double_scratch0(), value); 4258 __ swc1(double_scratch0(), MemOperand(scratch0(), additional_offset)); 4259 } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS 4260 __ sdc1(value, MemOperand(scratch0(), additional_offset)); 4261 } 4262 } else { 4263 Register value(ToRegister(instr->value())); 4264 MemOperand mem_operand = PrepareKeyedOperand( 4265 key, external_pointer, key_is_constant, constant_key, 4266 element_size_shift, shift_size, 4267 instr->additional_index(), additional_offset); 4268 switch (elements_kind) { 4269 case EXTERNAL_PIXEL_ELEMENTS: 4270 case EXTERNAL_BYTE_ELEMENTS: 4271 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: 4272 __ sb(value, mem_operand); 4273 break; 4274 case EXTERNAL_SHORT_ELEMENTS: 4275 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: 4276 __ sh(value, mem_operand); 4277 break; 4278 case EXTERNAL_INT_ELEMENTS: 4279 case EXTERNAL_UNSIGNED_INT_ELEMENTS: 4280 __ sw(value, mem_operand); 4281 break; 4282 case EXTERNAL_FLOAT_ELEMENTS: 4283 case EXTERNAL_DOUBLE_ELEMENTS: 4284 case FAST_DOUBLE_ELEMENTS: 4285 case FAST_ELEMENTS: 4286 case FAST_SMI_ELEMENTS: 4287 case FAST_HOLEY_DOUBLE_ELEMENTS: 4288 case FAST_HOLEY_ELEMENTS: 4289 case FAST_HOLEY_SMI_ELEMENTS: 4290 case DICTIONARY_ELEMENTS: 4291 case NON_STRICT_ARGUMENTS_ELEMENTS: 4292 UNREACHABLE(); 4293 break; 4294 } 4295 } 4296 } 4297 4298 4299 void LCodeGen::DoStoreKeyedFixedDoubleArray(LStoreKeyed* instr) { 4300 DoubleRegister value = ToDoubleRegister(instr->value()); 4301 Register elements = ToRegister(instr->elements()); 4302 Register key = no_reg; 4303 Register scratch = scratch0(); 4304 bool key_is_constant = instr->key()->IsConstantOperand(); 4305 int constant_key = 0; 4306 Label not_nan; 4307 4308 // Calculate the effective address of the slot in the array to store the 4309 // double value. 4310 if (key_is_constant) { 4311 constant_key = ToInteger32(LConstantOperand::cast(instr->key())); 4312 if (constant_key & 0xF0000000) { 4313 Abort(kArrayIndexConstantValueTooBig); 4314 } 4315 } else { 4316 key = ToRegister(instr->key()); 4317 } 4318 int element_size_shift = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS); 4319 int shift_size = (instr->hydrogen()->key()->representation().IsSmi()) 4320 ? (element_size_shift - kSmiTagSize) : element_size_shift; 4321 if (key_is_constant) { 4322 __ Addu(scratch, elements, Operand((constant_key << element_size_shift) + 4323 FixedDoubleArray::kHeaderSize - kHeapObjectTag)); 4324 } else { 4325 __ sll(scratch, key, shift_size); 4326 __ Addu(scratch, elements, Operand(scratch)); 4327 __ Addu(scratch, scratch, 4328 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); 4329 } 4330 4331 if (instr->NeedsCanonicalization()) { 4332 Label is_nan; 4333 // Check for NaN. All NaNs must be canonicalized. 4334 __ BranchF(NULL, &is_nan, eq, value, value); 4335 __ Branch(¬_nan); 4336 4337 // Only load canonical NaN if the comparison above set the overflow. 4338 __ bind(&is_nan); 4339 __ Move(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double()); 4340 } 4341 4342 __ bind(¬_nan); 4343 __ sdc1(value, MemOperand(scratch, instr->additional_index() << 4344 element_size_shift)); 4345 } 4346 4347 4348 void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { 4349 Register value = ToRegister(instr->value()); 4350 Register elements = ToRegister(instr->elements()); 4351 Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) 4352 : no_reg; 4353 Register scratch = scratch0(); 4354 Register store_base = scratch; 4355 int offset = 0; 4356 4357 // Do the store. 4358 if (instr->key()->IsConstantOperand()) { 4359 ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); 4360 LConstantOperand* const_operand = LConstantOperand::cast(instr->key()); 4361 offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) + 4362 instr->additional_index()); 4363 store_base = elements; 4364 } else { 4365 // Even though the HLoadKeyed instruction forces the input 4366 // representation for the key to be an integer, the input gets replaced 4367 // during bound check elimination with the index argument to the bounds 4368 // check, which can be tagged, so that case must be handled here, too. 4369 if (instr->hydrogen()->key()->representation().IsSmi()) { 4370 __ sll(scratch, key, kPointerSizeLog2 - kSmiTagSize); 4371 __ addu(scratch, elements, scratch); 4372 } else { 4373 __ sll(scratch, key, kPointerSizeLog2); 4374 __ addu(scratch, elements, scratch); 4375 } 4376 offset = FixedArray::OffsetOfElementAt(instr->additional_index()); 4377 } 4378 __ sw(value, FieldMemOperand(store_base, offset)); 4379 4380 if (instr->hydrogen()->NeedsWriteBarrier()) { 4381 SmiCheck check_needed = 4382 instr->hydrogen()->value()->IsHeapObject() 4383 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; 4384 // Compute address of modified element and store it into key register. 4385 __ Addu(key, store_base, Operand(offset - kHeapObjectTag)); 4386 __ RecordWrite(elements, 4387 key, 4388 value, 4389 GetRAState(), 4390 kSaveFPRegs, 4391 EMIT_REMEMBERED_SET, 4392 check_needed); 4393 } 4394 } 4395 4396 4397 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { 4398 // By cases: external, fast double 4399 if (instr->is_external()) { 4400 DoStoreKeyedExternalArray(instr); 4401 } else if (instr->hydrogen()->value()->representation().IsDouble()) { 4402 DoStoreKeyedFixedDoubleArray(instr); 4403 } else { 4404 DoStoreKeyedFixedArray(instr); 4405 } 4406 } 4407 4408 4409 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { 4410 ASSERT(ToRegister(instr->object()).is(a2)); 4411 ASSERT(ToRegister(instr->key()).is(a1)); 4412 ASSERT(ToRegister(instr->value()).is(a0)); 4413 4414 Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode) 4415 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() 4416 : isolate()->builtins()->KeyedStoreIC_Initialize(); 4417 CallCode(ic, RelocInfo::CODE_TARGET, instr); 4418 } 4419 4420 4421 void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { 4422 Register object_reg = ToRegister(instr->object()); 4423 Register scratch = scratch0(); 4424 4425 Handle<Map> from_map = instr->original_map(); 4426 Handle<Map> to_map = instr->transitioned_map(); 4427 ElementsKind from_kind = instr->from_kind(); 4428 ElementsKind to_kind = instr->to_kind(); 4429 4430 Label not_applicable; 4431 __ lw(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset)); 4432 __ Branch(¬_applicable, ne, scratch, Operand(from_map)); 4433 4434 if (IsSimpleMapChangeTransition(from_kind, to_kind)) { 4435 Register new_map_reg = ToRegister(instr->new_map_temp()); 4436 __ li(new_map_reg, Operand(to_map)); 4437 __ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); 4438 // Write barrier. 4439 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, 4440 scratch, GetRAState(), kDontSaveFPRegs); 4441 } else { 4442 PushSafepointRegistersScope scope( 4443 this, Safepoint::kWithRegistersAndDoubles); 4444 __ mov(a0, object_reg); 4445 __ li(a1, Operand(to_map)); 4446 TransitionElementsKindStub stub(from_kind, to_kind); 4447 __ CallStub(&stub); 4448 RecordSafepointWithRegistersAndDoubles( 4449 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); 4450 } 4451 __ bind(¬_applicable); 4452 } 4453 4454 4455 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { 4456 Register object = ToRegister(instr->object()); 4457 Register temp = ToRegister(instr->temp()); 4458 Label fail; 4459 __ TestJSArrayForAllocationMemento(object, temp, ne, &fail); 4460 DeoptimizeIf(al, instr->environment()); 4461 __ bind(&fail); 4462 } 4463 4464 4465 void LCodeGen::DoStringAdd(LStringAdd* instr) { 4466 __ push(ToRegister(instr->left())); 4467 __ push(ToRegister(instr->right())); 4468 StringAddStub stub(instr->hydrogen()->flags()); 4469 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 4470 } 4471 4472 4473 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { 4474 class DeferredStringCharCodeAt: public LDeferredCode { 4475 public: 4476 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) 4477 : LDeferredCode(codegen), instr_(instr) { } 4478 virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } 4479 virtual LInstruction* instr() { return instr_; } 4480 private: 4481 LStringCharCodeAt* instr_; 4482 }; 4483 4484 DeferredStringCharCodeAt* deferred = 4485 new(zone()) DeferredStringCharCodeAt(this, instr); 4486 StringCharLoadGenerator::Generate(masm(), 4487 ToRegister(instr->string()), 4488 ToRegister(instr->index()), 4489 ToRegister(instr->result()), 4490 deferred->entry()); 4491 __ bind(deferred->exit()); 4492 } 4493 4494 4495 void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) { 4496 Register string = ToRegister(instr->string()); 4497 Register result = ToRegister(instr->result()); 4498 Register scratch = scratch0(); 4499 4500 // TODO(3095996): Get rid of this. For now, we need to make the 4501 // result register contain a valid pointer because it is already 4502 // contained in the register pointer map. 4503 __ mov(result, zero_reg); 4504 4505 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 4506 __ push(string); 4507 // Push the index as a smi. This is safe because of the checks in 4508 // DoStringCharCodeAt above. 4509 if (instr->index()->IsConstantOperand()) { 4510 int const_index = ToInteger32(LConstantOperand::cast(instr->index())); 4511 __ Addu(scratch, zero_reg, Operand(Smi::FromInt(const_index))); 4512 __ push(scratch); 4513 } else { 4514 Register index = ToRegister(instr->index()); 4515 __ SmiTag(index); 4516 __ push(index); 4517 } 4518 CallRuntimeFromDeferred(Runtime::kStringCharCodeAt, 2, instr); 4519 __ AssertSmi(v0); 4520 __ SmiUntag(v0); 4521 __ StoreToSafepointRegisterSlot(v0, result); 4522 } 4523 4524 4525 void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) { 4526 class DeferredStringCharFromCode: public LDeferredCode { 4527 public: 4528 DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) 4529 : LDeferredCode(codegen), instr_(instr) { } 4530 virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } 4531 virtual LInstruction* instr() { return instr_; } 4532 private: 4533 LStringCharFromCode* instr_; 4534 }; 4535 4536 DeferredStringCharFromCode* deferred = 4537 new(zone()) DeferredStringCharFromCode(this, instr); 4538 4539 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); 4540 Register char_code = ToRegister(instr->char_code()); 4541 Register result = ToRegister(instr->result()); 4542 Register scratch = scratch0(); 4543 ASSERT(!char_code.is(result)); 4544 4545 __ Branch(deferred->entry(), hi, 4546 char_code, Operand(String::kMaxOneByteCharCode)); 4547 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex); 4548 __ sll(scratch, char_code, kPointerSizeLog2); 4549 __ Addu(result, result, scratch); 4550 __ lw(result, FieldMemOperand(result, FixedArray::kHeaderSize)); 4551 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); 4552 __ Branch(deferred->entry(), eq, result, Operand(scratch)); 4553 __ bind(deferred->exit()); 4554 } 4555 4556 4557 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { 4558 Register char_code = ToRegister(instr->char_code()); 4559 Register result = ToRegister(instr->result()); 4560 4561 // TODO(3095996): Get rid of this. For now, we need to make the 4562 // result register contain a valid pointer because it is already 4563 // contained in the register pointer map. 4564 __ mov(result, zero_reg); 4565 4566 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 4567 __ SmiTag(char_code); 4568 __ push(char_code); 4569 CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr); 4570 __ StoreToSafepointRegisterSlot(v0, result); 4571 } 4572 4573 4574 void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { 4575 LOperand* input = instr->value(); 4576 ASSERT(input->IsRegister() || input->IsStackSlot()); 4577 LOperand* output = instr->result(); 4578 ASSERT(output->IsDoubleRegister()); 4579 FPURegister single_scratch = double_scratch0().low(); 4580 if (input->IsStackSlot()) { 4581 Register scratch = scratch0(); 4582 __ lw(scratch, ToMemOperand(input)); 4583 __ mtc1(scratch, single_scratch); 4584 } else { 4585 __ mtc1(ToRegister(input), single_scratch); 4586 } 4587 __ cvt_d_w(ToDoubleRegister(output), single_scratch); 4588 } 4589 4590 4591 void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) { 4592 LOperand* input = instr->value(); 4593 ASSERT(input->IsRegister()); 4594 LOperand* output = instr->result(); 4595 ASSERT(output->IsRegister()); 4596 Register scratch = scratch0(); 4597 4598 __ SmiTagCheckOverflow(ToRegister(output), ToRegister(input), scratch); 4599 if (!instr->hydrogen()->value()->HasRange() || 4600 !instr->hydrogen()->value()->range()->IsInSmiRange()) { 4601 DeoptimizeIf(lt, instr->environment(), scratch, Operand(zero_reg)); 4602 } 4603 } 4604 4605 4606 void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) { 4607 LOperand* input = instr->value(); 4608 LOperand* output = instr->result(); 4609 4610 FPURegister dbl_scratch = double_scratch0(); 4611 __ mtc1(ToRegister(input), dbl_scratch); 4612 __ Cvt_d_uw(ToDoubleRegister(output), dbl_scratch, f22); 4613 } 4614 4615 4616 void LCodeGen::DoNumberTagI(LNumberTagI* instr) { 4617 class DeferredNumberTagI: public LDeferredCode { 4618 public: 4619 DeferredNumberTagI(LCodeGen* codegen, LNumberTagI* instr) 4620 : LDeferredCode(codegen), instr_(instr) { } 4621 virtual void Generate() { 4622 codegen()->DoDeferredNumberTagI(instr_, 4623 instr_->value(), 4624 SIGNED_INT32); 4625 } 4626 virtual LInstruction* instr() { return instr_; } 4627 private: 4628 LNumberTagI* instr_; 4629 }; 4630 4631 Register src = ToRegister(instr->value()); 4632 Register dst = ToRegister(instr->result()); 4633 Register overflow = scratch0(); 4634 4635 DeferredNumberTagI* deferred = new(zone()) DeferredNumberTagI(this, instr); 4636 __ SmiTagCheckOverflow(dst, src, overflow); 4637 __ BranchOnOverflow(deferred->entry(), overflow); 4638 __ bind(deferred->exit()); 4639 } 4640 4641 4642 void LCodeGen::DoNumberTagU(LNumberTagU* instr) { 4643 class DeferredNumberTagU: public LDeferredCode { 4644 public: 4645 DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr) 4646 : LDeferredCode(codegen), instr_(instr) { } 4647 virtual void Generate() { 4648 codegen()->DoDeferredNumberTagI(instr_, 4649 instr_->value(), 4650 UNSIGNED_INT32); 4651 } 4652 virtual LInstruction* instr() { return instr_; } 4653 private: 4654 LNumberTagU* instr_; 4655 }; 4656 4657 LOperand* input = instr->value(); 4658 ASSERT(input->IsRegister() && input->Equals(instr->result())); 4659 Register reg = ToRegister(input); 4660 4661 DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr); 4662 __ Branch(deferred->entry(), hi, reg, Operand(Smi::kMaxValue)); 4663 __ SmiTag(reg, reg); 4664 __ bind(deferred->exit()); 4665 } 4666 4667 4668 void LCodeGen::DoDeferredNumberTagI(LInstruction* instr, 4669 LOperand* value, 4670 IntegerSignedness signedness) { 4671 Label slow; 4672 Register src = ToRegister(value); 4673 Register dst = ToRegister(instr->result()); 4674 DoubleRegister dbl_scratch = double_scratch0(); 4675 4676 // Preserve the value of all registers. 4677 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 4678 4679 Label done; 4680 if (signedness == SIGNED_INT32) { 4681 // There was overflow, so bits 30 and 31 of the original integer 4682 // disagree. Try to allocate a heap number in new space and store 4683 // the value in there. If that fails, call the runtime system. 4684 if (dst.is(src)) { 4685 __ SmiUntag(src, dst); 4686 __ Xor(src, src, Operand(0x80000000)); 4687 } 4688 __ mtc1(src, dbl_scratch); 4689 __ cvt_d_w(dbl_scratch, dbl_scratch); 4690 } else { 4691 __ mtc1(src, dbl_scratch); 4692 __ Cvt_d_uw(dbl_scratch, dbl_scratch, f22); 4693 } 4694 4695 if (FLAG_inline_new) { 4696 __ LoadRoot(scratch0(), Heap::kHeapNumberMapRootIndex); 4697 __ AllocateHeapNumber(t1, a3, t0, scratch0(), &slow, DONT_TAG_RESULT); 4698 __ Move(dst, t1); 4699 __ Branch(&done); 4700 } 4701 4702 // Slow case: Call the runtime system to do the number allocation. 4703 __ bind(&slow); 4704 4705 // TODO(3095996): Put a valid pointer value in the stack slot where the result 4706 // register is stored, as this register is in the pointer map, but contains an 4707 // integer value. 4708 __ StoreToSafepointRegisterSlot(zero_reg, dst); 4709 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); 4710 __ Move(dst, v0); 4711 __ Subu(dst, dst, kHeapObjectTag); 4712 4713 // Done. Put the value in dbl_scratch into the value of the allocated heap 4714 // number. 4715 __ bind(&done); 4716 __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset)); 4717 __ Addu(dst, dst, kHeapObjectTag); 4718 __ StoreToSafepointRegisterSlot(dst, dst); 4719 } 4720 4721 4722 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { 4723 class DeferredNumberTagD: public LDeferredCode { 4724 public: 4725 DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) 4726 : LDeferredCode(codegen), instr_(instr) { } 4727 virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } 4728 virtual LInstruction* instr() { return instr_; } 4729 private: 4730 LNumberTagD* instr_; 4731 }; 4732 4733 DoubleRegister input_reg = ToDoubleRegister(instr->value()); 4734 Register scratch = scratch0(); 4735 Register reg = ToRegister(instr->result()); 4736 Register temp1 = ToRegister(instr->temp()); 4737 Register temp2 = ToRegister(instr->temp2()); 4738 4739 DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); 4740 if (FLAG_inline_new) { 4741 __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); 4742 // We want the untagged address first for performance 4743 __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(), 4744 DONT_TAG_RESULT); 4745 } else { 4746 __ Branch(deferred->entry()); 4747 } 4748 __ bind(deferred->exit()); 4749 __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset)); 4750 // Now that we have finished with the object's real address tag it 4751 __ Addu(reg, reg, kHeapObjectTag); 4752 } 4753 4754 4755 void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { 4756 // TODO(3095996): Get rid of this. For now, we need to make the 4757 // result register contain a valid pointer because it is already 4758 // contained in the register pointer map. 4759 Register reg = ToRegister(instr->result()); 4760 __ mov(reg, zero_reg); 4761 4762 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 4763 CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr); 4764 __ Subu(v0, v0, kHeapObjectTag); 4765 __ StoreToSafepointRegisterSlot(v0, reg); 4766 } 4767 4768 4769 void LCodeGen::DoSmiTag(LSmiTag* instr) { 4770 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); 4771 __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value())); 4772 } 4773 4774 4775 void LCodeGen::DoSmiUntag(LSmiUntag* instr) { 4776 Register scratch = scratch0(); 4777 Register input = ToRegister(instr->value()); 4778 Register result = ToRegister(instr->result()); 4779 if (instr->needs_check()) { 4780 STATIC_ASSERT(kHeapObjectTag == 1); 4781 // If the input is a HeapObject, value of scratch won't be zero. 4782 __ And(scratch, input, Operand(kHeapObjectTag)); 4783 __ SmiUntag(result, input); 4784 DeoptimizeIf(ne, instr->environment(), scratch, Operand(zero_reg)); 4785 } else { 4786 __ SmiUntag(result, input); 4787 } 4788 } 4789 4790 4791 void LCodeGen::EmitNumberUntagD(Register input_reg, 4792 DoubleRegister result_reg, 4793 bool can_convert_undefined_to_nan, 4794 bool deoptimize_on_minus_zero, 4795 LEnvironment* env, 4796 NumberUntagDMode mode) { 4797 Register scratch = scratch0(); 4798 4799 Label load_smi, heap_number, done; 4800 4801 if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { 4802 // Smi check. 4803 __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); 4804 4805 // Heap number map check. 4806 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); 4807 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 4808 if (!can_convert_undefined_to_nan) { 4809 DeoptimizeIf(ne, env, scratch, Operand(at)); 4810 } else { 4811 Label heap_number, convert; 4812 __ Branch(&heap_number, eq, scratch, Operand(at)); 4813 4814 // Convert undefined (and hole) to NaN. 4815 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); 4816 DeoptimizeIf(ne, env, input_reg, Operand(at)); 4817 4818 __ bind(&convert); 4819 __ LoadRoot(at, Heap::kNanValueRootIndex); 4820 __ ldc1(result_reg, FieldMemOperand(at, HeapNumber::kValueOffset)); 4821 __ Branch(&done); 4822 4823 __ bind(&heap_number); 4824 } 4825 // Heap number to double register conversion. 4826 __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); 4827 if (deoptimize_on_minus_zero) { 4828 __ mfc1(at, result_reg.low()); 4829 __ Branch(&done, ne, at, Operand(zero_reg)); 4830 __ mfc1(scratch, result_reg.high()); 4831 DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask)); 4832 } 4833 __ Branch(&done); 4834 } else { 4835 __ SmiUntag(scratch, input_reg); 4836 ASSERT(mode == NUMBER_CANDIDATE_IS_SMI); 4837 } 4838 4839 // Smi to double register conversion 4840 __ bind(&load_smi); 4841 // scratch: untagged value of input_reg 4842 __ mtc1(scratch, result_reg); 4843 __ cvt_d_w(result_reg, result_reg); 4844 __ bind(&done); 4845 } 4846 4847 4848 void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { 4849 Register input_reg = ToRegister(instr->value()); 4850 Register scratch1 = scratch0(); 4851 Register scratch2 = ToRegister(instr->temp()); 4852 DoubleRegister double_scratch = double_scratch0(); 4853 DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3()); 4854 4855 ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2)); 4856 ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1)); 4857 4858 Label done; 4859 4860 // The input is a tagged HeapObject. 4861 // Heap number map check. 4862 __ lw(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset)); 4863 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 4864 // This 'at' value and scratch1 map value are used for tests in both clauses 4865 // of the if. 4866 4867 if (instr->truncating()) { 4868 Register scratch3 = ToRegister(instr->temp2()); 4869 FPURegister single_scratch = double_scratch.low(); 4870 ASSERT(!scratch3.is(input_reg) && 4871 !scratch3.is(scratch1) && 4872 !scratch3.is(scratch2)); 4873 // Performs a truncating conversion of a floating point number as used by 4874 // the JS bitwise operations. 4875 Label heap_number; 4876 __ Branch(&heap_number, eq, scratch1, Operand(at)); // HeapNumber map? 4877 // Check for undefined. Undefined is converted to zero for truncating 4878 // conversions. 4879 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); 4880 DeoptimizeIf(ne, instr->environment(), input_reg, Operand(at)); 4881 ASSERT(ToRegister(instr->result()).is(input_reg)); 4882 __ mov(input_reg, zero_reg); 4883 __ Branch(&done); 4884 4885 __ bind(&heap_number); 4886 __ ldc1(double_scratch2, 4887 FieldMemOperand(input_reg, HeapNumber::kValueOffset)); 4888 __ EmitECMATruncate(input_reg, 4889 double_scratch2, 4890 single_scratch, 4891 scratch1, 4892 scratch2, 4893 scratch3); 4894 } else { 4895 // Deoptimize if we don't have a heap number. 4896 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(at)); 4897 4898 // Load the double value. 4899 __ ldc1(double_scratch, 4900 FieldMemOperand(input_reg, HeapNumber::kValueOffset)); 4901 4902 Register except_flag = scratch2; 4903 __ EmitFPUTruncate(kRoundToZero, 4904 input_reg, 4905 double_scratch, 4906 scratch1, 4907 double_scratch2, 4908 except_flag, 4909 kCheckForInexactConversion); 4910 4911 // Deopt if the operation did not succeed. 4912 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); 4913 4914 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 4915 __ Branch(&done, ne, input_reg, Operand(zero_reg)); 4916 4917 __ mfc1(scratch1, double_scratch.high()); 4918 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask)); 4919 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg)); 4920 } 4921 } 4922 __ bind(&done); 4923 } 4924 4925 4926 void LCodeGen::DoTaggedToI(LTaggedToI* instr) { 4927 class DeferredTaggedToI: public LDeferredCode { 4928 public: 4929 DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) 4930 : LDeferredCode(codegen), instr_(instr) { } 4931 virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } 4932 virtual LInstruction* instr() { return instr_; } 4933 private: 4934 LTaggedToI* instr_; 4935 }; 4936 4937 LOperand* input = instr->value(); 4938 ASSERT(input->IsRegister()); 4939 ASSERT(input->Equals(instr->result())); 4940 4941 Register input_reg = ToRegister(input); 4942 4943 DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr); 4944 4945 // Let the deferred code handle the HeapObject case. 4946 __ JumpIfNotSmi(input_reg, deferred->entry()); 4947 4948 // Smi to int32 conversion. 4949 __ SmiUntag(input_reg); 4950 __ bind(deferred->exit()); 4951 } 4952 4953 4954 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { 4955 LOperand* input = instr->value(); 4956 ASSERT(input->IsRegister()); 4957 LOperand* result = instr->result(); 4958 ASSERT(result->IsDoubleRegister()); 4959 4960 Register input_reg = ToRegister(input); 4961 DoubleRegister result_reg = ToDoubleRegister(result); 4962 4963 HValue* value = instr->hydrogen()->value(); 4964 NumberUntagDMode mode = value->representation().IsSmi() 4965 ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED; 4966 4967 EmitNumberUntagD(input_reg, result_reg, 4968 instr->hydrogen()->can_convert_undefined_to_nan(), 4969 instr->hydrogen()->deoptimize_on_minus_zero(), 4970 instr->environment(), 4971 mode); 4972 } 4973 4974 4975 void LCodeGen::DoDoubleToI(LDoubleToI* instr) { 4976 Register result_reg = ToRegister(instr->result()); 4977 Register scratch1 = scratch0(); 4978 Register scratch2 = ToRegister(instr->temp()); 4979 DoubleRegister double_input = ToDoubleRegister(instr->value()); 4980 4981 if (instr->truncating()) { 4982 Register scratch3 = ToRegister(instr->temp2()); 4983 FPURegister single_scratch = double_scratch0().low(); 4984 __ EmitECMATruncate(result_reg, 4985 double_input, 4986 single_scratch, 4987 scratch1, 4988 scratch2, 4989 scratch3); 4990 } else { 4991 Register except_flag = scratch2; 4992 4993 __ EmitFPUTruncate(kRoundToMinusInf, 4994 result_reg, 4995 double_input, 4996 scratch1, 4997 double_scratch0(), 4998 except_flag, 4999 kCheckForInexactConversion); 5000 5001 // Deopt if the operation did not succeed (except_flag != 0). 5002 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); 5003 5004 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 5005 Label done; 5006 __ Branch(&done, ne, result_reg, Operand(zero_reg)); 5007 __ mfc1(scratch1, double_input.high()); 5008 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask)); 5009 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg)); 5010 __ bind(&done); 5011 } 5012 } 5013 } 5014 5015 5016 void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) { 5017 Register result_reg = ToRegister(instr->result()); 5018 Register scratch1 = scratch0(); 5019 Register scratch2 = ToRegister(instr->temp()); 5020 DoubleRegister double_input = ToDoubleRegister(instr->value()); 5021 5022 if (instr->truncating()) { 5023 Register scratch3 = ToRegister(instr->temp2()); 5024 FPURegister single_scratch = double_scratch0().low(); 5025 __ EmitECMATruncate(result_reg, 5026 double_input, 5027 single_scratch, 5028 scratch1, 5029 scratch2, 5030 scratch3); 5031 } else { 5032 Register except_flag = scratch2; 5033 5034 __ EmitFPUTruncate(kRoundToMinusInf, 5035 result_reg, 5036 double_input, 5037 scratch1, 5038 double_scratch0(), 5039 except_flag, 5040 kCheckForInexactConversion); 5041 5042 // Deopt if the operation did not succeed (except_flag != 0). 5043 DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg)); 5044 5045 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { 5046 Label done; 5047 __ Branch(&done, ne, result_reg, Operand(zero_reg)); 5048 __ mfc1(scratch1, double_input.high()); 5049 __ And(scratch1, scratch1, Operand(HeapNumber::kSignMask)); 5050 DeoptimizeIf(ne, instr->environment(), scratch1, Operand(zero_reg)); 5051 __ bind(&done); 5052 } 5053 } 5054 __ SmiTagCheckOverflow(result_reg, result_reg, scratch1); 5055 DeoptimizeIf(lt, instr->environment(), scratch1, Operand(zero_reg)); 5056 } 5057 5058 5059 void LCodeGen::DoCheckSmi(LCheckSmi* instr) { 5060 LOperand* input = instr->value(); 5061 __ And(at, ToRegister(input), Operand(kSmiTagMask)); 5062 DeoptimizeIf(ne, instr->environment(), at, Operand(zero_reg)); 5063 } 5064 5065 5066 void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) { 5067 if (!instr->hydrogen()->value()->IsHeapObject()) { 5068 LOperand* input = instr->value(); 5069 __ And(at, ToRegister(input), Operand(kSmiTagMask)); 5070 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); 5071 } 5072 } 5073 5074 5075 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { 5076 Register input = ToRegister(instr->value()); 5077 Register scratch = scratch0(); 5078 5079 __ GetObjectType(input, scratch, scratch); 5080 5081 if (instr->hydrogen()->is_interval_check()) { 5082 InstanceType first; 5083 InstanceType last; 5084 instr->hydrogen()->GetCheckInterval(&first, &last); 5085 5086 // If there is only one type in the interval check for equality. 5087 if (first == last) { 5088 DeoptimizeIf(ne, instr->environment(), scratch, Operand(first)); 5089 } else { 5090 DeoptimizeIf(lo, instr->environment(), scratch, Operand(first)); 5091 // Omit check for the last type. 5092 if (last != LAST_TYPE) { 5093 DeoptimizeIf(hi, instr->environment(), scratch, Operand(last)); 5094 } 5095 } 5096 } else { 5097 uint8_t mask; 5098 uint8_t tag; 5099 instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag); 5100 5101 if (IsPowerOf2(mask)) { 5102 ASSERT(tag == 0 || IsPowerOf2(tag)); 5103 __ And(at, scratch, mask); 5104 DeoptimizeIf(tag == 0 ? ne : eq, instr->environment(), 5105 at, Operand(zero_reg)); 5106 } else { 5107 __ And(scratch, scratch, Operand(mask)); 5108 DeoptimizeIf(ne, instr->environment(), scratch, Operand(tag)); 5109 } 5110 } 5111 } 5112 5113 5114 void LCodeGen::DoCheckFunction(LCheckFunction* instr) { 5115 Register reg = ToRegister(instr->value()); 5116 Handle<JSFunction> target = instr->hydrogen()->target(); 5117 AllowDeferredHandleDereference smi_check; 5118 if (isolate()->heap()->InNewSpace(*target)) { 5119 Register reg = ToRegister(instr->value()); 5120 Handle<Cell> cell = isolate()->factory()->NewCell(target); 5121 __ li(at, Operand(Handle<Object>(cell))); 5122 __ lw(at, FieldMemOperand(at, Cell::kValueOffset)); 5123 DeoptimizeIf(ne, instr->environment(), reg, 5124 Operand(at)); 5125 } else { 5126 DeoptimizeIf(ne, instr->environment(), reg, 5127 Operand(target)); 5128 } 5129 } 5130 5131 5132 void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) { 5133 { 5134 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 5135 __ push(object); 5136 CallRuntimeFromDeferred(Runtime::kMigrateInstance, 1, instr); 5137 __ StoreToSafepointRegisterSlot(v0, scratch0()); 5138 } 5139 __ And(at, scratch0(), Operand(kSmiTagMask)); 5140 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); 5141 } 5142 5143 5144 void LCodeGen::DoCheckMaps(LCheckMaps* instr) { 5145 class DeferredCheckMaps: public LDeferredCode { 5146 public: 5147 DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object) 5148 : LDeferredCode(codegen), instr_(instr), object_(object) { 5149 SetExit(check_maps()); 5150 } 5151 virtual void Generate() { 5152 codegen()->DoDeferredInstanceMigration(instr_, object_); 5153 } 5154 Label* check_maps() { return &check_maps_; } 5155 virtual LInstruction* instr() { return instr_; } 5156 private: 5157 LCheckMaps* instr_; 5158 Label check_maps_; 5159 Register object_; 5160 }; 5161 5162 if (instr->hydrogen()->CanOmitMapChecks()) return; 5163 Register map_reg = scratch0(); 5164 LOperand* input = instr->value(); 5165 ASSERT(input->IsRegister()); 5166 Register reg = ToRegister(input); 5167 SmallMapList* map_set = instr->hydrogen()->map_set(); 5168 __ lw(map_reg, FieldMemOperand(reg, HeapObject::kMapOffset)); 5169 5170 DeferredCheckMaps* deferred = NULL; 5171 if (instr->hydrogen()->has_migration_target()) { 5172 deferred = new(zone()) DeferredCheckMaps(this, instr, reg); 5173 __ bind(deferred->check_maps()); 5174 } 5175 5176 Label success; 5177 for (int i = 0; i < map_set->length() - 1; i++) { 5178 Handle<Map> map = map_set->at(i); 5179 __ CompareMapAndBranch(map_reg, map, &success, eq, &success); 5180 } 5181 Handle<Map> map = map_set->last(); 5182 // Do the CompareMap() directly within the Branch() and DeoptimizeIf(). 5183 if (instr->hydrogen()->has_migration_target()) { 5184 __ Branch(deferred->entry(), ne, map_reg, Operand(map)); 5185 } else { 5186 DeoptimizeIf(ne, instr->environment(), map_reg, Operand(map)); 5187 } 5188 5189 __ bind(&success); 5190 } 5191 5192 5193 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) { 5194 DoubleRegister value_reg = ToDoubleRegister(instr->unclamped()); 5195 Register result_reg = ToRegister(instr->result()); 5196 DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); 5197 __ ClampDoubleToUint8(result_reg, value_reg, temp_reg); 5198 } 5199 5200 5201 void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) { 5202 Register unclamped_reg = ToRegister(instr->unclamped()); 5203 Register result_reg = ToRegister(instr->result()); 5204 __ ClampUint8(result_reg, unclamped_reg); 5205 } 5206 5207 5208 void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) { 5209 Register scratch = scratch0(); 5210 Register input_reg = ToRegister(instr->unclamped()); 5211 Register result_reg = ToRegister(instr->result()); 5212 DoubleRegister temp_reg = ToDoubleRegister(instr->temp()); 5213 Label is_smi, done, heap_number; 5214 5215 // Both smi and heap number cases are handled. 5216 __ UntagAndJumpIfSmi(scratch, input_reg, &is_smi); 5217 5218 // Check for heap number 5219 __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); 5220 __ Branch(&heap_number, eq, scratch, Operand(factory()->heap_number_map())); 5221 5222 // Check for undefined. Undefined is converted to zero for clamping 5223 // conversions. 5224 DeoptimizeIf(ne, instr->environment(), input_reg, 5225 Operand(factory()->undefined_value())); 5226 __ mov(result_reg, zero_reg); 5227 __ jmp(&done); 5228 5229 // Heap number 5230 __ bind(&heap_number); 5231 __ ldc1(double_scratch0(), FieldMemOperand(input_reg, 5232 HeapNumber::kValueOffset)); 5233 __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg); 5234 __ jmp(&done); 5235 5236 __ bind(&is_smi); 5237 __ ClampUint8(result_reg, scratch); 5238 5239 __ bind(&done); 5240 } 5241 5242 5243 void LCodeGen::DoAllocate(LAllocate* instr) { 5244 class DeferredAllocate: public LDeferredCode { 5245 public: 5246 DeferredAllocate(LCodeGen* codegen, LAllocate* instr) 5247 : LDeferredCode(codegen), instr_(instr) { } 5248 virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } 5249 virtual LInstruction* instr() { return instr_; } 5250 private: 5251 LAllocate* instr_; 5252 }; 5253 5254 DeferredAllocate* deferred = 5255 new(zone()) DeferredAllocate(this, instr); 5256 5257 Register result = ToRegister(instr->result()); 5258 Register scratch = ToRegister(instr->temp1()); 5259 Register scratch2 = ToRegister(instr->temp2()); 5260 5261 // Allocate memory for the object. 5262 AllocationFlags flags = TAG_OBJECT; 5263 if (instr->hydrogen()->MustAllocateDoubleAligned()) { 5264 flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT); 5265 } 5266 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) { 5267 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation()); 5268 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); 5269 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE); 5270 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) { 5271 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); 5272 flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE); 5273 } 5274 if (instr->size()->IsConstantOperand()) { 5275 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); 5276 __ Allocate(size, result, scratch, scratch2, deferred->entry(), flags); 5277 } else { 5278 Register size = ToRegister(instr->size()); 5279 __ Allocate(size, 5280 result, 5281 scratch, 5282 scratch2, 5283 deferred->entry(), 5284 flags); 5285 } 5286 5287 __ bind(deferred->exit()); 5288 5289 if (instr->hydrogen()->MustPrefillWithFiller()) { 5290 if (instr->size()->IsConstantOperand()) { 5291 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); 5292 __ li(scratch, Operand(size)); 5293 } else { 5294 scratch = ToRegister(instr->size()); 5295 } 5296 __ Subu(scratch, scratch, Operand(kPointerSize)); 5297 __ Subu(result, result, Operand(kHeapObjectTag)); 5298 Label loop; 5299 __ bind(&loop); 5300 __ li(scratch2, Operand(isolate()->factory()->one_pointer_filler_map())); 5301 __ Addu(at, result, Operand(scratch)); 5302 __ sw(scratch2, MemOperand(at)); 5303 __ Subu(scratch, scratch, Operand(kPointerSize)); 5304 __ Branch(&loop, ge, scratch, Operand(zero_reg)); 5305 __ Addu(result, result, Operand(kHeapObjectTag)); 5306 } 5307 } 5308 5309 5310 void LCodeGen::DoDeferredAllocate(LAllocate* instr) { 5311 Register result = ToRegister(instr->result()); 5312 5313 // TODO(3095996): Get rid of this. For now, we need to make the 5314 // result register contain a valid pointer because it is already 5315 // contained in the register pointer map. 5316 __ mov(result, zero_reg); 5317 5318 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 5319 if (instr->size()->IsRegister()) { 5320 Register size = ToRegister(instr->size()); 5321 ASSERT(!size.is(result)); 5322 __ SmiTag(size); 5323 __ push(size); 5324 } else { 5325 int32_t size = ToInteger32(LConstantOperand::cast(instr->size())); 5326 __ Push(Smi::FromInt(size)); 5327 } 5328 5329 if (instr->hydrogen()->IsOldPointerSpaceAllocation()) { 5330 ASSERT(!instr->hydrogen()->IsOldDataSpaceAllocation()); 5331 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); 5332 CallRuntimeFromDeferred(Runtime::kAllocateInOldPointerSpace, 1, instr); 5333 } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) { 5334 ASSERT(!instr->hydrogen()->IsNewSpaceAllocation()); 5335 CallRuntimeFromDeferred(Runtime::kAllocateInOldDataSpace, 1, instr); 5336 } else { 5337 CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); 5338 } 5339 __ StoreToSafepointRegisterSlot(v0, result); 5340 } 5341 5342 5343 void LCodeGen::DoToFastProperties(LToFastProperties* instr) { 5344 ASSERT(ToRegister(instr->value()).is(a0)); 5345 ASSERT(ToRegister(instr->result()).is(v0)); 5346 __ push(a0); 5347 CallRuntime(Runtime::kToFastProperties, 1, instr); 5348 } 5349 5350 5351 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { 5352 Label materialized; 5353 // Registers will be used as follows: 5354 // t3 = literals array. 5355 // a1 = regexp literal. 5356 // a0 = regexp literal clone. 5357 // a2 and t0-t2 are used as temporaries. 5358 int literal_offset = 5359 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index()); 5360 __ LoadHeapObject(t3, instr->hydrogen()->literals()); 5361 __ lw(a1, FieldMemOperand(t3, literal_offset)); 5362 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); 5363 __ Branch(&materialized, ne, a1, Operand(at)); 5364 5365 // Create regexp literal using runtime function 5366 // Result will be in v0. 5367 __ li(t2, Operand(Smi::FromInt(instr->hydrogen()->literal_index()))); 5368 __ li(t1, Operand(instr->hydrogen()->pattern())); 5369 __ li(t0, Operand(instr->hydrogen()->flags())); 5370 __ Push(t3, t2, t1, t0); 5371 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); 5372 __ mov(a1, v0); 5373 5374 __ bind(&materialized); 5375 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 5376 Label allocated, runtime_allocate; 5377 5378 __ Allocate(size, v0, a2, a3, &runtime_allocate, TAG_OBJECT); 5379 __ jmp(&allocated); 5380 5381 __ bind(&runtime_allocate); 5382 __ li(a0, Operand(Smi::FromInt(size))); 5383 __ Push(a1, a0); 5384 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); 5385 __ pop(a1); 5386 5387 __ bind(&allocated); 5388 // Copy the content into the newly allocated memory. 5389 // (Unroll copy loop once for better throughput). 5390 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { 5391 __ lw(a3, FieldMemOperand(a1, i)); 5392 __ lw(a2, FieldMemOperand(a1, i + kPointerSize)); 5393 __ sw(a3, FieldMemOperand(v0, i)); 5394 __ sw(a2, FieldMemOperand(v0, i + kPointerSize)); 5395 } 5396 if ((size % (2 * kPointerSize)) != 0) { 5397 __ lw(a3, FieldMemOperand(a1, size - kPointerSize)); 5398 __ sw(a3, FieldMemOperand(v0, size - kPointerSize)); 5399 } 5400 } 5401 5402 5403 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { 5404 // Use the fast case closure allocation code that allocates in new 5405 // space for nested functions that don't need literals cloning. 5406 bool pretenure = instr->hydrogen()->pretenure(); 5407 if (!pretenure && instr->hydrogen()->has_no_literals()) { 5408 FastNewClosureStub stub(instr->hydrogen()->language_mode(), 5409 instr->hydrogen()->is_generator()); 5410 __ li(a1, Operand(instr->hydrogen()->shared_info())); 5411 __ push(a1); 5412 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 5413 } else { 5414 __ li(a2, Operand(instr->hydrogen()->shared_info())); 5415 __ li(a1, Operand(pretenure ? factory()->true_value() 5416 : factory()->false_value())); 5417 __ Push(cp, a2, a1); 5418 CallRuntime(Runtime::kNewClosure, 3, instr); 5419 } 5420 } 5421 5422 5423 void LCodeGen::DoTypeof(LTypeof* instr) { 5424 ASSERT(ToRegister(instr->result()).is(v0)); 5425 Register input = ToRegister(instr->value()); 5426 __ push(input); 5427 CallRuntime(Runtime::kTypeof, 1, instr); 5428 } 5429 5430 5431 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) { 5432 Register input = ToRegister(instr->value()); 5433 5434 Register cmp1 = no_reg; 5435 Operand cmp2 = Operand(no_reg); 5436 5437 Condition final_branch_condition = EmitTypeofIs(instr->TrueLabel(chunk_), 5438 instr->FalseLabel(chunk_), 5439 input, 5440 instr->type_literal(), 5441 cmp1, 5442 cmp2); 5443 5444 ASSERT(cmp1.is_valid()); 5445 ASSERT(!cmp2.is_reg() || cmp2.rm().is_valid()); 5446 5447 if (final_branch_condition != kNoCondition) { 5448 EmitBranch(instr, final_branch_condition, cmp1, cmp2); 5449 } 5450 } 5451 5452 5453 Condition LCodeGen::EmitTypeofIs(Label* true_label, 5454 Label* false_label, 5455 Register input, 5456 Handle<String> type_name, 5457 Register& cmp1, 5458 Operand& cmp2) { 5459 // This function utilizes the delay slot heavily. This is used to load 5460 // values that are always usable without depending on the type of the input 5461 // register. 5462 Condition final_branch_condition = kNoCondition; 5463 Register scratch = scratch0(); 5464 if (type_name->Equals(heap()->number_string())) { 5465 __ JumpIfSmi(input, true_label); 5466 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset)); 5467 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); 5468 cmp1 = input; 5469 cmp2 = Operand(at); 5470 final_branch_condition = eq; 5471 5472 } else if (type_name->Equals(heap()->string_string())) { 5473 __ JumpIfSmi(input, false_label); 5474 __ GetObjectType(input, input, scratch); 5475 __ Branch(USE_DELAY_SLOT, false_label, 5476 ge, scratch, Operand(FIRST_NONSTRING_TYPE)); 5477 // input is an object so we can load the BitFieldOffset even if we take the 5478 // other branch. 5479 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset)); 5480 __ And(at, at, 1 << Map::kIsUndetectable); 5481 cmp1 = at; 5482 cmp2 = Operand(zero_reg); 5483 final_branch_condition = eq; 5484 5485 } else if (type_name->Equals(heap()->symbol_string())) { 5486 __ JumpIfSmi(input, false_label); 5487 __ GetObjectType(input, input, scratch); 5488 cmp1 = scratch; 5489 cmp2 = Operand(SYMBOL_TYPE); 5490 final_branch_condition = eq; 5491 5492 } else if (type_name->Equals(heap()->boolean_string())) { 5493 __ LoadRoot(at, Heap::kTrueValueRootIndex); 5494 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); 5495 __ LoadRoot(at, Heap::kFalseValueRootIndex); 5496 cmp1 = at; 5497 cmp2 = Operand(input); 5498 final_branch_condition = eq; 5499 5500 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { 5501 __ LoadRoot(at, Heap::kNullValueRootIndex); 5502 cmp1 = at; 5503 cmp2 = Operand(input); 5504 final_branch_condition = eq; 5505 5506 } else if (type_name->Equals(heap()->undefined_string())) { 5507 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); 5508 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); 5509 // The first instruction of JumpIfSmi is an And - it is safe in the delay 5510 // slot. 5511 __ JumpIfSmi(input, false_label); 5512 // Check for undetectable objects => true. 5513 __ lw(input, FieldMemOperand(input, HeapObject::kMapOffset)); 5514 __ lbu(at, FieldMemOperand(input, Map::kBitFieldOffset)); 5515 __ And(at, at, 1 << Map::kIsUndetectable); 5516 cmp1 = at; 5517 cmp2 = Operand(zero_reg); 5518 final_branch_condition = ne; 5519 5520 } else if (type_name->Equals(heap()->function_string())) { 5521 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); 5522 __ JumpIfSmi(input, false_label); 5523 __ GetObjectType(input, scratch, input); 5524 __ Branch(true_label, eq, input, Operand(JS_FUNCTION_TYPE)); 5525 cmp1 = input; 5526 cmp2 = Operand(JS_FUNCTION_PROXY_TYPE); 5527 final_branch_condition = eq; 5528 5529 } else if (type_name->Equals(heap()->object_string())) { 5530 __ JumpIfSmi(input, false_label); 5531 if (!FLAG_harmony_typeof) { 5532 __ LoadRoot(at, Heap::kNullValueRootIndex); 5533 __ Branch(USE_DELAY_SLOT, true_label, eq, at, Operand(input)); 5534 } 5535 Register map = input; 5536 __ GetObjectType(input, map, scratch); 5537 __ Branch(false_label, 5538 lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); 5539 __ Branch(USE_DELAY_SLOT, false_label, 5540 gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); 5541 // map is still valid, so the BitField can be loaded in delay slot. 5542 // Check for undetectable objects => false. 5543 __ lbu(at, FieldMemOperand(map, Map::kBitFieldOffset)); 5544 __ And(at, at, 1 << Map::kIsUndetectable); 5545 cmp1 = at; 5546 cmp2 = Operand(zero_reg); 5547 final_branch_condition = eq; 5548 5549 } else { 5550 cmp1 = at; 5551 cmp2 = Operand(zero_reg); // Set to valid regs, to avoid caller assertion. 5552 __ Branch(false_label); 5553 } 5554 5555 return final_branch_condition; 5556 } 5557 5558 5559 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { 5560 Register temp1 = ToRegister(instr->temp()); 5561 5562 EmitIsConstructCall(temp1, scratch0()); 5563 5564 EmitBranch(instr, eq, temp1, 5565 Operand(Smi::FromInt(StackFrame::CONSTRUCT))); 5566 } 5567 5568 5569 void LCodeGen::EmitIsConstructCall(Register temp1, Register temp2) { 5570 ASSERT(!temp1.is(temp2)); 5571 // Get the frame pointer for the calling frame. 5572 __ lw(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); 5573 5574 // Skip the arguments adaptor frame if it exists. 5575 Label check_frame_marker; 5576 __ lw(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset)); 5577 __ Branch(&check_frame_marker, ne, temp2, 5578 Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 5579 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset)); 5580 5581 // Check the marker in the calling frame. 5582 __ bind(&check_frame_marker); 5583 __ lw(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset)); 5584 } 5585 5586 5587 void LCodeGen::EnsureSpaceForLazyDeopt() { 5588 if (info()->IsStub()) return; 5589 // Ensure that we have enough space after the previous lazy-bailout 5590 // instruction for patching the code here. 5591 int current_pc = masm()->pc_offset(); 5592 int patch_size = Deoptimizer::patch_size(); 5593 if (current_pc < last_lazy_deopt_pc_ + patch_size) { 5594 int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc; 5595 ASSERT_EQ(0, padding_size % Assembler::kInstrSize); 5596 while (padding_size > 0) { 5597 __ nop(); 5598 padding_size -= Assembler::kInstrSize; 5599 } 5600 } 5601 } 5602 5603 5604 void LCodeGen::DoLazyBailout(LLazyBailout* instr) { 5605 EnsureSpaceForLazyDeopt(); 5606 last_lazy_deopt_pc_ = masm()->pc_offset(); 5607 ASSERT(instr->HasEnvironment()); 5608 LEnvironment* env = instr->environment(); 5609 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 5610 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 5611 } 5612 5613 5614 void LCodeGen::DoDeoptimize(LDeoptimize* instr) { 5615 Deoptimizer::BailoutType type = instr->hydrogen()->type(); 5616 // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the 5617 // needed return address), even though the implementation of LAZY and EAGER is 5618 // now identical. When LAZY is eventually completely folded into EAGER, remove 5619 // the special case below. 5620 if (info()->IsStub() && type == Deoptimizer::EAGER) { 5621 type = Deoptimizer::LAZY; 5622 } 5623 5624 Comment(";;; deoptimize: %s", instr->hydrogen()->reason()); 5625 DeoptimizeIf(al, instr->environment(), type, zero_reg, Operand(zero_reg)); 5626 } 5627 5628 5629 void LCodeGen::DoDummyUse(LDummyUse* instr) { 5630 // Nothing to see here, move on! 5631 } 5632 5633 5634 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { 5635 PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); 5636 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); 5637 RecordSafepointWithLazyDeopt( 5638 instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS); 5639 ASSERT(instr->HasEnvironment()); 5640 LEnvironment* env = instr->environment(); 5641 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 5642 } 5643 5644 5645 void LCodeGen::DoStackCheck(LStackCheck* instr) { 5646 class DeferredStackCheck: public LDeferredCode { 5647 public: 5648 DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) 5649 : LDeferredCode(codegen), instr_(instr) { } 5650 virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } 5651 virtual LInstruction* instr() { return instr_; } 5652 private: 5653 LStackCheck* instr_; 5654 }; 5655 5656 ASSERT(instr->HasEnvironment()); 5657 LEnvironment* env = instr->environment(); 5658 // There is no LLazyBailout instruction for stack-checks. We have to 5659 // prepare for lazy deoptimization explicitly here. 5660 if (instr->hydrogen()->is_function_entry()) { 5661 // Perform stack overflow check. 5662 Label done; 5663 __ LoadRoot(at, Heap::kStackLimitRootIndex); 5664 __ Branch(&done, hs, sp, Operand(at)); 5665 StackCheckStub stub; 5666 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); 5667 EnsureSpaceForLazyDeopt(); 5668 last_lazy_deopt_pc_ = masm()->pc_offset(); 5669 __ bind(&done); 5670 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 5671 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); 5672 } else { 5673 ASSERT(instr->hydrogen()->is_backwards_branch()); 5674 // Perform stack overflow check if this goto needs it before jumping. 5675 DeferredStackCheck* deferred_stack_check = 5676 new(zone()) DeferredStackCheck(this, instr); 5677 __ LoadRoot(at, Heap::kStackLimitRootIndex); 5678 __ Branch(deferred_stack_check->entry(), lo, sp, Operand(at)); 5679 EnsureSpaceForLazyDeopt(); 5680 last_lazy_deopt_pc_ = masm()->pc_offset(); 5681 __ bind(instr->done_label()); 5682 deferred_stack_check->SetExit(instr->done_label()); 5683 RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt); 5684 // Don't record a deoptimization index for the safepoint here. 5685 // This will be done explicitly when emitting call and the safepoint in 5686 // the deferred code. 5687 } 5688 } 5689 5690 5691 void LCodeGen::DoOsrEntry(LOsrEntry* instr) { 5692 // This is a pseudo-instruction that ensures that the environment here is 5693 // properly registered for deoptimization and records the assembler's PC 5694 // offset. 5695 LEnvironment* environment = instr->environment(); 5696 5697 // If the environment were already registered, we would have no way of 5698 // backpatching it with the spill slot operands. 5699 ASSERT(!environment->HasBeenRegistered()); 5700 RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt); 5701 5702 // Normally we record the first unknown OSR value as the entrypoint to the OSR 5703 // code, but if there were none, record the entrypoint here. 5704 if (osr_pc_offset_ == -1) osr_pc_offset_ = masm()->pc_offset(); 5705 } 5706 5707 5708 void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) { 5709 Register result = ToRegister(instr->result()); 5710 Register object = ToRegister(instr->object()); 5711 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); 5712 DeoptimizeIf(eq, instr->environment(), object, Operand(at)); 5713 5714 Register null_value = t1; 5715 __ LoadRoot(null_value, Heap::kNullValueRootIndex); 5716 DeoptimizeIf(eq, instr->environment(), object, Operand(null_value)); 5717 5718 __ And(at, object, kSmiTagMask); 5719 DeoptimizeIf(eq, instr->environment(), at, Operand(zero_reg)); 5720 5721 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); 5722 __ GetObjectType(object, a1, a1); 5723 DeoptimizeIf(le, instr->environment(), a1, Operand(LAST_JS_PROXY_TYPE)); 5724 5725 Label use_cache, call_runtime; 5726 ASSERT(object.is(a0)); 5727 __ CheckEnumCache(null_value, &call_runtime); 5728 5729 __ lw(result, FieldMemOperand(object, HeapObject::kMapOffset)); 5730 __ Branch(&use_cache); 5731 5732 // Get the set of properties to enumerate. 5733 __ bind(&call_runtime); 5734 __ push(object); 5735 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); 5736 5737 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); 5738 ASSERT(result.is(v0)); 5739 __ LoadRoot(at, Heap::kMetaMapRootIndex); 5740 DeoptimizeIf(ne, instr->environment(), a1, Operand(at)); 5741 __ bind(&use_cache); 5742 } 5743 5744 5745 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { 5746 Register map = ToRegister(instr->map()); 5747 Register result = ToRegister(instr->result()); 5748 Label load_cache, done; 5749 __ EnumLength(result, map); 5750 __ Branch(&load_cache, ne, result, Operand(Smi::FromInt(0))); 5751 __ li(result, Operand(isolate()->factory()->empty_fixed_array())); 5752 __ jmp(&done); 5753 5754 __ bind(&load_cache); 5755 __ LoadInstanceDescriptors(map, result); 5756 __ lw(result, 5757 FieldMemOperand(result, DescriptorArray::kEnumCacheOffset)); 5758 __ lw(result, 5759 FieldMemOperand(result, FixedArray::SizeFor(instr->idx()))); 5760 DeoptimizeIf(eq, instr->environment(), result, Operand(zero_reg)); 5761 5762 __ bind(&done); 5763 } 5764 5765 5766 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { 5767 Register object = ToRegister(instr->value()); 5768 Register map = ToRegister(instr->map()); 5769 __ lw(scratch0(), FieldMemOperand(object, HeapObject::kMapOffset)); 5770 DeoptimizeIf(ne, instr->environment(), map, Operand(scratch0())); 5771 } 5772 5773 5774 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { 5775 Register object = ToRegister(instr->object()); 5776 Register index = ToRegister(instr->index()); 5777 Register result = ToRegister(instr->result()); 5778 Register scratch = scratch0(); 5779 5780 Label out_of_object, done; 5781 __ Branch(USE_DELAY_SLOT, &out_of_object, lt, index, Operand(zero_reg)); 5782 __ sll(scratch, index, kPointerSizeLog2 - kSmiTagSize); // In delay slot. 5783 5784 STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize); 5785 __ Addu(scratch, object, scratch); 5786 __ lw(result, FieldMemOperand(scratch, JSObject::kHeaderSize)); 5787 5788 __ Branch(&done); 5789 5790 __ bind(&out_of_object); 5791 __ lw(result, FieldMemOperand(object, JSObject::kPropertiesOffset)); 5792 // Index is equal to negated out of object property index plus 1. 5793 __ Subu(scratch, result, scratch); 5794 __ lw(result, FieldMemOperand(scratch, 5795 FixedArray::kHeaderSize - kPointerSize)); 5796 __ bind(&done); 5797 } 5798 5799 5800 #undef __ 5801 5802 } } // namespace v8::internal 5803