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