~james-page/ubuntu/precise/nodejs/0.6.x-merge

« back to all changes in this revision

Viewing changes to deps/v8/src/arm/lithium-codegen-arm.cc

  • Committer: James Page
  • Date: 2012-03-30 12:09:16 UTC
  • mfrom: (7.1.23 sid)
  • Revision ID: james.page@canonical.com-20120330120916-40hfu9o00qr5t87b
* Merge from Debian unstable:
  - New upstream release (LP: #892034).
  - This package is x86/arm only. Update control to match
  - d/patches/2009_increase_test_timeout.patch: Increased default test
    timeout from 60 to 120 seconds to support reliable execution of all
    tests on armhf/armel architectures.
  - d/patches/2005_expected_failing_tests.patch: 
    - Allow racey tests to fail: test-cluster-kill-workers,
      test-child-process-fork2 
    - Allow test-fs-watch to fail as LP buildd's don't support
      inotify.
    - Revert all other Ubuntu changes as no longer required.
* Update Standards-Version to 3.9.3.
* Patch wscript to enable build on mipsel arch, libv8 being available.
  Upstream does not support that arch, failure expected.
* test-cluster-kill-workers is expected to fail on armhf,
  Bug#660802 will be closed when test pass.
* test-buffer is expected to fail on armel,
  Bug#660800 will be closed when test pass.
* Add epoch to dependency on libev >= 1:4.11. Closes: bug#658441.
* Remove tools/doc because node-doc-generator has no license for now.
* Add copyright for doc/sh* files (shjs).
* source.lintian-overrides : source-contains-waf-binary tools/node-waf
  it is simply not the case here.
* test-stream-pipe-multi expected to timeout sometimes on busy builds. 
* New upstream release.
* Remove upstream patches.
* test-dgram-pingpong expected to timeout, the test itself is buggy.
* test-buffer expected to fail on armel, allow building package to make
  it easier to find the cause of the failure.
  Closes: bug#639636.
* Expect tests dgram-multicast and broadcast to fail.
  debian/patches/2005_expected_failing_tests.patch
* Drop dpkg-source local-options: Defaults since dpkg-source 1.16.1.
* New upstream release.
* Depend on libev-dev 4.11, see bug#657080.
* Bump dependency on openssl to 1.0.0g.
* Remove useless uv_loop_refcount from libuv,
  refreshed 2009_fix_shared_ev.patch.
* Apply to upstream patches landed after 0.6.10 release,
  to fix debugger repl and http client.
* New upstream release. Closes:bug#650661
* Repackage to remove non-dfsg font files ./deps/npm/html/*/*.ttf
* Remove unneeded bundled dependencies: lighter tarball,
  debian/copyright is easier to maintain.
* Drop unneeded build-dependency on scons.
* Depend on zlib1g, libc-ares, libev.
  Patches done to support building with those shared libs.
* Fix DEB_UPSTREAM_URL in debian/rules, and debian/watch.
* nodejs.pc file for pkgconfig is no more available.
* Build-depend on procps package, a test is using /bin/ps.
* Refreshed debian/patches/2005_expected_failing_tests.patch,
  only for tests that need networking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
 
 
28
#include "v8.h"
 
29
 
28
30
#include "arm/lithium-codegen-arm.h"
29
31
#include "arm/lithium-gap-resolver-arm.h"
30
32
#include "code-stubs.h"
34
36
namespace internal {
35
37
 
36
38
 
37
 
class SafepointGenerator : public PostCallGenerator {
 
39
class SafepointGenerator : public CallWrapper {
38
40
 public:
39
41
  SafepointGenerator(LCodeGen* codegen,
40
42
                     LPointerMap* pointers,
41
 
                     int deoptimization_index)
 
43
                     Safepoint::DeoptMode mode)
42
44
      : codegen_(codegen),
43
45
        pointers_(pointers),
44
 
        deoptimization_index_(deoptimization_index) { }
 
46
        deopt_mode_(mode) { }
45
47
  virtual ~SafepointGenerator() { }
46
48
 
47
 
  virtual void Generate() {
48
 
    codegen_->RecordSafepoint(pointers_, deoptimization_index_);
 
49
  virtual void BeforeCall(int call_size) const { }
 
50
 
 
51
  virtual void AfterCall() const {
 
52
    codegen_->RecordSafepoint(pointers_, deopt_mode_);
49
53
  }
50
54
 
51
55
 private:
52
56
  LCodeGen* codegen_;
53
57
  LPointerMap* pointers_;
54
 
  int deoptimization_index_;
 
58
  Safepoint::DeoptMode deopt_mode_;
55
59
};
56
60
 
57
61
 
66
70
  return GeneratePrologue() &&
67
71
      GenerateBody() &&
68
72
      GenerateDeferredCode() &&
 
73
      GenerateDeoptJumpTable() &&
69
74
      GenerateSafepointTable();
70
75
}
71
76
 
72
77
 
73
78
void LCodeGen::FinishCode(Handle<Code> code) {
74
79
  ASSERT(is_done());
75
 
  code->set_stack_slots(StackSlotCount());
 
80
  code->set_stack_slots(GetStackSlotCount());
76
81
  code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
77
82
  PopulateDeoptimizationData(code);
78
 
  Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
79
83
}
80
84
 
81
85
 
82
86
void LCodeGen::Abort(const char* format, ...) {
83
87
  if (FLAG_trace_bailout) {
84
 
    SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
85
 
    PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
 
88
    SmartArrayPointer<char> name(
 
89
        info()->shared_info()->DebugName()->ToCString());
 
90
    PrintF("Aborting LCodeGen in @\"%s\": ", *name);
86
91
    va_list arguments;
87
92
    va_start(arguments, format);
88
93
    OS::VPrint(format, arguments);
126
131
  // fp: Caller's frame pointer.
127
132
  // lr: Caller's pc.
128
133
 
 
134
  // Strict mode functions and builtins need to replace the receiver
 
135
  // with undefined when called as functions (without an explicit
 
136
  // receiver object). r5 is zero for method calls and non-zero for
 
137
  // function calls.
 
138
  if (info_->is_strict_mode() || info_->is_native()) {
 
139
    Label ok;
 
140
    __ cmp(r5, Operand(0));
 
141
    __ b(eq, &ok);
 
142
    int receiver_offset = scope()->num_parameters() * kPointerSize;
 
143
    __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
 
144
    __ str(r2, MemOperand(sp, receiver_offset));
 
145
    __ bind(&ok);
 
146
  }
 
147
 
129
148
  __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
130
149
  __ add(fp, sp, Operand(2 * kPointerSize));  // Adjust FP to point to saved FP.
131
150
 
132
151
  // Reserve space for the stack slots needed by the code.
133
 
  int slots = StackSlotCount();
 
152
  int slots = GetStackSlotCount();
134
153
  if (slots > 0) {
135
154
    if (FLAG_debug_code) {
136
155
      __ mov(r0, Operand(slots));
155
174
      FastNewContextStub stub(heap_slots);
156
175
      __ CallStub(&stub);
157
176
    } else {
158
 
      __ CallRuntime(Runtime::kNewContext, 1);
 
177
      __ CallRuntime(Runtime::kNewFunctionContext, 1);
159
178
    }
160
 
    RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
 
179
    RecordSafepoint(Safepoint::kNoLazyDeopt);
161
180
    // Context is returned in both r0 and cp.  It replaces the context
162
181
    // passed to us.  It's saved in the stack and kept live in cp.
163
182
    __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
164
183
    // Copy any necessary parameters into the context.
165
184
    int num_parameters = scope()->num_parameters();
166
185
    for (int i = 0; i < num_parameters; i++) {
167
 
      Slot* slot = scope()->parameter(i)->AsSlot();
168
 
      if (slot != NULL && slot->type() == Slot::CONTEXT) {
 
186
      Variable* var = scope()->parameter(i);
 
187
      if (var->IsContextSlot()) {
169
188
        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
170
189
            (num_parameters - 1 - i) * kPointerSize;
171
190
        // Load parameter from stack.
172
191
        __ ldr(r0, MemOperand(fp, parameter_offset));
173
192
        // Store it in the context.
174
 
        __ mov(r1, Operand(Context::SlotOffset(slot->index())));
 
193
        __ mov(r1, Operand(Context::SlotOffset(var->index())));
175
194
        __ str(r0, MemOperand(cp, r1));
176
195
        // Update the write barrier. This clobbers all involved
177
196
        // registers, so we have to use two more registers to avoid
208
227
      instr->CompileToNative(this);
209
228
    }
210
229
  }
 
230
  EnsureSpaceForLazyDeopt();
211
231
  return !is_aborted();
212
232
}
213
233
 
214
234
 
215
 
LInstruction* LCodeGen::GetNextInstruction() {
216
 
  if (current_instruction_ < instructions_->length() - 1) {
217
 
    return instructions_->at(current_instruction_ + 1);
218
 
  } else {
219
 
    return NULL;
220
 
  }
221
 
}
222
 
 
223
 
 
224
235
bool LCodeGen::GenerateDeferredCode() {
225
236
  ASSERT(is_generating());
226
 
  for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
227
 
    LDeferredCode* code = deferred_[i];
228
 
    __ bind(code->entry());
229
 
    code->Generate();
230
 
    __ jmp(code->exit());
 
237
  if (deferred_.length() > 0) {
 
238
    for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
 
239
      LDeferredCode* code = deferred_[i];
 
240
      __ bind(code->entry());
 
241
      code->Generate();
 
242
      __ jmp(code->exit());
 
243
    }
231
244
  }
232
245
 
233
 
  // Force constant pool emission at the end of deferred code to make
234
 
  // sure that no constant pools are emitted after the official end of
235
 
  // the instruction sequence.
 
246
  // Force constant pool emission at the end of the deferred code to make
 
247
  // sure that no constant pools are emitted after.
236
248
  masm()->CheckConstPool(true, false);
237
249
 
238
 
  // Deferred code is the last part of the instruction sequence. Mark
239
 
  // the generated code as done unless we bailed out.
 
250
  return !is_aborted();
 
251
}
 
252
 
 
253
 
 
254
bool LCodeGen::GenerateDeoptJumpTable() {
 
255
  // Check that the jump table is accessible from everywhere in the function
 
256
  // code, ie that offsets to the table can be encoded in the 24bit signed
 
257
  // immediate of a branch instruction.
 
258
  // To simplify we consider the code size from the first instruction to the
 
259
  // end of the jump table. We also don't consider the pc load delta.
 
260
  // Each entry in the jump table generates one instruction and inlines one
 
261
  // 32bit data after it.
 
262
  if (!is_int24((masm()->pc_offset() / Assembler::kInstrSize) +
 
263
      deopt_jump_table_.length() * 2)) {
 
264
    Abort("Generated code is too large");
 
265
  }
 
266
 
 
267
  // Block the constant pool emission during the jump table emission.
 
268
  __ BlockConstPoolFor(deopt_jump_table_.length());
 
269
  __ RecordComment("[ Deoptimisation jump table");
 
270
  Label table_start;
 
271
  __ bind(&table_start);
 
272
  for (int i = 0; i < deopt_jump_table_.length(); i++) {
 
273
    __ bind(&deopt_jump_table_[i].label);
 
274
    __ ldr(pc, MemOperand(pc, Assembler::kInstrSize - Assembler::kPcLoadDelta));
 
275
    __ dd(reinterpret_cast<uint32_t>(deopt_jump_table_[i].address));
 
276
  }
 
277
  ASSERT(masm()->InstructionsGeneratedSince(&table_start) ==
 
278
      deopt_jump_table_.length() * 2);
 
279
  __ RecordComment("]");
 
280
 
 
281
  // The deoptimization jump table is the last part of the instruction
 
282
  // sequence. Mark the generated code as done unless we bailed out.
240
283
  if (!is_aborted()) status_ = DONE;
241
284
  return !is_aborted();
242
285
}
244
287
 
245
288
bool LCodeGen::GenerateSafepointTable() {
246
289
  ASSERT(is_done());
247
 
  safepoints_.Emit(masm(), StackSlotCount());
 
290
  safepoints_.Emit(masm(), GetStackSlotCount());
248
291
  return !is_aborted();
249
292
}
250
293
 
440
483
    translation->StoreDoubleStackSlot(op->index());
441
484
  } else if (op->IsArgument()) {
442
485
    ASSERT(is_tagged);
443
 
    int src_index = StackSlotCount() + op->index();
 
486
    int src_index = GetStackSlotCount() + op->index();
444
487
    translation->StoreStackSlot(src_index);
445
488
  } else if (op->IsRegister()) {
446
489
    Register reg = ToRegister(op);
477
520
  LPointerMap* pointers = instr->pointer_map();
478
521
  RecordPosition(pointers->position());
479
522
  __ Call(code, mode);
480
 
  RegisterLazyDeoptimization(instr, safepoint_mode);
 
523
  RecordSafepointWithLazyDeopt(instr, safepoint_mode);
 
524
 
 
525
  // Signal that we don't inline smi code before these stubs in the
 
526
  // optimizing code generator.
 
527
  if (code->kind() == Code::BINARY_OP_IC ||
 
528
      code->kind() == Code::COMPARE_IC) {
 
529
    __ nop();
 
530
  }
481
531
}
482
532
 
483
533
 
484
 
void LCodeGen::CallRuntime(Runtime::Function* function,
 
534
void LCodeGen::CallRuntime(const Runtime::Function* function,
485
535
                           int num_arguments,
486
536
                           LInstruction* instr) {
487
537
  ASSERT(instr != NULL);
490
540
  RecordPosition(pointers->position());
491
541
 
492
542
  __ CallRuntime(function, num_arguments);
493
 
  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
 
543
  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
494
544
}
495
545
 
496
546
 
499
549
                                       LInstruction* instr) {
500
550
  __ CallRuntimeSaveDoubles(id);
501
551
  RecordSafepointWithRegisters(
502
 
      instr->pointer_map(), argc, Safepoint::kNoDeoptimizationIndex);
503
 
}
504
 
 
505
 
 
506
 
void LCodeGen::RegisterLazyDeoptimization(LInstruction* instr,
507
 
                                          SafepointMode safepoint_mode) {
508
 
  // Create the environment to bailout to. If the call has side effects
509
 
  // execution has to continue after the call otherwise execution can continue
510
 
  // from a previous bailout point repeating the call.
511
 
  LEnvironment* deoptimization_environment;
512
 
  if (instr->HasDeoptimizationEnvironment()) {
513
 
    deoptimization_environment = instr->deoptimization_environment();
514
 
  } else {
515
 
    deoptimization_environment = instr->environment();
516
 
  }
517
 
 
518
 
  RegisterEnvironmentForDeoptimization(deoptimization_environment);
519
 
  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
520
 
    RecordSafepoint(instr->pointer_map(),
521
 
                    deoptimization_environment->deoptimization_index());
522
 
  } else {
523
 
    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
524
 
    RecordSafepointWithRegisters(
525
 
        instr->pointer_map(),
526
 
        0,
527
 
        deoptimization_environment->deoptimization_index());
528
 
  }
529
 
}
530
 
 
531
 
 
532
 
void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment) {
 
552
      instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
 
553
}
 
554
 
 
555
 
 
556
void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
 
557
                                                    Safepoint::DeoptMode mode) {
533
558
  if (!environment->HasBeenRegistered()) {
534
559
    // Physical stack frame layout:
535
560
    // -x ............. -4  0 ..................................... y
551
576
    Translation translation(&translations_, frame_count);
552
577
    WriteTranslation(environment, &translation);
553
578
    int deoptimization_index = deoptimizations_.length();
554
 
    environment->Register(deoptimization_index, translation.index());
 
579
    int pc_offset = masm()->pc_offset();
 
580
    environment->Register(deoptimization_index,
 
581
                          translation.index(),
 
582
                          (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
555
583
    deoptimizations_.Add(environment);
556
584
  }
557
585
}
558
586
 
559
587
 
560
588
void LCodeGen::DeoptimizeIf(Condition cc, LEnvironment* environment) {
561
 
  RegisterEnvironmentForDeoptimization(environment);
 
589
  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
562
590
  ASSERT(environment->HasBeenRegistered());
563
591
  int id = environment->deoptimization_index();
564
592
  Address entry = Deoptimizer::GetDeoptimizationEntry(id, Deoptimizer::EAGER);
576
604
    return;
577
605
  }
578
606
 
 
607
  if (FLAG_trap_on_deopt) __ stop("trap_on_deopt", cc);
 
608
 
579
609
  if (cc == al) {
580
 
    if (FLAG_trap_on_deopt) __ stop("trap_on_deopt");
581
610
    __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
582
611
  } else {
583
 
    if (FLAG_trap_on_deopt) {
584
 
      Label done;
585
 
      __ b(&done, NegateCondition(cc));
586
 
      __ stop("trap_on_deopt");
587
 
      __ Jump(entry, RelocInfo::RUNTIME_ENTRY);
588
 
      __ bind(&done);
589
 
    } else {
590
 
      __ Jump(entry, RelocInfo::RUNTIME_ENTRY, cc);
 
612
    // We often have several deopts to the same entry, reuse the last
 
613
    // jump entry if this is the case.
 
614
    if (deopt_jump_table_.is_empty() ||
 
615
        (deopt_jump_table_.last().address != entry)) {
 
616
      deopt_jump_table_.Add(JumpTableEntry(entry));
591
617
    }
 
618
    __ b(cc, &deopt_jump_table_.last().label);
592
619
  }
593
620
}
594
621
 
598
625
  if (length == 0) return;
599
626
  ASSERT(FLAG_deopt);
600
627
  Handle<DeoptimizationInputData> data =
601
 
      Factory::NewDeoptimizationInputData(length, TENURED);
 
628
      factory()->NewDeoptimizationInputData(length, TENURED);
602
629
 
603
630
  Handle<ByteArray> translations = translations_.CreateByteArray();
604
631
  data->SetTranslationByteArray(*translations);
605
632
  data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
606
633
 
607
634
  Handle<FixedArray> literals =
608
 
      Factory::NewFixedArray(deoptimization_literals_.length(), TENURED);
 
635
      factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
609
636
  for (int i = 0; i < deoptimization_literals_.length(); i++) {
610
637
    literals->set(i, *deoptimization_literals_[i]);
611
638
  }
621
648
    data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
622
649
    data->SetArgumentsStackHeight(i,
623
650
                                  Smi::FromInt(env->arguments_stack_height()));
 
651
    data->SetPc(i, Smi::FromInt(env->pc_offset()));
624
652
  }
625
653
  code->set_deoptimization_data(*data);
626
654
}
652
680
}
653
681
 
654
682
 
 
683
void LCodeGen::RecordSafepointWithLazyDeopt(
 
684
    LInstruction* instr, SafepointMode safepoint_mode) {
 
685
  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
 
686
    RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
 
687
  } else {
 
688
    ASSERT(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
 
689
    RecordSafepointWithRegisters(
 
690
        instr->pointer_map(), 0, Safepoint::kLazyDeopt);
 
691
  }
 
692
}
 
693
 
 
694
 
655
695
void LCodeGen::RecordSafepoint(
656
696
    LPointerMap* pointers,
657
697
    Safepoint::Kind kind,
658
698
    int arguments,
659
 
    int deoptimization_index) {
 
699
    Safepoint::DeoptMode deopt_mode) {
660
700
  ASSERT(expected_safepoint_kind_ == kind);
661
701
 
662
702
  const ZoneList<LOperand*>* operands = pointers->operands();
663
703
  Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
664
 
      kind, arguments, deoptimization_index);
 
704
      kind, arguments, deopt_mode);
665
705
  for (int i = 0; i < operands->length(); i++) {
666
706
    LOperand* pointer = operands->at(i);
667
707
    if (pointer->IsStackSlot()) {
678
718
 
679
719
 
680
720
void LCodeGen::RecordSafepoint(LPointerMap* pointers,
681
 
                               int deoptimization_index) {
682
 
  RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
 
721
                               Safepoint::DeoptMode deopt_mode) {
 
722
  RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
683
723
}
684
724
 
685
725
 
686
 
void LCodeGen::RecordSafepoint(int deoptimization_index) {
 
726
void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
687
727
  LPointerMap empty_pointers(RelocInfo::kNoPosition);
688
 
  RecordSafepoint(&empty_pointers, deoptimization_index);
 
728
  RecordSafepoint(&empty_pointers, deopt_mode);
689
729
}
690
730
 
691
731
 
692
732
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
693
733
                                            int arguments,
694
 
                                            int deoptimization_index) {
695
 
  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
696
 
      deoptimization_index);
 
734
                                            Safepoint::DeoptMode deopt_mode) {
 
735
  RecordSafepoint(
 
736
      pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
697
737
}
698
738
 
699
739
 
700
740
void LCodeGen::RecordSafepointWithRegistersAndDoubles(
701
741
    LPointerMap* pointers,
702
742
    int arguments,
703
 
    int deoptimization_index) {
704
 
  RecordSafepoint(pointers, Safepoint::kWithRegistersAndDoubles, arguments,
705
 
      deoptimization_index);
 
743
    Safepoint::DeoptMode deopt_mode) {
 
744
  RecordSafepoint(
 
745
      pointers, Safepoint::kWithRegistersAndDoubles, arguments, deopt_mode);
706
746
}
707
747
 
708
748
 
709
749
void LCodeGen::RecordPosition(int position) {
710
 
  if (!FLAG_debug_info || position == RelocInfo::kNoPosition) return;
 
750
  if (position == RelocInfo::kNoPosition) return;
711
751
  masm()->positions_recorder()->RecordPosition(position);
712
752
}
713
753
 
720
760
  }
721
761
  __ bind(label->label());
722
762
  current_block_ = label->block_id();
723
 
  LCodeGen::DoGap(label);
 
763
  DoGap(label);
724
764
}
725
765
 
726
766
 
737
777
    LParallelMove* move = gap->GetParallelMove(inner_pos);
738
778
    if (move != NULL) DoParallelMove(move);
739
779
  }
740
 
 
741
 
  LInstruction* next = GetNextInstruction();
742
 
  if (next != NULL && next->IsLazyBailout()) {
743
 
    int pc = masm()->pc_offset();
744
 
    safepoints_.SetPcAfterGap(pc);
745
 
  }
 
780
}
 
781
 
 
782
 
 
783
void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
 
784
  DoGap(instr);
746
785
}
747
786
 
748
787
 
769
808
      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
770
809
      break;
771
810
    }
772
 
    case CodeStub::StringCharAt: {
773
 
      StringCharAtStub stub;
774
 
      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
775
 
      break;
776
 
    }
777
 
    case CodeStub::MathPow: {
778
 
      Abort("MathPowStub unimplemented.");
779
 
      break;
780
 
    }
781
811
    case CodeStub::NumberToString: {
782
812
      NumberToStringStub stub;
783
813
      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
795
825
    }
796
826
    case CodeStub::TranscendentalCache: {
797
827
      __ ldr(r0, MemOperand(sp, 0));
798
 
      TranscendentalCacheStub stub(instr->transcendental_type());
 
828
      TranscendentalCacheStub stub(instr->transcendental_type(),
 
829
                                   TranscendentalCacheStub::TAGGED);
799
830
      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
800
831
      break;
801
832
    }
811
842
 
812
843
 
813
844
void LCodeGen::DoModI(LModI* instr) {
814
 
  class DeferredModI: public LDeferredCode {
815
 
   public:
816
 
    DeferredModI(LCodeGen* codegen, LModI* instr)
817
 
        : LDeferredCode(codegen), instr_(instr) { }
818
 
    virtual void Generate() {
819
 
      codegen()->DoDeferredBinaryOpStub(instr_, Token::MOD);
 
845
  if (instr->hydrogen()->HasPowerOf2Divisor()) {
 
846
    Register dividend = ToRegister(instr->InputAt(0));
 
847
    Register result = ToRegister(instr->result());
 
848
 
 
849
    int32_t divisor =
 
850
        HConstant::cast(instr->hydrogen()->right())->Integer32Value();
 
851
 
 
852
    if (divisor < 0) divisor = -divisor;
 
853
 
 
854
    Label positive_dividend, done;
 
855
    __ cmp(dividend, Operand(0));
 
856
    __ b(pl, &positive_dividend);
 
857
    __ rsb(result, dividend, Operand(0));
 
858
    __ and_(result, result, Operand(divisor - 1), SetCC);
 
859
    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
 
860
      DeoptimizeIf(eq, instr->environment());
820
861
    }
821
 
   private:
822
 
    LModI* instr_;
823
 
  };
 
862
    __ rsb(result, result, Operand(0));
 
863
    __ b(&done);
 
864
    __ bind(&positive_dividend);
 
865
    __ and_(result, dividend, Operand(divisor - 1));
 
866
    __ bind(&done);
 
867
    return;
 
868
  }
 
869
 
824
870
  // These registers hold untagged 32 bit values.
825
871
  Register left = ToRegister(instr->InputAt(0));
826
872
  Register right = ToRegister(instr->InputAt(1));
827
873
  Register result = ToRegister(instr->result());
 
874
 
828
875
  Register scratch = scratch0();
829
 
 
830
 
  Label deoptimize, done;
 
876
  Register scratch2 = ToRegister(instr->TempAt(0));
 
877
  DwVfpRegister dividend = ToDoubleRegister(instr->TempAt(1));
 
878
  DwVfpRegister divisor = ToDoubleRegister(instr->TempAt(2));
 
879
  DwVfpRegister quotient = double_scratch0();
 
880
 
 
881
  ASSERT(!dividend.is(divisor));
 
882
  ASSERT(!dividend.is(quotient));
 
883
  ASSERT(!divisor.is(quotient));
 
884
  ASSERT(!scratch.is(left));
 
885
  ASSERT(!scratch.is(right));
 
886
  ASSERT(!scratch.is(result));
 
887
 
 
888
  Label done, vfp_modulo, both_positive, right_negative;
 
889
 
831
890
  // Check for x % 0.
832
891
  if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
833
 
    __ tst(right, Operand(right));
834
 
    __ b(eq, &deoptimize);
835
 
  }
836
 
 
837
 
  // Check for (0 % -x) that will produce negative zero.
838
 
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
839
 
    Label ok;
840
 
    __ tst(left, Operand(left));
841
 
    __ b(ne, &ok);
842
 
    __ tst(right, Operand(right));
843
 
    __ b(pl, &ok);
844
 
    __ b(al, &deoptimize);
845
 
    __ bind(&ok);
846
 
  }
847
 
 
848
 
  // Try a few common cases before using the stub.
849
 
  Label call_stub;
 
892
    __ cmp(right, Operand(0));
 
893
    DeoptimizeIf(eq, instr->environment());
 
894
  }
 
895
 
 
896
  __ Move(result, left);
 
897
 
 
898
  // (0 % x) must yield 0 (if x is finite, which is the case here).
 
899
  __ cmp(left, Operand(0));
 
900
  __ b(eq, &done);
 
901
  // Preload right in a vfp register.
 
902
  __ vmov(divisor.low(), right);
 
903
  __ b(lt, &vfp_modulo);
 
904
 
 
905
  __ cmp(left, Operand(right));
 
906
  __ b(lt, &done);
 
907
 
 
908
  // Check for (positive) power of two on the right hand side.
 
909
  __ JumpIfNotPowerOfTwoOrZeroAndNeg(right,
 
910
                                     scratch,
 
911
                                     &right_negative,
 
912
                                     &both_positive);
 
913
  // Perform modulo operation (scratch contains right - 1).
 
914
  __ and_(result, scratch, Operand(left));
 
915
  __ b(&done);
 
916
 
 
917
  __ bind(&right_negative);
 
918
  // Negate right. The sign of the divisor does not matter.
 
919
  __ rsb(right, right, Operand(0));
 
920
 
 
921
  __ bind(&both_positive);
850
922
  const int kUnfolds = 3;
851
 
  // Skip if either side is negative.
852
 
  __ cmp(left, Operand(0));
853
 
  __ cmp(right, Operand(0), NegateCondition(mi));
854
 
  __ b(mi, &call_stub);
855
923
  // If the right hand side is smaller than the (nonnegative)
856
 
  // left hand side, it is the result. Else try a few subtractions
857
 
  // of the left hand side.
 
924
  // left hand side, the left hand side is the result.
 
925
  // Else try a few subtractions of the left hand side.
858
926
  __ mov(scratch, left);
859
927
  for (int i = 0; i < kUnfolds; i++) {
860
928
    // Check if the left hand side is less or equal than the
861
929
    // the right hand side.
862
 
    __ cmp(scratch, right);
 
930
    __ cmp(scratch, Operand(right));
863
931
    __ mov(result, scratch, LeaveCC, lt);
864
932
    __ b(lt, &done);
865
933
    // If not, reduce the left hand side by the right hand
867
935
    if (i < kUnfolds - 1) __ sub(scratch, scratch, right);
868
936
  }
869
937
 
870
 
  // Check for power of two on the right hand side.
871
 
  __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
872
 
  // Perform modulo operation (scratch contains right - 1).
873
 
  __ and_(result, scratch, Operand(left));
874
 
 
875
 
  __ bind(&call_stub);
876
 
  // Call the stub. The numbers in r0 and r1 have
877
 
  // to be tagged to Smis. If that is not possible, deoptimize.
878
 
  DeferredModI* deferred = new DeferredModI(this, instr);
879
 
  __ TrySmiTag(left, &deoptimize, scratch);
880
 
  __ TrySmiTag(right, &deoptimize, scratch);
881
 
 
882
 
  __ b(al, deferred->entry());
883
 
  __ bind(deferred->exit());
884
 
 
885
 
  // If the result in r0 is a Smi, untag it, else deoptimize.
886
 
  __ JumpIfNotSmi(result, &deoptimize);
887
 
  __ SmiUntag(result);
888
 
 
889
 
  __ b(al, &done);
890
 
  __ bind(&deoptimize);
891
 
  DeoptimizeIf(al, instr->environment());
 
938
  __ bind(&vfp_modulo);
 
939
  // Load the arguments in VFP registers.
 
940
  // The divisor value is preloaded before. Be careful that 'right' is only live
 
941
  // on entry.
 
942
  __ vmov(dividend.low(), left);
 
943
  // From here on don't use right as it may have been reallocated (for example
 
944
  // to scratch2).
 
945
  right = no_reg;
 
946
 
 
947
  __ vcvt_f64_s32(dividend, dividend.low());
 
948
  __ vcvt_f64_s32(divisor, divisor.low());
 
949
 
 
950
  // We do not care about the sign of the divisor.
 
951
  __ vabs(divisor, divisor);
 
952
  // Compute the quotient and round it to a 32bit integer.
 
953
  __ vdiv(quotient, dividend, divisor);
 
954
  __ vcvt_s32_f64(quotient.low(), quotient);
 
955
  __ vcvt_f64_s32(quotient, quotient.low());
 
956
 
 
957
  // Compute the remainder in result.
 
958
  DwVfpRegister double_scratch = dividend;
 
959
  __ vmul(double_scratch, divisor, quotient);
 
960
  __ vcvt_s32_f64(double_scratch.low(), double_scratch);
 
961
  __ vmov(scratch, double_scratch.low());
 
962
 
 
963
  if (!instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
 
964
    __ sub(result, left, scratch);
 
965
  } else {
 
966
    Label ok;
 
967
    // Check for -0.
 
968
    __ sub(scratch2, left, scratch, SetCC);
 
969
    __ b(ne, &ok);
 
970
    __ cmp(left, Operand(0));
 
971
    DeoptimizeIf(mi, instr->environment());
 
972
    __ bind(&ok);
 
973
    // Load the result and we are done.
 
974
    __ mov(result, scratch2);
 
975
  }
 
976
 
892
977
  __ bind(&done);
893
978
}
894
979
 
912
997
 
913
998
  // Check for x / 0.
914
999
  if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
915
 
    __ tst(right, right);
 
1000
    __ cmp(right, Operand(0));
916
1001
    DeoptimizeIf(eq, instr->environment());
917
1002
  }
918
1003
 
919
1004
  // Check for (0 / -x) that will produce negative zero.
920
1005
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
921
1006
    Label left_not_zero;
922
 
    __ tst(left, Operand(left));
 
1007
    __ cmp(left, Operand(0));
923
1008
    __ b(ne, &left_not_zero);
924
 
    __ tst(right, Operand(right));
 
1009
    __ cmp(right, Operand(0));
925
1010
    DeoptimizeIf(mi, instr->environment());
926
1011
    __ bind(&left_not_zero);
927
1012
  }
994
1079
    __ mov(r0, right);
995
1080
    __ mov(r1, left);
996
1081
  }
997
 
  TypeRecordingBinaryOpStub stub(op, OVERWRITE_LEFT);
 
1082
  BinaryOpStub stub(op, OVERWRITE_LEFT);
998
1083
  __ CallStub(&stub);
999
1084
  RecordSafepointWithRegistersAndDoubles(instr->pointer_map(),
1000
1085
                                         0,
1001
 
                                         Safepoint::kNoDeoptimizationIndex);
 
1086
                                         Safepoint::kNoLazyDeopt);
1002
1087
  // Overwrite the stored value of r0 with the result of the stub.
1003
1088
  __ StoreToSafepointRegistersAndDoublesSlot(r0, r0);
1004
1089
}
1006
1091
 
1007
1092
void LCodeGen::DoMulI(LMulI* instr) {
1008
1093
  Register scratch = scratch0();
 
1094
  Register result = ToRegister(instr->result());
 
1095
  // Note that result may alias left.
1009
1096
  Register left = ToRegister(instr->InputAt(0));
1010
 
  Register right = EmitLoadRegister(instr->InputAt(1), scratch);
1011
 
 
1012
 
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero) &&
1013
 
      !instr->InputAt(1)->IsConstantOperand()) {
1014
 
    __ orr(ToRegister(instr->TempAt(0)), left, right);
1015
 
  }
1016
 
 
1017
 
  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
1018
 
    // scratch:left = left * right.
1019
 
    __ smull(left, scratch, left, right);
1020
 
    __ mov(ip, Operand(left, ASR, 31));
1021
 
    __ cmp(ip, Operand(scratch));
1022
 
    DeoptimizeIf(ne, instr->environment());
 
1097
  LOperand* right_op = instr->InputAt(1);
 
1098
 
 
1099
  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
 
1100
  bool bailout_on_minus_zero =
 
1101
    instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
 
1102
 
 
1103
  if (right_op->IsConstantOperand() && !can_overflow) {
 
1104
    // Use optimized code for specific constants.
 
1105
    int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
 
1106
 
 
1107
    if (bailout_on_minus_zero && (constant < 0)) {
 
1108
      // The case of a null constant will be handled separately.
 
1109
      // If constant is negative and left is null, the result should be -0.
 
1110
      __ cmp(left, Operand(0));
 
1111
      DeoptimizeIf(eq, instr->environment());
 
1112
    }
 
1113
 
 
1114
    switch (constant) {
 
1115
      case -1:
 
1116
        __ rsb(result, left, Operand(0));
 
1117
        break;
 
1118
      case 0:
 
1119
        if (bailout_on_minus_zero) {
 
1120
          // If left is strictly negative and the constant is null, the
 
1121
          // result is -0. Deoptimize if required, otherwise return 0.
 
1122
          __ cmp(left, Operand(0));
 
1123
          DeoptimizeIf(mi, instr->environment());
 
1124
        }
 
1125
        __ mov(result, Operand(0));
 
1126
        break;
 
1127
      case 1:
 
1128
        __ Move(result, left);
 
1129
        break;
 
1130
      default:
 
1131
        // Multiplying by powers of two and powers of two plus or minus
 
1132
        // one can be done faster with shifted operands.
 
1133
        // For other constants we emit standard code.
 
1134
        int32_t mask = constant >> 31;
 
1135
        uint32_t constant_abs = (constant + mask) ^ mask;
 
1136
 
 
1137
        if (IsPowerOf2(constant_abs) ||
 
1138
            IsPowerOf2(constant_abs - 1) ||
 
1139
            IsPowerOf2(constant_abs + 1)) {
 
1140
          if (IsPowerOf2(constant_abs)) {
 
1141
            int32_t shift = WhichPowerOf2(constant_abs);
 
1142
            __ mov(result, Operand(left, LSL, shift));
 
1143
          } else if (IsPowerOf2(constant_abs - 1)) {
 
1144
            int32_t shift = WhichPowerOf2(constant_abs - 1);
 
1145
            __ add(result, left, Operand(left, LSL, shift));
 
1146
          } else if (IsPowerOf2(constant_abs + 1)) {
 
1147
            int32_t shift = WhichPowerOf2(constant_abs + 1);
 
1148
            __ rsb(result, left, Operand(left, LSL, shift));
 
1149
          }
 
1150
 
 
1151
          // Correct the sign of the result is the constant is negative.
 
1152
          if (constant < 0)  __ rsb(result, result, Operand(0));
 
1153
 
 
1154
        } else {
 
1155
          // Generate standard code.
 
1156
          __ mov(ip, Operand(constant));
 
1157
          __ mul(result, left, ip);
 
1158
        }
 
1159
    }
 
1160
 
1023
1161
  } else {
1024
 
    __ mul(left, left, right);
1025
 
  }
 
1162
    Register right = EmitLoadRegister(right_op, scratch);
 
1163
    if (bailout_on_minus_zero) {
 
1164
      __ orr(ToRegister(instr->TempAt(0)), left, right);
 
1165
    }
1026
1166
 
1027
 
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
1028
 
    // Bail out if the result is supposed to be negative zero.
1029
 
    Label done;
1030
 
    __ tst(left, Operand(left));
1031
 
    __ b(ne, &done);
1032
 
    if (instr->InputAt(1)->IsConstantOperand()) {
1033
 
      if (ToInteger32(LConstantOperand::cast(instr->InputAt(1))) <= 0) {
1034
 
        DeoptimizeIf(al, instr->environment());
1035
 
      }
 
1167
    if (can_overflow) {
 
1168
      // scratch:result = left * right.
 
1169
      __ smull(result, scratch, left, right);
 
1170
      __ cmp(scratch, Operand(result, ASR, 31));
 
1171
      DeoptimizeIf(ne, instr->environment());
1036
1172
    } else {
1037
 
      // Test the non-zero operand for negative sign.
 
1173
      __ mul(result, left, right);
 
1174
    }
 
1175
 
 
1176
    if (bailout_on_minus_zero) {
 
1177
      // Bail out if the result is supposed to be negative zero.
 
1178
      Label done;
 
1179
      __ cmp(result, Operand(0));
 
1180
      __ b(ne, &done);
1038
1181
      __ cmp(ToRegister(instr->TempAt(0)), Operand(0));
1039
1182
      DeoptimizeIf(mi, instr->environment());
 
1183
      __ bind(&done);
1040
1184
    }
1041
 
    __ bind(&done);
1042
1185
  }
1043
1186
}
1044
1187
 
1045
1188
 
1046
1189
void LCodeGen::DoBitI(LBitI* instr) {
1047
 
  LOperand* left = instr->InputAt(0);
1048
 
  LOperand* right = instr->InputAt(1);
1049
 
  ASSERT(left->Equals(instr->result()));
1050
 
  ASSERT(left->IsRegister());
1051
 
  Register result = ToRegister(left);
1052
 
  Register right_reg = EmitLoadRegister(right, ip);
 
1190
  LOperand* left_op = instr->InputAt(0);
 
1191
  LOperand* right_op = instr->InputAt(1);
 
1192
  ASSERT(left_op->IsRegister());
 
1193
  Register left = ToRegister(left_op);
 
1194
  Register result = ToRegister(instr->result());
 
1195
  Operand right(no_reg);
 
1196
 
 
1197
  if (right_op->IsStackSlot() || right_op->IsArgument()) {
 
1198
    right = Operand(EmitLoadRegister(right_op, ip));
 
1199
  } else {
 
1200
    ASSERT(right_op->IsRegister() || right_op->IsConstantOperand());
 
1201
    right = ToOperand(right_op);
 
1202
  }
 
1203
 
1053
1204
  switch (instr->op()) {
1054
1205
    case Token::BIT_AND:
1055
 
      __ and_(result, ToRegister(left), Operand(right_reg));
 
1206
      __ and_(result, left, right);
1056
1207
      break;
1057
1208
    case Token::BIT_OR:
1058
 
      __ orr(result, ToRegister(left), Operand(right_reg));
 
1209
      __ orr(result, left, right);
1059
1210
      break;
1060
1211
    case Token::BIT_XOR:
1061
 
      __ eor(result, ToRegister(left), Operand(right_reg));
 
1212
      __ eor(result, left, right);
1062
1213
      break;
1063
1214
    default:
1064
1215
      UNREACHABLE();
1068
1219
 
1069
1220
 
1070
1221
void LCodeGen::DoShiftI(LShiftI* instr) {
 
1222
  // Both 'left' and 'right' are "used at start" (see LCodeGen::DoShift), so
 
1223
  // result may alias either of them.
 
1224
  LOperand* right_op = instr->InputAt(1);
 
1225
  Register left = ToRegister(instr->InputAt(0));
 
1226
  Register result = ToRegister(instr->result());
1071
1227
  Register scratch = scratch0();
1072
 
  LOperand* left = instr->InputAt(0);
1073
 
  LOperand* right = instr->InputAt(1);
1074
 
  ASSERT(left->Equals(instr->result()));
1075
 
  ASSERT(left->IsRegister());
1076
 
  Register result = ToRegister(left);
1077
 
  if (right->IsRegister()) {
1078
 
    // Mask the right operand.
1079
 
    __ and_(scratch, ToRegister(right), Operand(0x1F));
 
1228
  if (right_op->IsRegister()) {
 
1229
    // Mask the right_op operand.
 
1230
    __ and_(scratch, ToRegister(right_op), Operand(0x1F));
1080
1231
    switch (instr->op()) {
1081
1232
      case Token::SAR:
1082
 
        __ mov(result, Operand(result, ASR, scratch));
 
1233
        __ mov(result, Operand(left, ASR, scratch));
1083
1234
        break;
1084
1235
      case Token::SHR:
1085
1236
        if (instr->can_deopt()) {
1086
 
          __ mov(result, Operand(result, LSR, scratch), SetCC);
 
1237
          __ mov(result, Operand(left, LSR, scratch), SetCC);
1087
1238
          DeoptimizeIf(mi, instr->environment());
1088
1239
        } else {
1089
 
          __ mov(result, Operand(result, LSR, scratch));
 
1240
          __ mov(result, Operand(left, LSR, scratch));
1090
1241
        }
1091
1242
        break;
1092
1243
      case Token::SHL:
1093
 
        __ mov(result, Operand(result, LSL, scratch));
 
1244
        __ mov(result, Operand(left, LSL, scratch));
1094
1245
        break;
1095
1246
      default:
1096
1247
        UNREACHABLE();
1097
1248
        break;
1098
1249
    }
1099
1250
  } else {
1100
 
    int value = ToInteger32(LConstantOperand::cast(right));
 
1251
    // Mask the right_op operand.
 
1252
    int value = ToInteger32(LConstantOperand::cast(right_op));
1101
1253
    uint8_t shift_count = static_cast<uint8_t>(value & 0x1F);
1102
1254
    switch (instr->op()) {
1103
1255
      case Token::SAR:
1104
1256
        if (shift_count != 0) {
1105
 
          __ mov(result, Operand(result, ASR, shift_count));
 
1257
          __ mov(result, Operand(left, ASR, shift_count));
 
1258
        } else {
 
1259
          __ Move(result, left);
1106
1260
        }
1107
1261
        break;
1108
1262
      case Token::SHR:
1109
 
        if (shift_count == 0 && instr->can_deopt()) {
1110
 
          __ tst(result, Operand(0x80000000));
1111
 
          DeoptimizeIf(ne, instr->environment());
 
1263
        if (shift_count != 0) {
 
1264
          __ mov(result, Operand(left, LSR, shift_count));
1112
1265
        } else {
1113
 
          __ mov(result, Operand(result, LSR, shift_count));
 
1266
          if (instr->can_deopt()) {
 
1267
            __ tst(left, Operand(0x80000000));
 
1268
            DeoptimizeIf(ne, instr->environment());
 
1269
          }
 
1270
          __ Move(result, left);
1114
1271
        }
1115
1272
        break;
1116
1273
      case Token::SHL:
1117
1274
        if (shift_count != 0) {
1118
 
          __ mov(result, Operand(result, LSL, shift_count));
 
1275
          __ mov(result, Operand(left, LSL, shift_count));
 
1276
        } else {
 
1277
          __ Move(result, left);
1119
1278
        }
1120
1279
        break;
1121
1280
      default:
1127
1286
 
1128
1287
 
1129
1288
void LCodeGen::DoSubI(LSubI* instr) {
1130
 
  Register left = ToRegister(instr->InputAt(0));
1131
 
  Register right = EmitLoadRegister(instr->InputAt(1), ip);
1132
 
  ASSERT(instr->InputAt(0)->Equals(instr->result()));
1133
 
  __ sub(left, left, right, SetCC);
1134
 
  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
 
1289
  LOperand* left = instr->InputAt(0);
 
1290
  LOperand* right = instr->InputAt(1);
 
1291
  LOperand* result = instr->result();
 
1292
  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
 
1293
  SBit set_cond = can_overflow ? SetCC : LeaveCC;
 
1294
 
 
1295
  if (right->IsStackSlot() || right->IsArgument()) {
 
1296
    Register right_reg = EmitLoadRegister(right, ip);
 
1297
    __ sub(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
 
1298
  } else {
 
1299
    ASSERT(right->IsRegister() || right->IsConstantOperand());
 
1300
    __ sub(ToRegister(result), ToRegister(left), ToOperand(right), set_cond);
 
1301
  }
 
1302
 
 
1303
  if (can_overflow) {
1135
1304
    DeoptimizeIf(vs, instr->environment());
1136
1305
  }
1137
1306
}
1147
1316
  ASSERT(instr->result()->IsDoubleRegister());
1148
1317
  DwVfpRegister result = ToDoubleRegister(instr->result());
1149
1318
  double v = instr->value();
1150
 
  __ vmov(result, v);
 
1319
  __ Vmov(result, v);
1151
1320
}
1152
1321
 
1153
1322
 
1164
1333
}
1165
1334
 
1166
1335
 
1167
 
void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
 
1336
void LCodeGen::DoFixedArrayBaseLength(LFixedArrayBaseLength* instr) {
1168
1337
  Register result = ToRegister(instr->result());
1169
1338
  Register array = ToRegister(instr->InputAt(0));
1170
 
  __ ldr(result, FieldMemOperand(array, PixelArray::kLengthOffset));
 
1339
  __ ldr(result, FieldMemOperand(array, FixedArrayBase::kLengthOffset));
1171
1340
}
1172
1341
 
1173
1342
 
1174
 
void LCodeGen::DoFixedArrayLength(LFixedArrayLength* instr) {
 
1343
void LCodeGen::DoElementsKind(LElementsKind* instr) {
1175
1344
  Register result = ToRegister(instr->result());
1176
 
  Register array = ToRegister(instr->InputAt(0));
1177
 
  __ ldr(result, FieldMemOperand(array, FixedArray::kLengthOffset));
 
1345
  Register input = ToRegister(instr->InputAt(0));
 
1346
 
 
1347
  // Load map into |result|.
 
1348
  __ ldr(result, FieldMemOperand(input, HeapObject::kMapOffset));
 
1349
  // Load the map's "bit field 2" into |result|. We only need the first byte,
 
1350
  // but the following bit field extraction takes care of that anyway.
 
1351
  __ ldr(result, FieldMemOperand(result, Map::kBitField2Offset));
 
1352
  // Retrieve elements_kind from bit field 2.
 
1353
  __ ubfx(result, result, Map::kElementsKindShift, Map::kElementsKindBitCount);
1178
1354
}
1179
1355
 
1180
1356
 
1182
1358
  Register input = ToRegister(instr->InputAt(0));
1183
1359
  Register result = ToRegister(instr->result());
1184
1360
  Register map = ToRegister(instr->TempAt(0));
1185
 
  ASSERT(input.is(result));
1186
1361
  Label done;
1187
1362
 
1188
1363
  // If the object is a smi return the object.
1189
1364
  __ tst(input, Operand(kSmiTagMask));
 
1365
  __ Move(result, input, eq);
1190
1366
  __ b(eq, &done);
1191
1367
 
1192
1368
  // If the object is not a value type, return the object.
1193
1369
  __ CompareObjectType(input, map, map, JS_VALUE_TYPE);
 
1370
  __ Move(result, input, ne);
1194
1371
  __ b(ne, &done);
1195
1372
  __ ldr(result, FieldMemOperand(input, JSValue::kValueOffset));
1196
1373
 
1199
1376
 
1200
1377
 
1201
1378
void LCodeGen::DoBitNotI(LBitNotI* instr) {
1202
 
  LOperand* input = instr->InputAt(0);
1203
 
  ASSERT(input->Equals(instr->result()));
1204
 
  __ mvn(ToRegister(input), Operand(ToRegister(input)));
 
1379
  Register input = ToRegister(instr->InputAt(0));
 
1380
  Register result = ToRegister(instr->result());
 
1381
  __ mvn(result, Operand(input));
1205
1382
}
1206
1383
 
1207
1384
 
1219
1396
void LCodeGen::DoAddI(LAddI* instr) {
1220
1397
  LOperand* left = instr->InputAt(0);
1221
1398
  LOperand* right = instr->InputAt(1);
1222
 
  ASSERT(left->Equals(instr->result()));
1223
 
 
1224
 
  Register right_reg = EmitLoadRegister(right, ip);
1225
 
  __ add(ToRegister(left), ToRegister(left), Operand(right_reg), SetCC);
1226
 
 
1227
 
  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
 
1399
  LOperand* result = instr->result();
 
1400
  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
 
1401
  SBit set_cond = can_overflow ? SetCC : LeaveCC;
 
1402
 
 
1403
  if (right->IsStackSlot() || right->IsArgument()) {
 
1404
    Register right_reg = EmitLoadRegister(right, ip);
 
1405
    __ add(ToRegister(result), ToRegister(left), Operand(right_reg), set_cond);
 
1406
  } else {
 
1407
    ASSERT(right->IsRegister() || right->IsConstantOperand());
 
1408
    __ add(ToRegister(result), ToRegister(left), ToOperand(right), set_cond);
 
1409
  }
 
1410
 
 
1411
  if (can_overflow) {
1228
1412
    DeoptimizeIf(vs, instr->environment());
1229
1413
  }
1230
1414
}
1233
1417
void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
1234
1418
  DoubleRegister left = ToDoubleRegister(instr->InputAt(0));
1235
1419
  DoubleRegister right = ToDoubleRegister(instr->InputAt(1));
 
1420
  DoubleRegister result = ToDoubleRegister(instr->result());
1236
1421
  switch (instr->op()) {
1237
1422
    case Token::ADD:
1238
 
      __ vadd(left, left, right);
 
1423
      __ vadd(result, left, right);
1239
1424
      break;
1240
1425
    case Token::SUB:
1241
 
      __ vsub(left, left, right);
 
1426
      __ vsub(result, left, right);
1242
1427
      break;
1243
1428
    case Token::MUL:
1244
 
      __ vmul(left, left, right);
 
1429
      __ vmul(result, left, right);
1245
1430
      break;
1246
1431
    case Token::DIV:
1247
 
      __ vdiv(left, left, right);
 
1432
      __ vdiv(result, left, right);
1248
1433
      break;
1249
1434
    case Token::MOD: {
1250
1435
      // Save r0-r3 on the stack.
1251
1436
      __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
1252
1437
 
1253
 
      __ PrepareCallCFunction(4, scratch0());
1254
 
      __ vmov(r0, r1, left);
1255
 
      __ vmov(r2, r3, right);
1256
 
      __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
 
1438
      __ PrepareCallCFunction(0, 2, scratch0());
 
1439
      __ SetCallCDoubleArguments(left, right);
 
1440
      __ CallCFunction(
 
1441
          ExternalReference::double_fp_operation(Token::MOD, isolate()),
 
1442
          0, 2);
1257
1443
      // Move the result in the double result register.
1258
 
      __ GetCFunctionDoubleResult(ToDoubleRegister(instr->result()));
 
1444
      __ GetCFunctionDoubleResult(result);
1259
1445
 
1260
1446
      // Restore r0-r3.
1261
1447
      __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
1273
1459
  ASSERT(ToRegister(instr->InputAt(1)).is(r0));
1274
1460
  ASSERT(ToRegister(instr->result()).is(r0));
1275
1461
 
1276
 
  TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
 
1462
  BinaryOpStub stub(instr->op(), NO_OVERWRITE);
1277
1463
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 
1464
  __ nop();  // Signals no inlined code.
1278
1465
}
1279
1466
 
1280
1467
 
1309
1496
  int true_block = chunk_->LookupDestination(instr->true_block_id());
1310
1497
  int false_block = chunk_->LookupDestination(instr->false_block_id());
1311
1498
 
1312
 
  Representation r = instr->hydrogen()->representation();
 
1499
  Representation r = instr->hydrogen()->value()->representation();
1313
1500
  if (r.IsInteger32()) {
1314
1501
    Register reg = ToRegister(instr->InputAt(0));
1315
1502
    __ cmp(reg, Operand(0));
1321
1508
    // Test the double value. Zero and NaN are false.
1322
1509
    __ VFPCompareAndLoadFlags(reg, 0.0, scratch);
1323
1510
    __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit));
1324
 
    EmitBranch(true_block, false_block, ne);
 
1511
    EmitBranch(true_block, false_block, eq);
1325
1512
  } else {
1326
1513
    ASSERT(r.IsTagged());
1327
1514
    Register reg = ToRegister(instr->InputAt(0));
1328
 
    if (instr->hydrogen()->type().IsBoolean()) {
1329
 
      __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1330
 
      __ cmp(reg, ip);
 
1515
    HType type = instr->hydrogen()->value()->type();
 
1516
    if (type.IsBoolean()) {
 
1517
      __ CompareRoot(reg, Heap::kTrueValueRootIndex);
1331
1518
      EmitBranch(true_block, false_block, eq);
 
1519
    } else if (type.IsSmi()) {
 
1520
      __ cmp(reg, Operand(0));
 
1521
      EmitBranch(true_block, false_block, ne);
1332
1522
    } else {
1333
1523
      Label* true_label = chunk_->GetAssemblyLabel(true_block);
1334
1524
      Label* false_label = chunk_->GetAssemblyLabel(false_block);
1335
1525
 
1336
 
      __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1337
 
      __ cmp(reg, ip);
1338
 
      __ b(eq, false_label);
1339
 
      __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1340
 
      __ cmp(reg, ip);
1341
 
      __ b(eq, true_label);
1342
 
      __ LoadRoot(ip, Heap::kFalseValueRootIndex);
1343
 
      __ cmp(reg, ip);
1344
 
      __ b(eq, false_label);
1345
 
      __ cmp(reg, Operand(0));
1346
 
      __ b(eq, false_label);
1347
 
      __ tst(reg, Operand(kSmiTagMask));
1348
 
      __ b(eq, true_label);
1349
 
 
1350
 
      // Test double values. Zero and NaN are false.
1351
 
      Label call_stub;
1352
 
      DoubleRegister dbl_scratch = d0;
1353
 
      Register scratch = scratch0();
1354
 
      __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
1355
 
      __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
1356
 
      __ cmp(scratch, Operand(ip));
1357
 
      __ b(ne, &call_stub);
1358
 
      __ sub(ip, reg, Operand(kHeapObjectTag));
1359
 
      __ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
1360
 
      __ VFPCompareAndLoadFlags(dbl_scratch, 0.0, scratch);
1361
 
      __ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPVConditionFlagBit));
1362
 
      __ b(ne, false_label);
1363
 
      __ b(true_label);
1364
 
 
1365
 
      // The conversion stub doesn't cause garbage collections so it's
1366
 
      // safe to not record a safepoint after the call.
1367
 
      __ bind(&call_stub);
1368
 
      ToBooleanStub stub(reg);
1369
 
      RegList saved_regs = kJSCallerSaved | kCalleeSaved;
1370
 
      __ stm(db_w, sp, saved_regs);
1371
 
      __ CallStub(&stub);
1372
 
      __ cmp(reg, Operand(0));
1373
 
      __ ldm(ia_w, sp, saved_regs);
1374
 
      EmitBranch(true_block, false_block, ne);
 
1526
      ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
 
1527
      // Avoid deopts in the case where we've never executed this path before.
 
1528
      if (expected.IsEmpty()) expected = ToBooleanStub::all_types();
 
1529
 
 
1530
      if (expected.Contains(ToBooleanStub::UNDEFINED)) {
 
1531
        // undefined -> false.
 
1532
        __ CompareRoot(reg, Heap::kUndefinedValueRootIndex);
 
1533
        __ b(eq, false_label);
 
1534
      }
 
1535
      if (expected.Contains(ToBooleanStub::BOOLEAN)) {
 
1536
        // Boolean -> its value.
 
1537
        __ CompareRoot(reg, Heap::kTrueValueRootIndex);
 
1538
        __ b(eq, true_label);
 
1539
        __ CompareRoot(reg, Heap::kFalseValueRootIndex);
 
1540
        __ b(eq, false_label);
 
1541
      }
 
1542
      if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
 
1543
        // 'null' -> false.
 
1544
        __ CompareRoot(reg, Heap::kNullValueRootIndex);
 
1545
        __ b(eq, false_label);
 
1546
      }
 
1547
 
 
1548
      if (expected.Contains(ToBooleanStub::SMI)) {
 
1549
        // Smis: 0 -> false, all other -> true.
 
1550
        __ cmp(reg, Operand(0));
 
1551
        __ b(eq, false_label);
 
1552
        __ JumpIfSmi(reg, true_label);
 
1553
      } else if (expected.NeedsMap()) {
 
1554
        // If we need a map later and have a Smi -> deopt.
 
1555
        __ tst(reg, Operand(kSmiTagMask));
 
1556
        DeoptimizeIf(eq, instr->environment());
 
1557
      }
 
1558
 
 
1559
      const Register map = scratch0();
 
1560
      if (expected.NeedsMap()) {
 
1561
        __ ldr(map, FieldMemOperand(reg, HeapObject::kMapOffset));
 
1562
 
 
1563
        if (expected.CanBeUndetectable()) {
 
1564
          // Undetectable -> false.
 
1565
          __ ldrb(ip, FieldMemOperand(map, Map::kBitFieldOffset));
 
1566
          __ tst(ip, Operand(1 << Map::kIsUndetectable));
 
1567
          __ b(ne, false_label);
 
1568
        }
 
1569
      }
 
1570
 
 
1571
      if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
 
1572
        // spec object -> true.
 
1573
        __ CompareInstanceType(map, ip, FIRST_SPEC_OBJECT_TYPE);
 
1574
        __ b(ge, true_label);
 
1575
      }
 
1576
 
 
1577
      if (expected.Contains(ToBooleanStub::STRING)) {
 
1578
        // String value -> false iff empty.
 
1579
        Label not_string;
 
1580
        __ CompareInstanceType(map, ip, FIRST_NONSTRING_TYPE);
 
1581
        __ b(ge, &not_string);
 
1582
        __ ldr(ip, FieldMemOperand(reg, String::kLengthOffset));
 
1583
        __ cmp(ip, Operand(0));
 
1584
        __ b(ne, true_label);
 
1585
        __ b(false_label);
 
1586
        __ bind(&not_string);
 
1587
      }
 
1588
 
 
1589
      if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
 
1590
        // heap number -> false iff +0, -0, or NaN.
 
1591
        DoubleRegister dbl_scratch = double_scratch0();
 
1592
        Label not_heap_number;
 
1593
        __ CompareRoot(map, Heap::kHeapNumberMapRootIndex);
 
1594
        __ b(ne, &not_heap_number);
 
1595
        __ vldr(dbl_scratch, FieldMemOperand(reg, HeapNumber::kValueOffset));
 
1596
        __ VFPCompareAndSetFlags(dbl_scratch, 0.0);
 
1597
        __ b(vs, false_label);  // NaN -> false.
 
1598
        __ b(eq, false_label);  // +0, -0 -> false.
 
1599
        __ b(true_label);
 
1600
        __ bind(&not_heap_number);
 
1601
      }
 
1602
 
 
1603
      // We've seen something for the first time -> deopt.
 
1604
      DeoptimizeIf(al, instr->environment());
1375
1605
    }
1376
1606
  }
1377
1607
}
1378
1608
 
1379
1609
 
1380
 
void LCodeGen::EmitGoto(int block, LDeferredCode* deferred_stack_check) {
 
1610
void LCodeGen::EmitGoto(int block) {
1381
1611
  block = chunk_->LookupDestination(block);
1382
1612
  int next_block = GetNextEmittedBlock(current_block_);
1383
1613
  if (block != next_block) {
1384
 
    // Perform stack overflow check if this goto needs it before jumping.
1385
 
    if (deferred_stack_check != NULL) {
1386
 
      __ LoadRoot(ip, Heap::kStackLimitRootIndex);
1387
 
      __ cmp(sp, Operand(ip));
1388
 
      __ b(hs, chunk_->GetAssemblyLabel(block));
1389
 
      __ jmp(deferred_stack_check->entry());
1390
 
      deferred_stack_check->SetExit(chunk_->GetAssemblyLabel(block));
1391
 
    } else {
1392
 
      __ jmp(chunk_->GetAssemblyLabel(block));
1393
 
    }
 
1614
    __ jmp(chunk_->GetAssemblyLabel(block));
1394
1615
  }
1395
1616
}
1396
1617
 
1397
1618
 
1398
 
void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
1399
 
  PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
1400
 
  CallRuntimeFromDeferred(Runtime::kStackGuard, 0, instr);
1401
 
}
1402
 
 
1403
 
 
1404
1619
void LCodeGen::DoGoto(LGoto* instr) {
1405
 
  class DeferredStackCheck: public LDeferredCode {
1406
 
   public:
1407
 
    DeferredStackCheck(LCodeGen* codegen, LGoto* instr)
1408
 
        : LDeferredCode(codegen), instr_(instr) { }
1409
 
    virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
1410
 
   private:
1411
 
    LGoto* instr_;
1412
 
  };
1413
 
 
1414
 
  DeferredStackCheck* deferred = NULL;
1415
 
  if (instr->include_stack_check()) {
1416
 
    deferred = new DeferredStackCheck(this, instr);
1417
 
  }
1418
 
  EmitGoto(instr->block_id(), deferred);
 
1620
  EmitGoto(instr->block_id());
1419
1621
}
1420
1622
 
1421
1623
 
1452
1654
}
1453
1655
 
1454
1656
 
1455
 
void LCodeGen::DoCmpID(LCmpID* instr) {
1456
 
  LOperand* left = instr->InputAt(0);
1457
 
  LOperand* right = instr->InputAt(1);
1458
 
  LOperand* result = instr->result();
1459
 
  Register scratch = scratch0();
1460
 
 
1461
 
  Label unordered, done;
1462
 
  if (instr->is_double()) {
1463
 
    // Compare left and right as doubles and load the
1464
 
    // resulting flags into the normal status register.
1465
 
    __ VFPCompareAndSetFlags(ToDoubleRegister(left), ToDoubleRegister(right));
1466
 
    // If a NaN is involved, i.e. the result is unordered (V set),
1467
 
    // jump to unordered to return false.
1468
 
    __ b(vs, &unordered);
1469
 
  } else {
1470
 
    EmitCmpI(left, right);
1471
 
  }
1472
 
 
1473
 
  Condition cc = TokenToCondition(instr->op(), instr->is_double());
1474
 
  __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
1475
 
  __ b(cc, &done);
1476
 
 
1477
 
  __ bind(&unordered);
1478
 
  __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
1479
 
  __ bind(&done);
1480
 
}
1481
 
 
1482
 
 
1483
1657
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
1484
1658
  LOperand* left = instr->InputAt(0);
1485
1659
  LOperand* right = instr->InputAt(1);
1502
1676
}
1503
1677
 
1504
1678
 
1505
 
void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) {
1506
 
  Register left = ToRegister(instr->InputAt(0));
1507
 
  Register right = ToRegister(instr->InputAt(1));
1508
 
  Register result = ToRegister(instr->result());
1509
 
 
1510
 
  __ cmp(left, Operand(right));
1511
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
1512
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
1513
 
}
1514
 
 
1515
 
 
1516
 
void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
1517
 
  Register left = ToRegister(instr->InputAt(0));
1518
 
  Register right = ToRegister(instr->InputAt(1));
1519
 
  int false_block = chunk_->LookupDestination(instr->false_block_id());
1520
 
  int true_block = chunk_->LookupDestination(instr->true_block_id());
1521
 
 
1522
 
  __ cmp(left, Operand(right));
1523
 
  EmitBranch(true_block, false_block, eq);
1524
 
}
1525
 
 
1526
 
 
1527
 
void LCodeGen::DoIsNull(LIsNull* instr) {
1528
 
  Register reg = ToRegister(instr->InputAt(0));
1529
 
  Register result = ToRegister(instr->result());
1530
 
 
1531
 
  __ LoadRoot(ip, Heap::kNullValueRootIndex);
1532
 
  __ cmp(reg, ip);
1533
 
  if (instr->is_strict()) {
1534
 
    __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
1535
 
    __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
1536
 
  } else {
1537
 
    Label true_value, false_value, done;
1538
 
    __ b(eq, &true_value);
1539
 
    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1540
 
    __ cmp(ip, reg);
1541
 
    __ b(eq, &true_value);
1542
 
    __ tst(reg, Operand(kSmiTagMask));
1543
 
    __ b(eq, &false_value);
1544
 
    // Check for undetectable objects by looking in the bit field in
1545
 
    // the map. The object has already been smi checked.
1546
 
    Register scratch = result;
1547
 
    __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
1548
 
    __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
1549
 
    __ tst(scratch, Operand(1 << Map::kIsUndetectable));
1550
 
    __ b(ne, &true_value);
1551
 
    __ bind(&false_value);
1552
 
    __ LoadRoot(result, Heap::kFalseValueRootIndex);
1553
 
    __ jmp(&done);
1554
 
    __ bind(&true_value);
1555
 
    __ LoadRoot(result, Heap::kTrueValueRootIndex);
1556
 
    __ bind(&done);
1557
 
  }
 
1679
void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
 
1680
  Register left = ToRegister(instr->InputAt(0));
 
1681
  Register right = ToRegister(instr->InputAt(1));
 
1682
  int false_block = chunk_->LookupDestination(instr->false_block_id());
 
1683
  int true_block = chunk_->LookupDestination(instr->true_block_id());
 
1684
 
 
1685
  __ cmp(left, Operand(right));
 
1686
  EmitBranch(true_block, false_block, eq);
 
1687
}
 
1688
 
 
1689
 
 
1690
void LCodeGen::DoCmpConstantEqAndBranch(LCmpConstantEqAndBranch* instr) {
 
1691
  Register left = ToRegister(instr->InputAt(0));
 
1692
  int true_block = chunk_->LookupDestination(instr->true_block_id());
 
1693
  int false_block = chunk_->LookupDestination(instr->false_block_id());
 
1694
 
 
1695
  __ cmp(left, Operand(instr->hydrogen()->right()));
 
1696
  EmitBranch(true_block, false_block, eq);
1558
1697
}
1559
1698
 
1560
1699
 
1579
1718
    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1580
1719
    __ cmp(reg, ip);
1581
1720
    __ b(eq, true_label);
1582
 
    __ tst(reg, Operand(kSmiTagMask));
1583
 
    __ b(eq, false_label);
 
1721
    __ JumpIfSmi(reg, false_label);
1584
1722
    // Check for undetectable objects by looking in the bit field in
1585
1723
    // the map. The object has already been smi checked.
1586
1724
    __ ldr(scratch, FieldMemOperand(reg, HeapObject::kMapOffset));
1593
1731
 
1594
1732
Condition LCodeGen::EmitIsObject(Register input,
1595
1733
                                 Register temp1,
1596
 
                                 Register temp2,
1597
1734
                                 Label* is_not_object,
1598
1735
                                 Label* is_object) {
 
1736
  Register temp2 = scratch0();
1599
1737
  __ JumpIfSmi(input, is_not_object);
1600
1738
 
1601
 
  __ LoadRoot(temp1, Heap::kNullValueRootIndex);
1602
 
  __ cmp(input, temp1);
 
1739
  __ LoadRoot(temp2, Heap::kNullValueRootIndex);
 
1740
  __ cmp(input, temp2);
1603
1741
  __ b(eq, is_object);
1604
1742
 
1605
1743
  // Load map.
1611
1749
 
1612
1750
  // Load instance type and check that it is in object type range.
1613
1751
  __ ldrb(temp2, FieldMemOperand(temp1, Map::kInstanceTypeOffset));
1614
 
  __ cmp(temp2, Operand(FIRST_JS_OBJECT_TYPE));
 
1752
  __ cmp(temp2, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
1615
1753
  __ b(lt, is_not_object);
1616
 
  __ cmp(temp2, Operand(LAST_JS_OBJECT_TYPE));
 
1754
  __ cmp(temp2, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
1617
1755
  return le;
1618
1756
}
1619
1757
 
1620
1758
 
1621
 
void LCodeGen::DoIsObject(LIsObject* instr) {
1622
 
  Register reg = ToRegister(instr->InputAt(0));
1623
 
  Register result = ToRegister(instr->result());
1624
 
  Register temp = scratch0();
1625
 
  Label is_false, is_true, done;
1626
 
 
1627
 
  Condition true_cond = EmitIsObject(reg, result, temp, &is_false, &is_true);
1628
 
  __ b(true_cond, &is_true);
1629
 
 
1630
 
  __ bind(&is_false);
1631
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex);
1632
 
  __ b(&done);
1633
 
 
1634
 
  __ bind(&is_true);
1635
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex);
1636
 
 
1637
 
  __ bind(&done);
1638
 
}
1639
 
 
1640
 
 
1641
1759
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
1642
1760
  Register reg = ToRegister(instr->InputAt(0));
1643
1761
  Register temp1 = ToRegister(instr->TempAt(0));
1644
 
  Register temp2 = scratch0();
1645
1762
 
1646
1763
  int true_block = chunk_->LookupDestination(instr->true_block_id());
1647
1764
  int false_block = chunk_->LookupDestination(instr->false_block_id());
1649
1766
  Label* false_label = chunk_->GetAssemblyLabel(false_block);
1650
1767
 
1651
1768
  Condition true_cond =
1652
 
      EmitIsObject(reg, temp1, temp2, false_label, true_label);
 
1769
      EmitIsObject(reg, temp1, false_label, true_label);
1653
1770
 
1654
1771
  EmitBranch(true_block, false_block, true_cond);
1655
1772
}
1656
1773
 
1657
1774
 
1658
 
void LCodeGen::DoIsSmi(LIsSmi* instr) {
1659
 
  ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1660
 
  Register result = ToRegister(instr->result());
1661
 
  Register input_reg = EmitLoadRegister(instr->InputAt(0), ip);
1662
 
  __ tst(input_reg, Operand(kSmiTagMask));
1663
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex);
1664
 
  Label done;
1665
 
  __ b(eq, &done);
1666
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex);
1667
 
  __ bind(&done);
1668
 
}
1669
 
 
1670
 
 
1671
1775
void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
1672
1776
  int true_block = chunk_->LookupDestination(instr->true_block_id());
1673
1777
  int false_block = chunk_->LookupDestination(instr->false_block_id());
1678
1782
}
1679
1783
 
1680
1784
 
1681
 
static InstanceType TestType(HHasInstanceType* instr) {
 
1785
void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
 
1786
  Register input = ToRegister(instr->InputAt(0));
 
1787
  Register temp = ToRegister(instr->TempAt(0));
 
1788
 
 
1789
  int true_block = chunk_->LookupDestination(instr->true_block_id());
 
1790
  int false_block = chunk_->LookupDestination(instr->false_block_id());
 
1791
 
 
1792
  __ JumpIfSmi(input, chunk_->GetAssemblyLabel(false_block));
 
1793
  __ ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
 
1794
  __ ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
 
1795
  __ tst(temp, Operand(1 << Map::kIsUndetectable));
 
1796
  EmitBranch(true_block, false_block, ne);
 
1797
}
 
1798
 
 
1799
 
 
1800
static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
1682
1801
  InstanceType from = instr->from();
1683
1802
  InstanceType to = instr->to();
1684
1803
  if (from == FIRST_TYPE) return to;
1687
1806
}
1688
1807
 
1689
1808
 
1690
 
static Condition BranchCondition(HHasInstanceType* instr) {
 
1809
static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
1691
1810
  InstanceType from = instr->from();
1692
1811
  InstanceType to = instr->to();
1693
1812
  if (from == to) return eq;
1698
1817
}
1699
1818
 
1700
1819
 
1701
 
void LCodeGen::DoHasInstanceType(LHasInstanceType* instr) {
1702
 
  Register input = ToRegister(instr->InputAt(0));
1703
 
  Register result = ToRegister(instr->result());
1704
 
 
1705
 
  ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1706
 
  Label done;
1707
 
  __ tst(input, Operand(kSmiTagMask));
1708
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex, eq);
1709
 
  __ b(eq, &done);
1710
 
  __ CompareObjectType(input, result, result, TestType(instr->hydrogen()));
1711
 
  Condition cond = BranchCondition(instr->hydrogen());
1712
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex, cond);
1713
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex, NegateCondition(cond));
1714
 
  __ bind(&done);
1715
 
}
1716
 
 
1717
 
 
1718
1820
void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
1719
1821
  Register scratch = scratch0();
1720
1822
  Register input = ToRegister(instr->InputAt(0));
1724
1826
 
1725
1827
  Label* false_label = chunk_->GetAssemblyLabel(false_block);
1726
1828
 
1727
 
  __ tst(input, Operand(kSmiTagMask));
1728
 
  __ b(eq, false_label);
 
1829
  __ JumpIfSmi(input, false_label);
1729
1830
 
1730
1831
  __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
1731
1832
  EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
1735
1836
void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
1736
1837
  Register input = ToRegister(instr->InputAt(0));
1737
1838
  Register result = ToRegister(instr->result());
1738
 
  Register scratch = scratch0();
1739
 
 
1740
 
  __ ldr(scratch, FieldMemOperand(input, String::kHashFieldOffset));
1741
 
  __ IndexFromHash(scratch, result);
1742
 
}
1743
 
 
1744
 
 
1745
 
void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
1746
 
  Register input = ToRegister(instr->InputAt(0));
1747
 
  Register result = ToRegister(instr->result());
1748
 
  Register scratch = scratch0();
1749
 
 
1750
 
  ASSERT(instr->hydrogen()->value()->representation().IsTagged());
1751
 
  __ ldr(scratch,
1752
 
         FieldMemOperand(input, String::kHashFieldOffset));
1753
 
  __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
1754
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
1755
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
 
1839
 
 
1840
  if (FLAG_debug_code) {
 
1841
    __ AbortIfNotString(input);
 
1842
  }
 
1843
 
 
1844
  __ ldr(result, FieldMemOperand(input, String::kHashFieldOffset));
 
1845
  __ IndexFromHash(result, result);
1756
1846
}
1757
1847
 
1758
1848
 
1781
1871
                               Register temp2) {
1782
1872
  ASSERT(!input.is(temp));
1783
1873
  ASSERT(!temp.is(temp2));  // But input and temp2 may be the same register.
1784
 
  __ tst(input, Operand(kSmiTagMask));
1785
 
  __ b(eq, is_false);
1786
 
  __ CompareObjectType(input, temp, temp2, FIRST_JS_OBJECT_TYPE);
 
1874
  __ JumpIfSmi(input, is_false);
 
1875
  __ CompareObjectType(input, temp, temp2, FIRST_SPEC_OBJECT_TYPE);
1787
1876
  __ b(lt, is_false);
1788
1877
 
1789
1878
  // Map is now in temp.
1790
1879
  // Functions have class 'Function'.
1791
 
  __ CompareInstanceType(temp, temp2, JS_FUNCTION_TYPE);
 
1880
  __ CompareInstanceType(temp, temp2, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
1792
1881
  if (class_name->IsEqualTo(CStrVector("Function"))) {
1793
 
    __ b(eq, is_true);
 
1882
    __ b(ge, is_true);
1794
1883
  } else {
1795
 
    __ b(eq, is_false);
 
1884
    __ b(ge, is_false);
1796
1885
  }
1797
1886
 
1798
1887
  // Check if the constructor in the map is a function.
1799
1888
  __ ldr(temp, FieldMemOperand(temp, Map::kConstructorOffset));
1800
1889
 
1801
 
  // As long as JS_FUNCTION_TYPE is the last instance type and it is
1802
 
  // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
1803
 
  // LAST_JS_OBJECT_TYPE.
1804
 
  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1805
 
  ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
 
1890
  // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type and
 
1891
  // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
 
1892
  // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
 
1893
  STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
 
1894
  STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
 
1895
                LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
1806
1896
 
1807
1897
  // Objects with a non-function constructor have class 'Object'.
1808
1898
  __ CompareObjectType(temp, temp2, temp2, JS_FUNCTION_TYPE);
1828
1918
}
1829
1919
 
1830
1920
 
1831
 
void LCodeGen::DoClassOfTest(LClassOfTest* instr) {
1832
 
  Register input = ToRegister(instr->InputAt(0));
1833
 
  Register result = ToRegister(instr->result());
1834
 
  ASSERT(input.is(result));
1835
 
  Handle<String> class_name = instr->hydrogen()->class_name();
1836
 
 
1837
 
  Label done, is_true, is_false;
1838
 
 
1839
 
  EmitClassOfTest(&is_true, &is_false, class_name, input, scratch0(), input);
1840
 
  __ b(ne, &is_false);
1841
 
 
1842
 
  __ bind(&is_true);
1843
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex);
1844
 
  __ jmp(&done);
1845
 
 
1846
 
  __ bind(&is_false);
1847
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex);
1848
 
  __ bind(&done);
1849
 
}
1850
 
 
1851
 
 
1852
1921
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
1853
1922
  Register input = ToRegister(instr->InputAt(0));
1854
1923
  Register temp = scratch0();
1886
1955
  InstanceofStub stub(InstanceofStub::kArgsInRegisters);
1887
1956
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1888
1957
 
1889
 
  Label true_value, done;
1890
 
  __ tst(r0, r0);
1891
 
  __ mov(r0, Operand(Factory::false_value()), LeaveCC, ne);
1892
 
  __ mov(r0, Operand(Factory::true_value()), LeaveCC, eq);
1893
 
}
1894
 
 
1895
 
 
1896
 
void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
1897
 
  ASSERT(ToRegister(instr->InputAt(0)).is(r0));  // Object is in r0.
1898
 
  ASSERT(ToRegister(instr->InputAt(1)).is(r1));  // Function is in r1.
1899
 
 
1900
 
  int true_block = chunk_->LookupDestination(instr->true_block_id());
1901
 
  int false_block = chunk_->LookupDestination(instr->false_block_id());
1902
 
 
1903
 
  InstanceofStub stub(InstanceofStub::kArgsInRegisters);
1904
 
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
1905
 
  __ tst(r0, Operand(r0));
1906
 
  EmitBranch(true_block, false_block, eq);
 
1958
  __ cmp(r0, Operand(0));
 
1959
  __ mov(r0, Operand(factory()->false_value()), LeaveCC, ne);
 
1960
  __ mov(r0, Operand(factory()->true_value()), LeaveCC, eq);
1907
1961
}
1908
1962
 
1909
1963
 
1914
1968
                                  LInstanceOfKnownGlobal* instr)
1915
1969
        : LDeferredCode(codegen), instr_(instr) { }
1916
1970
    virtual void Generate() {
1917
 
      codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_);
 
1971
      codegen()->DoDeferredInstanceOfKnownGlobal(instr_, &map_check_);
1918
1972
    }
1919
1973
 
1920
1974
    Label* map_check() { return &map_check_; }
1948
2002
  // We use Factory::the_hole_value() on purpose instead of loading from the
1949
2003
  // root array to force relocation to be able to later patch with
1950
2004
  // the cached map.
1951
 
  __ mov(ip, Operand(Factory::the_hole_value()));
 
2005
  __ mov(ip, Operand(factory()->the_hole_value()));
1952
2006
  __ cmp(map, Operand(ip));
1953
2007
  __ b(ne, &cache_miss);
1954
2008
  // We use Factory::the_hole_value() on purpose instead of loading from the
1955
2009
  // root array to force relocation to be able to later patch
1956
2010
  // with true or false.
1957
 
  __ mov(result, Operand(Factory::the_hole_value()));
 
2011
  __ mov(result, Operand(factory()->the_hole_value()));
1958
2012
  __ b(&done);
1959
2013
 
1960
2014
  // The inlined call site cache did not match. Check null and string before
1982
2036
}
1983
2037
 
1984
2038
 
1985
 
void LCodeGen::DoDeferredLInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
1986
 
                                                Label* map_check) {
 
2039
void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr,
 
2040
                                               Label* map_check) {
1987
2041
  Register result = ToRegister(instr->result());
1988
2042
  ASSERT(result.is(r0));
1989
2043
 
2015
2069
                  RelocInfo::CODE_TARGET,
2016
2070
                  instr,
2017
2071
                  RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
 
2072
  ASSERT(instr->HasDeoptimizationEnvironment());
 
2073
  LEnvironment* env = instr->deoptimization_environment();
 
2074
  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
2018
2075
  // Put the result value into the result register slot and
2019
2076
  // restore all registers.
2020
2077
  __ StoreToSafepointRegisterSlot(result, result);
2061
2118
}
2062
2119
 
2063
2120
 
2064
 
void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
2065
 
  Token::Value op = instr->op();
2066
 
  int true_block = chunk_->LookupDestination(instr->true_block_id());
2067
 
  int false_block = chunk_->LookupDestination(instr->false_block_id());
2068
 
 
2069
 
  Handle<Code> ic = CompareIC::GetUninitialized(op);
2070
 
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2071
 
 
2072
 
  // The compare stub expects compare condition and the input operands
2073
 
  // reversed for GT and LTE.
2074
 
  Condition condition = ComputeCompareCondition(op);
2075
 
  if (op == Token::GT || op == Token::LTE) {
2076
 
    condition = ReverseCondition(condition);
2077
 
  }
2078
 
  __ cmp(r0, Operand(0));
2079
 
  EmitBranch(true_block, false_block, condition);
2080
 
}
2081
 
 
2082
 
 
2083
2121
void LCodeGen::DoReturn(LReturn* instr) {
2084
2122
  if (FLAG_trace) {
2085
2123
    // Push the return value on the stack as the parameter.
2087
2125
    __ push(r0);
2088
2126
    __ CallRuntime(Runtime::kTraceExit, 1);
2089
2127
  }
2090
 
  int32_t sp_delta = (ParameterCount() + 1) * kPointerSize;
 
2128
  int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize;
2091
2129
  __ mov(sp, fp);
2092
2130
  __ ldm(ia_w, sp, fp.bit() | lr.bit());
2093
2131
  __ add(sp, sp, Operand(sp_delta));
2095
2133
}
2096
2134
 
2097
2135
 
2098
 
void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
 
2136
void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
2099
2137
  Register result = ToRegister(instr->result());
2100
2138
  __ mov(ip, Operand(Handle<Object>(instr->hydrogen()->cell())));
2101
2139
  __ ldr(result, FieldMemOperand(ip, JSGlobalPropertyCell::kValueOffset));
2107
2145
}
2108
2146
 
2109
2147
 
2110
 
void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
 
2148
void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
 
2149
  ASSERT(ToRegister(instr->global_object()).is(r0));
 
2150
  ASSERT(ToRegister(instr->result()).is(r0));
 
2151
 
 
2152
  __ mov(r2, Operand(instr->name()));
 
2153
  RelocInfo::Mode mode = instr->for_typeof() ? RelocInfo::CODE_TARGET
 
2154
                                             : RelocInfo::CODE_TARGET_CONTEXT;
 
2155
  Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
 
2156
  CallCode(ic, mode, instr);
 
2157
}
 
2158
 
 
2159
 
 
2160
void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
2111
2161
  Register value = ToRegister(instr->InputAt(0));
2112
2162
  Register scratch = scratch0();
2113
2163
 
2132
2182
}
2133
2183
 
2134
2184
 
 
2185
void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) {
 
2186
  ASSERT(ToRegister(instr->global_object()).is(r1));
 
2187
  ASSERT(ToRegister(instr->value()).is(r0));
 
2188
 
 
2189
  __ mov(r2, Operand(instr->name()));
 
2190
  Handle<Code> ic = instr->strict_mode()
 
2191
      ? isolate()->builtins()->StoreIC_Initialize_Strict()
 
2192
      : isolate()->builtins()->StoreIC_Initialize();
 
2193
  CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
 
2194
}
 
2195
 
 
2196
 
2135
2197
void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
2136
2198
  Register context = ToRegister(instr->context());
2137
2199
  Register result = ToRegister(instr->result());
2162
2224
}
2163
2225
 
2164
2226
 
 
2227
void LCodeGen::EmitLoadFieldOrConstantFunction(Register result,
 
2228
                                               Register object,
 
2229
                                               Handle<Map> type,
 
2230
                                               Handle<String> name) {
 
2231
  LookupResult lookup;
 
2232
  type->LookupInDescriptors(NULL, *name, &lookup);
 
2233
  ASSERT(lookup.IsProperty() &&
 
2234
         (lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION));
 
2235
  if (lookup.type() == FIELD) {
 
2236
    int index = lookup.GetLocalFieldIndexFromMap(*type);
 
2237
    int offset = index * kPointerSize;
 
2238
    if (index < 0) {
 
2239
      // Negative property indices are in-object properties, indexed
 
2240
      // from the end of the fixed part of the object.
 
2241
      __ ldr(result, FieldMemOperand(object, offset + type->instance_size()));
 
2242
    } else {
 
2243
      // Non-negative property indices are in the properties array.
 
2244
      __ ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
 
2245
      __ ldr(result, FieldMemOperand(result, offset + FixedArray::kHeaderSize));
 
2246
    }
 
2247
  } else {
 
2248
    Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*type));
 
2249
    LoadHeapObject(result, Handle<HeapObject>::cast(function));
 
2250
  }
 
2251
}
 
2252
 
 
2253
 
 
2254
void LCodeGen::DoLoadNamedFieldPolymorphic(LLoadNamedFieldPolymorphic* instr) {
 
2255
  Register object = ToRegister(instr->object());
 
2256
  Register result = ToRegister(instr->result());
 
2257
  Register scratch = scratch0();
 
2258
  int map_count = instr->hydrogen()->types()->length();
 
2259
  Handle<String> name = instr->hydrogen()->name();
 
2260
  if (map_count == 0) {
 
2261
    ASSERT(instr->hydrogen()->need_generic());
 
2262
    __ mov(r2, Operand(name));
 
2263
    Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
 
2264
    CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
2265
  } else {
 
2266
    Label done;
 
2267
    __ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
 
2268
    for (int i = 0; i < map_count - 1; ++i) {
 
2269
      Handle<Map> map = instr->hydrogen()->types()->at(i);
 
2270
      Label next;
 
2271
      __ cmp(scratch, Operand(map));
 
2272
      __ b(ne, &next);
 
2273
      EmitLoadFieldOrConstantFunction(result, object, map, name);
 
2274
      __ b(&done);
 
2275
      __ bind(&next);
 
2276
    }
 
2277
    Handle<Map> map = instr->hydrogen()->types()->last();
 
2278
    __ cmp(scratch, Operand(map));
 
2279
    if (instr->hydrogen()->need_generic()) {
 
2280
      Label generic;
 
2281
      __ b(ne, &generic);
 
2282
      EmitLoadFieldOrConstantFunction(result, object, map, name);
 
2283
      __ b(&done);
 
2284
      __ bind(&generic);
 
2285
      __ mov(r2, Operand(name));
 
2286
      Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
 
2287
      CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
2288
    } else {
 
2289
      DeoptimizeIf(ne, instr->environment());
 
2290
      EmitLoadFieldOrConstantFunction(result, object, map, name);
 
2291
    }
 
2292
    __ bind(&done);
 
2293
  }
 
2294
}
 
2295
 
 
2296
 
2165
2297
void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
2166
2298
  ASSERT(ToRegister(instr->object()).is(r0));
2167
2299
  ASSERT(ToRegister(instr->result()).is(r0));
2168
2300
 
2169
2301
  // Name is always in r2.
2170
2302
  __ mov(r2, Operand(instr->name()));
2171
 
  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
 
2303
  Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
2172
2304
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2173
2305
}
2174
2306
 
2224
2356
 
2225
2357
  __ ldr(result, FieldMemOperand(input, JSObject::kElementsOffset));
2226
2358
  if (FLAG_debug_code) {
2227
 
    Label done;
 
2359
    Label done, fail;
2228
2360
    __ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
2229
2361
    __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
2230
2362
    __ cmp(scratch, ip);
2231
2363
    __ b(eq, &done);
2232
 
    __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
2233
 
    __ cmp(scratch, ip);
2234
 
    __ b(eq, &done);
2235
2364
    __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
2236
2365
    __ cmp(scratch, ip);
2237
 
    __ Check(eq, "Check for fast elements failed.");
 
2366
    __ b(eq, &done);
 
2367
    // |scratch| still contains |input|'s map.
 
2368
    __ ldr(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
 
2369
    __ ubfx(scratch, scratch, Map::kElementsKindShift,
 
2370
            Map::kElementsKindBitCount);
 
2371
    __ cmp(scratch, Operand(FAST_ELEMENTS));
 
2372
    __ b(eq, &done);
 
2373
    __ cmp(scratch, Operand(FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND));
 
2374
    __ b(lt, &fail);
 
2375
    __ cmp(scratch, Operand(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND));
 
2376
    __ b(le, &done);
 
2377
    __ bind(&fail);
 
2378
    __ Abort("Check for fast or external elements failed.");
2238
2379
    __ bind(&done);
2239
2380
  }
2240
2381
}
2241
2382
 
2242
2383
 
2243
 
void LCodeGen::DoLoadPixelArrayExternalPointer(
2244
 
    LLoadPixelArrayExternalPointer* instr) {
 
2384
void LCodeGen::DoLoadExternalArrayPointer(
 
2385
    LLoadExternalArrayPointer* instr) {
2245
2386
  Register to_reg = ToRegister(instr->result());
2246
2387
  Register from_reg  = ToRegister(instr->InputAt(0));
2247
 
  __ ldr(to_reg, FieldMemOperand(from_reg, PixelArray::kExternalPointerOffset));
 
2388
  __ ldr(to_reg, FieldMemOperand(from_reg,
 
2389
                                 ExternalArray::kExternalPointerOffset));
2248
2390
}
2249
2391
 
2250
2392
 
2271
2413
  Register key = EmitLoadRegister(instr->key(), scratch0());
2272
2414
  Register result = ToRegister(instr->result());
2273
2415
  Register scratch = scratch0();
2274
 
  ASSERT(result.is(elements));
2275
2416
 
2276
2417
  // Load the result.
2277
2418
  __ add(scratch, elements, Operand(key, LSL, kPointerSizeLog2));
2278
2419
  __ ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize));
2279
2420
 
2280
2421
  // Check for the hole value.
2281
 
  __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
2282
 
  __ cmp(result, scratch);
2283
 
  DeoptimizeIf(eq, instr->environment());
2284
 
}
2285
 
 
2286
 
 
2287
 
void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
2288
 
  Register external_elements = ToRegister(instr->external_pointer());
2289
 
  Register key = ToRegister(instr->key());
2290
 
  Register result = ToRegister(instr->result());
2291
 
 
2292
 
  // Load the result.
2293
 
  __ ldrb(result, MemOperand(external_elements, key));
 
2422
  if (instr->hydrogen()->RequiresHoleCheck()) {
 
2423
    __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex);
 
2424
    __ cmp(result, scratch);
 
2425
    DeoptimizeIf(eq, instr->environment());
 
2426
  }
 
2427
}
 
2428
 
 
2429
 
 
2430
void LCodeGen::DoLoadKeyedFastDoubleElement(
 
2431
    LLoadKeyedFastDoubleElement* instr) {
 
2432
  Register elements = ToRegister(instr->elements());
 
2433
  bool key_is_constant = instr->key()->IsConstantOperand();
 
2434
  Register key = no_reg;
 
2435
  DwVfpRegister result = ToDoubleRegister(instr->result());
 
2436
  Register scratch = scratch0();
 
2437
 
 
2438
  int shift_size =
 
2439
      ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
 
2440
  int constant_key = 0;
 
2441
  if (key_is_constant) {
 
2442
    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
 
2443
    if (constant_key & 0xF0000000) {
 
2444
      Abort("array index constant value too big.");
 
2445
    }
 
2446
  } else {
 
2447
    key = ToRegister(instr->key());
 
2448
  }
 
2449
 
 
2450
  Operand operand = key_is_constant
 
2451
      ? Operand(constant_key * (1 << shift_size) +
 
2452
                FixedDoubleArray::kHeaderSize - kHeapObjectTag)
 
2453
      : Operand(key, LSL, shift_size);
 
2454
  __ add(elements, elements, operand);
 
2455
  if (!key_is_constant) {
 
2456
    __ add(elements, elements,
 
2457
           Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
 
2458
  }
 
2459
 
 
2460
  if (instr->hydrogen()->RequiresHoleCheck()) {
 
2461
    // TODO(danno): If no hole check is required, there is no need to allocate
 
2462
    // elements into a temporary register, instead scratch can be used.
 
2463
    __ ldr(scratch, MemOperand(elements, sizeof(kHoleNanLower32)));
 
2464
    __ cmp(scratch, Operand(kHoleNanUpper32));
 
2465
    DeoptimizeIf(eq, instr->environment());
 
2466
  }
 
2467
 
 
2468
  __ vldr(result, elements, 0);
 
2469
}
 
2470
 
 
2471
 
 
2472
void LCodeGen::DoLoadKeyedSpecializedArrayElement(
 
2473
    LLoadKeyedSpecializedArrayElement* instr) {
 
2474
  Register external_pointer = ToRegister(instr->external_pointer());
 
2475
  Register key = no_reg;
 
2476
  ElementsKind elements_kind = instr->elements_kind();
 
2477
  bool key_is_constant = instr->key()->IsConstantOperand();
 
2478
  int constant_key = 0;
 
2479
  if (key_is_constant) {
 
2480
    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
 
2481
    if (constant_key & 0xF0000000) {
 
2482
      Abort("array index constant value too big.");
 
2483
    }
 
2484
  } else {
 
2485
    key = ToRegister(instr->key());
 
2486
  }
 
2487
  int shift_size = ElementsKindToShiftSize(elements_kind);
 
2488
 
 
2489
  if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
 
2490
      elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
 
2491
    CpuFeatures::Scope scope(VFP3);
 
2492
    DwVfpRegister result = ToDoubleRegister(instr->result());
 
2493
    Operand operand = key_is_constant
 
2494
        ? Operand(constant_key * (1 << shift_size))
 
2495
        : Operand(key, LSL, shift_size);
 
2496
    __ add(scratch0(), external_pointer, operand);
 
2497
    if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
 
2498
      __ vldr(result.low(), scratch0(), 0);
 
2499
      __ vcvt_f64_f32(result, result.low());
 
2500
    } else  {  // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
 
2501
      __ vldr(result, scratch0(), 0);
 
2502
    }
 
2503
  } else {
 
2504
    Register result = ToRegister(instr->result());
 
2505
    MemOperand mem_operand(key_is_constant
 
2506
        ? MemOperand(external_pointer, constant_key * (1 << shift_size))
 
2507
        : MemOperand(external_pointer, key, LSL, shift_size));
 
2508
    switch (elements_kind) {
 
2509
      case EXTERNAL_BYTE_ELEMENTS:
 
2510
        __ ldrsb(result, mem_operand);
 
2511
        break;
 
2512
      case EXTERNAL_PIXEL_ELEMENTS:
 
2513
      case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
 
2514
        __ ldrb(result, mem_operand);
 
2515
        break;
 
2516
      case EXTERNAL_SHORT_ELEMENTS:
 
2517
        __ ldrsh(result, mem_operand);
 
2518
        break;
 
2519
      case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
 
2520
        __ ldrh(result, mem_operand);
 
2521
        break;
 
2522
      case EXTERNAL_INT_ELEMENTS:
 
2523
        __ ldr(result, mem_operand);
 
2524
        break;
 
2525
      case EXTERNAL_UNSIGNED_INT_ELEMENTS:
 
2526
        __ ldr(result, mem_operand);
 
2527
        __ cmp(result, Operand(0x80000000));
 
2528
        // TODO(danno): we could be more clever here, perhaps having a special
 
2529
        // version of the stub that detects if the overflow case actually
 
2530
        // happens, and generate code that returns a double rather than int.
 
2531
        DeoptimizeIf(cs, instr->environment());
 
2532
        break;
 
2533
      case EXTERNAL_FLOAT_ELEMENTS:
 
2534
      case EXTERNAL_DOUBLE_ELEMENTS:
 
2535
      case FAST_DOUBLE_ELEMENTS:
 
2536
      case FAST_ELEMENTS:
 
2537
      case DICTIONARY_ELEMENTS:
 
2538
      case NON_STRICT_ARGUMENTS_ELEMENTS:
 
2539
        UNREACHABLE();
 
2540
        break;
 
2541
    }
 
2542
  }
2294
2543
}
2295
2544
 
2296
2545
 
2298
2547
  ASSERT(ToRegister(instr->object()).is(r1));
2299
2548
  ASSERT(ToRegister(instr->key()).is(r0));
2300
2549
 
2301
 
  Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
 
2550
  Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
2302
2551
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2303
2552
}
2304
2553
 
2352
2601
  ASSERT(function.is(r1));  // Required by InvokeFunction.
2353
2602
  ASSERT(ToRegister(instr->result()).is(r0));
2354
2603
 
2355
 
  // If the receiver is null or undefined, we have to pass the global object
2356
 
  // as a receiver.
 
2604
  // If the receiver is null or undefined, we have to pass the global
 
2605
  // object as a receiver to normal functions. Values have to be
 
2606
  // passed unchanged to builtins and strict-mode functions.
2357
2607
  Label global_object, receiver_ok;
 
2608
 
 
2609
  // Do not transform the receiver to object for strict mode
 
2610
  // functions.
 
2611
  __ ldr(scratch,
 
2612
         FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
 
2613
  __ ldr(scratch,
 
2614
         FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
 
2615
  __ tst(scratch,
 
2616
         Operand(1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize)));
 
2617
  __ b(ne, &receiver_ok);
 
2618
 
 
2619
  // Do not transform the receiver to object for builtins.
 
2620
  __ tst(scratch, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
 
2621
  __ b(ne, &receiver_ok);
 
2622
 
 
2623
  // Normal function. Replace undefined or null with global receiver.
2358
2624
  __ LoadRoot(scratch, Heap::kNullValueRootIndex);
2359
2625
  __ cmp(receiver, scratch);
2360
2626
  __ b(eq, &global_object);
2365
2631
  // Deoptimize if the receiver is not a JS object.
2366
2632
  __ tst(receiver, Operand(kSmiTagMask));
2367
2633
  DeoptimizeIf(eq, instr->environment());
2368
 
  __ CompareObjectType(receiver, scratch, scratch, FIRST_JS_OBJECT_TYPE);
2369
 
  DeoptimizeIf(lo, instr->environment());
 
2634
  __ CompareObjectType(receiver, scratch, scratch, FIRST_SPEC_OBJECT_TYPE);
 
2635
  DeoptimizeIf(lt, instr->environment());
2370
2636
  __ jmp(&receiver_ok);
2371
2637
 
2372
2638
  __ bind(&global_object);
2373
2639
  __ ldr(receiver, GlobalObjectOperand());
 
2640
  __ ldr(receiver,
 
2641
         FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
2374
2642
  __ bind(&receiver_ok);
2375
2643
 
2376
2644
  // Copy the arguments to this function possibly from the
2390
2658
  // stack.
2391
2659
  Label invoke, loop;
2392
2660
  // length is a small non-negative integer, due to the test above.
2393
 
  __ tst(length, Operand(length));
 
2661
  __ cmp(length, Operand(0));
2394
2662
  __ b(eq, &invoke);
2395
2663
  __ bind(&loop);
2396
2664
  __ ldr(scratch, MemOperand(elements, length, LSL, 2));
2401
2669
  __ bind(&invoke);
2402
2670
  ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
2403
2671
  LPointerMap* pointers = instr->pointer_map();
2404
 
  LEnvironment* env = instr->deoptimization_environment();
2405
2672
  RecordPosition(pointers->position());
2406
 
  RegisterEnvironmentForDeoptimization(env);
2407
 
  SafepointGenerator safepoint_generator(this,
2408
 
                                         pointers,
2409
 
                                         env->deoptimization_index());
 
2673
  SafepointGenerator safepoint_generator(
 
2674
      this, pointers, Safepoint::kLazyDeopt);
2410
2675
  // The number of arguments is stored in receiver which is r0, as expected
2411
2676
  // by InvokeFunction.
2412
2677
  v8::internal::ParameterCount actual(receiver);
2413
 
  __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
 
2678
  __ InvokeFunction(function, actual, CALL_FUNCTION,
 
2679
                    safepoint_generator, CALL_AS_METHOD);
2414
2680
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2415
2681
}
2416
2682
 
2426
2692
}
2427
2693
 
2428
2694
 
 
2695
void LCodeGen::DoThisFunction(LThisFunction* instr) {
 
2696
  Register result = ToRegister(instr->result());
 
2697
  __ ldr(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
 
2698
}
 
2699
 
 
2700
 
2429
2701
void LCodeGen::DoContext(LContext* instr) {
2430
2702
  Register result = ToRegister(instr->result());
2431
2703
  __ mov(result, cp);
2436
2708
  Register context = ToRegister(instr->context());
2437
2709
  Register result = ToRegister(instr->result());
2438
2710
  __ ldr(result,
2439
 
         MemOperand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
2440
 
  __ ldr(result, FieldMemOperand(result, JSFunction::kContextOffset));
 
2711
         MemOperand(context, Context::SlotOffset(Context::PREVIOUS_INDEX)));
2441
2712
}
2442
2713
 
2443
2714
 
2444
2715
void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
2445
 
  Register context = ToRegister(instr->context());
2446
2716
  Register result = ToRegister(instr->result());
2447
2717
  __ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX));
2448
2718
}
2457
2727
 
2458
2728
void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
2459
2729
                                 int arity,
2460
 
                                 LInstruction* instr) {
 
2730
                                 LInstruction* instr,
 
2731
                                 CallKind call_kind) {
2461
2732
  // Change context if needed.
2462
2733
  bool change_context =
2463
 
      (graph()->info()->closure()->context() != function->context()) ||
 
2734
      (info()->closure()->context() != function->context()) ||
2464
2735
      scope()->contains_with() ||
2465
2736
      (scope()->num_heap_slots() > 0);
2466
2737
  if (change_context) {
2477
2748
  RecordPosition(pointers->position());
2478
2749
 
2479
2750
  // Invoke function.
 
2751
  __ SetCallKind(r5, call_kind);
2480
2752
  __ ldr(ip, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
2481
2753
  __ Call(ip);
2482
2754
 
2483
2755
  // Setup deoptimization.
2484
 
  RegisterLazyDeoptimization(instr, RECORD_SIMPLE_SAFEPOINT);
 
2756
  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
2485
2757
 
2486
2758
  // Restore context.
2487
2759
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2491
2763
void LCodeGen::DoCallConstantFunction(LCallConstantFunction* instr) {
2492
2764
  ASSERT(ToRegister(instr->result()).is(r0));
2493
2765
  __ mov(r1, Operand(instr->function()));
2494
 
  CallKnownFunction(instr->function(), instr->arity(), instr);
 
2766
  CallKnownFunction(instr->function(),
 
2767
                    instr->arity(),
 
2768
                    instr,
 
2769
                    CALL_AS_METHOD);
2495
2770
}
2496
2771
 
2497
2772
 
2498
2773
void LCodeGen::DoDeferredMathAbsTaggedHeapNumber(LUnaryMathOperation* instr) {
2499
 
  ASSERT(instr->InputAt(0)->Equals(instr->result()));
2500
2774
  Register input = ToRegister(instr->InputAt(0));
 
2775
  Register result = ToRegister(instr->result());
2501
2776
  Register scratch = scratch0();
2502
2777
 
2503
2778
  // Deoptimize if not a heap number.
2511
2786
  scratch = no_reg;
2512
2787
  __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
2513
2788
  // Check the sign of the argument. If the argument is positive, just
2514
 
  // return it. We do not need to patch the stack since |input| and
2515
 
  // |result| are the same register and |input| would be restored
2516
 
  // unchanged by popping safepoint registers.
 
2789
  // return it.
2517
2790
  __ tst(exponent, Operand(HeapNumber::kSignMask));
 
2791
  // Move the input to the result if necessary.
 
2792
  __ Move(result, input);
2518
2793
  __ b(eq, &done);
2519
2794
 
2520
2795
  // Input is negative. Reverse its sign.
2554
2829
    __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
2555
2830
    __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
2556
2831
 
2557
 
    __ StoreToSafepointRegisterSlot(tmp1, input);
 
2832
    __ StoreToSafepointRegisterSlot(tmp1, result);
2558
2833
  }
2559
2834
 
2560
2835
  __ bind(&done);
2563
2838
 
2564
2839
void LCodeGen::EmitIntegerMathAbs(LUnaryMathOperation* instr) {
2565
2840
  Register input = ToRegister(instr->InputAt(0));
 
2841
  Register result = ToRegister(instr->result());
2566
2842
  __ cmp(input, Operand(0));
 
2843
  __ Move(result, input, pl);
2567
2844
  // We can make rsb conditional because the previous cmp instruction
2568
2845
  // will clear the V (overflow) flag and rsb won't set this flag
2569
2846
  // if input is positive.
2570
 
  __ rsb(input, input, Operand(0), SetCC, mi);
 
2847
  __ rsb(result, input, Operand(0), SetCC, mi);
2571
2848
  // Deoptimize on overflow.
2572
2849
  DeoptimizeIf(vs, instr->environment());
2573
2850
}
2587
2864
    LUnaryMathOperation* instr_;
2588
2865
  };
2589
2866
 
2590
 
  ASSERT(instr->InputAt(0)->Equals(instr->result()));
2591
2867
  Representation r = instr->hydrogen()->value()->representation();
2592
2868
  if (r.IsDouble()) {
2593
2869
    DwVfpRegister input = ToDoubleRegister(instr->InputAt(0));
2594
 
    __ vabs(input, input);
 
2870
    DwVfpRegister result = ToDoubleRegister(instr->result());
 
2871
    __ vabs(result, input);
2595
2872
  } else if (r.IsInteger32()) {
2596
2873
    EmitIntegerMathAbs(instr);
2597
2874
  } else {
2625
2902
  // Move the result back to general purpose register r0.
2626
2903
  __ vmov(result, single_scratch);
2627
2904
 
2628
 
  // Test for -0.
2629
 
  Label done;
2630
 
  __ cmp(result, Operand(0));
2631
 
  __ b(ne, &done);
2632
 
  __ vmov(scratch1, input.high());
2633
 
  __ tst(scratch1, Operand(HeapNumber::kSignMask));
2634
 
  DeoptimizeIf(ne, instr->environment());
2635
 
  __ bind(&done);
 
2905
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
 
2906
    // Test for -0.
 
2907
    Label done;
 
2908
    __ cmp(result, Operand(0));
 
2909
    __ b(ne, &done);
 
2910
    __ vmov(scratch1, input.high());
 
2911
    __ tst(scratch1, Operand(HeapNumber::kSignMask));
 
2912
    DeoptimizeIf(ne, instr->environment());
 
2913
    __ bind(&done);
 
2914
  }
2636
2915
}
2637
2916
 
2638
2917
 
2639
2918
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
2640
2919
  DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
2641
2920
  Register result = ToRegister(instr->result());
2642
 
  Register scratch1 = scratch0();
2643
 
  Register scratch2 = result;
2644
 
  __ EmitVFPTruncate(kRoundToNearest,
 
2921
  Register scratch = scratch0();
 
2922
  Label done, check_sign_on_zero;
 
2923
 
 
2924
  // Extract exponent bits.
 
2925
  __ vmov(result, input.high());
 
2926
  __ ubfx(scratch,
 
2927
          result,
 
2928
          HeapNumber::kExponentShift,
 
2929
          HeapNumber::kExponentBits);
 
2930
 
 
2931
  // If the number is in ]-0.5, +0.5[, the result is +/- 0.
 
2932
  __ cmp(scratch, Operand(HeapNumber::kExponentBias - 2));
 
2933
  __ mov(result, Operand(0), LeaveCC, le);
 
2934
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
 
2935
    __ b(le, &check_sign_on_zero);
 
2936
  } else {
 
2937
    __ b(le, &done);
 
2938
  }
 
2939
 
 
2940
  // The following conversion will not work with numbers
 
2941
  // outside of ]-2^32, 2^32[.
 
2942
  __ cmp(scratch, Operand(HeapNumber::kExponentBias + 32));
 
2943
  DeoptimizeIf(ge, instr->environment());
 
2944
 
 
2945
  // Save the original sign for later comparison.
 
2946
  __ and_(scratch, result, Operand(HeapNumber::kSignMask));
 
2947
 
 
2948
  __ Vmov(double_scratch0(), 0.5);
 
2949
  __ vadd(double_scratch0(), input, double_scratch0());
 
2950
 
 
2951
  // Check sign of the result: if the sign changed, the input
 
2952
  // value was in ]0.5, 0[ and the result should be -0.
 
2953
  __ vmov(result, double_scratch0().high());
 
2954
  __ eor(result, result, Operand(scratch), SetCC);
 
2955
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
 
2956
    DeoptimizeIf(mi, instr->environment());
 
2957
  } else {
 
2958
    __ mov(result, Operand(0), LeaveCC, mi);
 
2959
    __ b(mi, &done);
 
2960
  }
 
2961
 
 
2962
  __ EmitVFPTruncate(kRoundToMinusInf,
2645
2963
                     double_scratch0().low(),
2646
 
                     input,
2647
 
                     scratch1,
2648
 
                     scratch2);
 
2964
                     double_scratch0(),
 
2965
                     result,
 
2966
                     scratch);
2649
2967
  DeoptimizeIf(ne, instr->environment());
2650
2968
  __ vmov(result, double_scratch0().low());
2651
2969
 
2652
 
  // Test for -0.
2653
 
  Label done;
2654
 
  __ cmp(result, Operand(0));
2655
 
  __ b(ne, &done);
2656
 
  __ vmov(scratch1, input.high());
2657
 
  __ tst(scratch1, Operand(HeapNumber::kSignMask));
2658
 
  DeoptimizeIf(ne, instr->environment());
 
2970
  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
 
2971
    // Test for -0.
 
2972
    __ cmp(result, Operand(0));
 
2973
    __ b(ne, &done);
 
2974
    __ bind(&check_sign_on_zero);
 
2975
    __ vmov(scratch, input.high());
 
2976
    __ tst(scratch, Operand(HeapNumber::kSignMask));
 
2977
    DeoptimizeIf(ne, instr->environment());
 
2978
  }
2659
2979
  __ bind(&done);
2660
2980
}
2661
2981
 
2662
2982
 
2663
2983
void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
2664
2984
  DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
2665
 
  ASSERT(ToDoubleRegister(instr->result()).is(input));
2666
 
  __ vsqrt(input, input);
 
2985
  DoubleRegister result = ToDoubleRegister(instr->result());
 
2986
  __ vsqrt(result, input);
 
2987
}
 
2988
 
 
2989
 
 
2990
void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
 
2991
  DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
 
2992
  DoubleRegister result = ToDoubleRegister(instr->result());
 
2993
  // Add +0 to convert -0 to +0.
 
2994
  __ vadd(result, input, kDoubleRegZero);
 
2995
  __ vsqrt(result, result);
2667
2996
}
2668
2997
 
2669
2998
 
2675
3004
  Representation exponent_type = instr->hydrogen()->right()->representation();
2676
3005
  if (exponent_type.IsDouble()) {
2677
3006
    // Prepare arguments and call C function.
2678
 
    __ PrepareCallCFunction(4, scratch);
2679
 
    __ vmov(r0, r1, ToDoubleRegister(left));
2680
 
    __ vmov(r2, r3, ToDoubleRegister(right));
2681
 
    __ CallCFunction(ExternalReference::power_double_double_function(), 4);
 
3007
    __ PrepareCallCFunction(0, 2, scratch);
 
3008
    __ SetCallCDoubleArguments(ToDoubleRegister(left),
 
3009
                               ToDoubleRegister(right));
 
3010
    __ CallCFunction(
 
3011
        ExternalReference::power_double_double_function(isolate()), 0, 2);
2682
3012
  } else if (exponent_type.IsInteger32()) {
2683
3013
    ASSERT(ToRegister(right).is(r0));
2684
3014
    // Prepare arguments and call C function.
2685
 
    __ PrepareCallCFunction(4, scratch);
2686
 
    __ mov(r2, ToRegister(right));
2687
 
    __ vmov(r0, r1, ToDoubleRegister(left));
2688
 
    __ CallCFunction(ExternalReference::power_double_int_function(), 4);
 
3015
    __ PrepareCallCFunction(1, 1, scratch);
 
3016
    __ SetCallCDoubleArguments(ToDoubleRegister(left), ToRegister(right));
 
3017
    __ CallCFunction(
 
3018
        ExternalReference::power_double_int_function(isolate()), 1, 1);
2689
3019
  } else {
2690
3020
    ASSERT(exponent_type.IsTagged());
2691
3021
    ASSERT(instr->hydrogen()->left()->representation().IsDouble());
2715
3045
 
2716
3046
    // Prepare arguments and call C function.
2717
3047
    __ bind(&call);
2718
 
    __ PrepareCallCFunction(4, scratch);
2719
 
    __ vmov(r0, r1, ToDoubleRegister(left));
2720
 
    __ vmov(r2, r3, result_reg);
2721
 
    __ CallCFunction(ExternalReference::power_double_double_function(), 4);
 
3048
    __ PrepareCallCFunction(0, 2, scratch);
 
3049
    __ SetCallCDoubleArguments(ToDoubleRegister(left), result_reg);
 
3050
    __ CallCFunction(
 
3051
        ExternalReference::power_double_double_function(isolate()), 0, 2);
2722
3052
  }
2723
3053
  // Store the result in the result register.
2724
3054
  __ GetCFunctionDoubleResult(result_reg);
2725
3055
}
2726
3056
 
2727
3057
 
 
3058
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
 
3059
  ASSERT(ToDoubleRegister(instr->result()).is(d2));
 
3060
  TranscendentalCacheStub stub(TranscendentalCache::LOG,
 
3061
                               TranscendentalCacheStub::UNTAGGED);
 
3062
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 
3063
}
 
3064
 
 
3065
 
 
3066
void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
 
3067
  ASSERT(ToDoubleRegister(instr->result()).is(d2));
 
3068
  TranscendentalCacheStub stub(TranscendentalCache::COS,
 
3069
                               TranscendentalCacheStub::UNTAGGED);
 
3070
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 
3071
}
 
3072
 
 
3073
 
 
3074
void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
 
3075
  ASSERT(ToDoubleRegister(instr->result()).is(d2));
 
3076
  TranscendentalCacheStub stub(TranscendentalCache::SIN,
 
3077
                               TranscendentalCacheStub::UNTAGGED);
 
3078
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 
3079
}
 
3080
 
 
3081
 
2728
3082
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
2729
3083
  switch (instr->op()) {
2730
3084
    case kMathAbs:
2739
3093
    case kMathSqrt:
2740
3094
      DoMathSqrt(instr);
2741
3095
      break;
 
3096
    case kMathPowHalf:
 
3097
      DoMathPowHalf(instr);
 
3098
      break;
 
3099
    case kMathCos:
 
3100
      DoMathCos(instr);
 
3101
      break;
 
3102
    case kMathSin:
 
3103
      DoMathSin(instr);
 
3104
      break;
 
3105
    case kMathLog:
 
3106
      DoMathLog(instr);
 
3107
      break;
2742
3108
    default:
2743
3109
      Abort("Unimplemented type of LUnaryMathOperation.");
2744
3110
      UNREACHABLE();
2746
3112
}
2747
3113
 
2748
3114
 
 
3115
void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
 
3116
  ASSERT(ToRegister(instr->function()).is(r1));
 
3117
  ASSERT(instr->HasPointerMap());
 
3118
  ASSERT(instr->HasDeoptimizationEnvironment());
 
3119
  LPointerMap* pointers = instr->pointer_map();
 
3120
  RecordPosition(pointers->position());
 
3121
  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
 
3122
  ParameterCount count(instr->arity());
 
3123
  __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
 
3124
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
 
3125
}
 
3126
 
 
3127
 
2749
3128
void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
2750
3129
  ASSERT(ToRegister(instr->result()).is(r0));
2751
3130
 
2752
3131
  int arity = instr->arity();
2753
 
  Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
 
3132
  Handle<Code> ic =
 
3133
      isolate()->stub_cache()->ComputeKeyedCallInitialize(arity);
2754
3134
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2755
3135
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2756
3136
}
2760
3140
  ASSERT(ToRegister(instr->result()).is(r0));
2761
3141
 
2762
3142
  int arity = instr->arity();
2763
 
  Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
 
3143
  RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
 
3144
  Handle<Code> ic =
 
3145
      isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
2764
3146
  __ mov(r2, Operand(instr->name()));
2765
 
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
 
3147
  CallCode(ic, mode, instr);
2766
3148
  // Restore context register.
2767
3149
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2768
3150
}
2772
3154
  ASSERT(ToRegister(instr->result()).is(r0));
2773
3155
 
2774
3156
  int arity = instr->arity();
2775
 
  CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
 
3157
  CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT);
2776
3158
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
2777
3159
  __ Drop(1);
2778
3160
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2783
3165
  ASSERT(ToRegister(instr->result()).is(r0));
2784
3166
 
2785
3167
  int arity = instr->arity();
2786
 
  Handle<Code> ic = StubCache::ComputeCallInitialize(arity, NOT_IN_LOOP);
 
3168
  RelocInfo::Mode mode = RelocInfo::CODE_TARGET_CONTEXT;
 
3169
  Handle<Code> ic =
 
3170
      isolate()->stub_cache()->ComputeCallInitialize(arity, mode);
2787
3171
  __ mov(r2, Operand(instr->name()));
2788
 
  CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
 
3172
  CallCode(ic, mode, instr);
2789
3173
  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2790
3174
}
2791
3175
 
2793
3177
void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
2794
3178
  ASSERT(ToRegister(instr->result()).is(r0));
2795
3179
  __ mov(r1, Operand(instr->target()));
2796
 
  CallKnownFunction(instr->target(), instr->arity(), instr);
 
3180
  CallKnownFunction(instr->target(), instr->arity(), instr, CALL_AS_FUNCTION);
2797
3181
}
2798
3182
 
2799
3183
 
2801
3185
  ASSERT(ToRegister(instr->InputAt(0)).is(r1));
2802
3186
  ASSERT(ToRegister(instr->result()).is(r0));
2803
3187
 
2804
 
  Handle<Code> builtin(Builtins::builtin(Builtins::JSConstructCall));
 
3188
  Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
2805
3189
  __ mov(r0, Operand(instr->arity()));
2806
3190
  CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
2807
3191
}
2850
3234
 
2851
3235
  // Name is always in r2.
2852
3236
  __ mov(r2, Operand(instr->name()));
2853
 
  Handle<Code> ic(Builtins::builtin(
2854
 
      info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
2855
 
                         : Builtins::StoreIC_Initialize));
 
3237
  Handle<Code> ic = instr->strict_mode()
 
3238
      ? isolate()->builtins()->StoreIC_Initialize_Strict()
 
3239
      : isolate()->builtins()->StoreIC_Initialize();
2856
3240
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2857
3241
}
2858
3242
 
2889
3273
}
2890
3274
 
2891
3275
 
 
3276
void LCodeGen::DoStoreKeyedFastDoubleElement(
 
3277
    LStoreKeyedFastDoubleElement* instr) {
 
3278
  DwVfpRegister value = ToDoubleRegister(instr->value());
 
3279
  Register elements = ToRegister(instr->elements());
 
3280
  Register key = no_reg;
 
3281
  Register scratch = scratch0();
 
3282
  bool key_is_constant = instr->key()->IsConstantOperand();
 
3283
  int constant_key = 0;
 
3284
  Label not_nan;
 
3285
 
 
3286
  // Calculate the effective address of the slot in the array to store the
 
3287
  // double value.
 
3288
  if (key_is_constant) {
 
3289
    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
 
3290
    if (constant_key & 0xF0000000) {
 
3291
      Abort("array index constant value too big.");
 
3292
    }
 
3293
  } else {
 
3294
    key = ToRegister(instr->key());
 
3295
  }
 
3296
  int shift_size = ElementsKindToShiftSize(FAST_DOUBLE_ELEMENTS);
 
3297
  Operand operand = key_is_constant
 
3298
      ? Operand(constant_key * (1 << shift_size) +
 
3299
                FixedDoubleArray::kHeaderSize - kHeapObjectTag)
 
3300
      : Operand(key, LSL, shift_size);
 
3301
  __ add(scratch, elements, operand);
 
3302
  if (!key_is_constant) {
 
3303
    __ add(scratch, scratch,
 
3304
           Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag));
 
3305
  }
 
3306
 
 
3307
  // Check for NaN. All NaNs must be canonicalized.
 
3308
  __ VFPCompareAndSetFlags(value, value);
 
3309
 
 
3310
  // Only load canonical NaN if the comparison above set the overflow.
 
3311
  __ Vmov(value, FixedDoubleArray::canonical_not_the_hole_nan_as_double(), vs);
 
3312
 
 
3313
  __ bind(&not_nan);
 
3314
  __ vstr(value, scratch, 0);
 
3315
}
 
3316
 
 
3317
 
 
3318
void LCodeGen::DoStoreKeyedSpecializedArrayElement(
 
3319
    LStoreKeyedSpecializedArrayElement* instr) {
 
3320
 
 
3321
  Register external_pointer = ToRegister(instr->external_pointer());
 
3322
  Register key = no_reg;
 
3323
  ElementsKind elements_kind = instr->elements_kind();
 
3324
  bool key_is_constant = instr->key()->IsConstantOperand();
 
3325
  int constant_key = 0;
 
3326
  if (key_is_constant) {
 
3327
    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
 
3328
    if (constant_key & 0xF0000000) {
 
3329
      Abort("array index constant value too big.");
 
3330
    }
 
3331
  } else {
 
3332
    key = ToRegister(instr->key());
 
3333
  }
 
3334
  int shift_size = ElementsKindToShiftSize(elements_kind);
 
3335
 
 
3336
  if (elements_kind == EXTERNAL_FLOAT_ELEMENTS ||
 
3337
      elements_kind == EXTERNAL_DOUBLE_ELEMENTS) {
 
3338
    CpuFeatures::Scope scope(VFP3);
 
3339
    DwVfpRegister value(ToDoubleRegister(instr->value()));
 
3340
    Operand operand(key_is_constant ? Operand(constant_key * (1 << shift_size))
 
3341
                                    : Operand(key, LSL, shift_size));
 
3342
    __ add(scratch0(), external_pointer, operand);
 
3343
    if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) {
 
3344
      __ vcvt_f32_f64(double_scratch0().low(), value);
 
3345
      __ vstr(double_scratch0().low(), scratch0(), 0);
 
3346
    } else {  // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS
 
3347
      __ vstr(value, scratch0(), 0);
 
3348
    }
 
3349
  } else {
 
3350
    Register value(ToRegister(instr->value()));
 
3351
    MemOperand mem_operand(key_is_constant
 
3352
        ? MemOperand(external_pointer, constant_key * (1 << shift_size))
 
3353
        : MemOperand(external_pointer, key, LSL, shift_size));
 
3354
    switch (elements_kind) {
 
3355
      case EXTERNAL_PIXEL_ELEMENTS:
 
3356
      case EXTERNAL_BYTE_ELEMENTS:
 
3357
      case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
 
3358
        __ strb(value, mem_operand);
 
3359
        break;
 
3360
      case EXTERNAL_SHORT_ELEMENTS:
 
3361
      case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
 
3362
        __ strh(value, mem_operand);
 
3363
        break;
 
3364
      case EXTERNAL_INT_ELEMENTS:
 
3365
      case EXTERNAL_UNSIGNED_INT_ELEMENTS:
 
3366
        __ str(value, mem_operand);
 
3367
        break;
 
3368
      case EXTERNAL_FLOAT_ELEMENTS:
 
3369
      case EXTERNAL_DOUBLE_ELEMENTS:
 
3370
      case FAST_DOUBLE_ELEMENTS:
 
3371
      case FAST_ELEMENTS:
 
3372
      case DICTIONARY_ELEMENTS:
 
3373
      case NON_STRICT_ARGUMENTS_ELEMENTS:
 
3374
        UNREACHABLE();
 
3375
        break;
 
3376
    }
 
3377
  }
 
3378
}
 
3379
 
 
3380
 
2892
3381
void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
2893
3382
  ASSERT(ToRegister(instr->object()).is(r2));
2894
3383
  ASSERT(ToRegister(instr->key()).is(r1));
2895
3384
  ASSERT(ToRegister(instr->value()).is(r0));
2896
3385
 
2897
 
  Handle<Code> ic(Builtins::builtin(
2898
 
      info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
2899
 
                         : Builtins::KeyedStoreIC_Initialize));
 
3386
  Handle<Code> ic = instr->strict_mode()
 
3387
      ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
 
3388
      : isolate()->builtins()->KeyedStoreIC_Initialize();
2900
3389
  CallCode(ic, RelocInfo::CODE_TARGET, instr);
2901
3390
}
2902
3391
 
2903
3392
 
 
3393
void LCodeGen::DoStringAdd(LStringAdd* instr) {
 
3394
  __ push(ToRegister(instr->left()));
 
3395
  __ push(ToRegister(instr->right()));
 
3396
  StringAddStub stub(NO_STRING_CHECK_IN_STUB);
 
3397
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 
3398
}
 
3399
 
 
3400
 
2904
3401
void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
2905
3402
  class DeferredStringCharCodeAt: public LDeferredCode {
2906
3403
   public:
2911
3408
    LStringCharCodeAt* instr_;
2912
3409
  };
2913
3410
 
2914
 
  Register scratch = scratch0();
2915
3411
  Register string = ToRegister(instr->string());
2916
 
  Register index = no_reg;
2917
 
  int const_index = -1;
2918
 
  if (instr->index()->IsConstantOperand()) {
2919
 
    const_index = ToInteger32(LConstantOperand::cast(instr->index()));
2920
 
    STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
2921
 
    if (!Smi::IsValid(const_index)) {
2922
 
      // Guaranteed to be out of bounds because of the assert above.
2923
 
      // So the bounds check that must dominate this instruction must
2924
 
      // have deoptimized already.
2925
 
      if (FLAG_debug_code) {
2926
 
        __ Abort("StringCharCodeAt: out of bounds index.");
2927
 
      }
2928
 
      // No code needs to be generated.
2929
 
      return;
2930
 
    }
2931
 
  } else {
2932
 
    index = ToRegister(instr->index());
2933
 
  }
 
3412
  Register index = ToRegister(instr->index());
2934
3413
  Register result = ToRegister(instr->result());
2935
3414
 
2936
3415
  DeferredStringCharCodeAt* deferred =
2937
3416
      new DeferredStringCharCodeAt(this, instr);
2938
3417
 
2939
 
  Label flat_string, ascii_string, done;
2940
 
 
2941
3418
  // Fetch the instance type of the receiver into result register.
2942
3419
  __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
2943
3420
  __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
2944
3421
 
2945
 
  // We need special handling for non-flat strings.
2946
 
  STATIC_ASSERT(kSeqStringTag == 0);
2947
 
  __ tst(result, Operand(kStringRepresentationMask));
2948
 
  __ b(eq, &flat_string);
2949
 
 
2950
 
  // Handle non-flat strings.
2951
 
  __ tst(result, Operand(kIsConsStringMask));
2952
 
  __ b(eq, deferred->entry());
2953
 
 
2954
 
  // ConsString.
 
3422
  // We need special handling for indirect strings.
 
3423
  Label check_sequential;
 
3424
  __ tst(result, Operand(kIsIndirectStringMask));
 
3425
  __ b(eq, &check_sequential);
 
3426
 
 
3427
  // Dispatch on the indirect string shape: slice or cons.
 
3428
  Label cons_string;
 
3429
  __ tst(result, Operand(kSlicedNotConsMask));
 
3430
  __ b(eq, &cons_string);
 
3431
 
 
3432
  // Handle slices.
 
3433
  Label indirect_string_loaded;
 
3434
  __ ldr(result, FieldMemOperand(string, SlicedString::kOffsetOffset));
 
3435
  __ add(index, index, Operand(result, ASR, kSmiTagSize));
 
3436
  __ ldr(string, FieldMemOperand(string, SlicedString::kParentOffset));
 
3437
  __ jmp(&indirect_string_loaded);
 
3438
 
 
3439
  // Handle conses.
2955
3440
  // Check whether the right hand side is the empty string (i.e. if
2956
3441
  // this is really a flat string in a cons string). If that is not
2957
3442
  // the case we would rather go to the runtime system now to flatten
2958
3443
  // the string.
2959
 
  __ ldr(scratch, FieldMemOperand(string, ConsString::kSecondOffset));
 
3444
  __ bind(&cons_string);
 
3445
  __ ldr(result, FieldMemOperand(string, ConsString::kSecondOffset));
2960
3446
  __ LoadRoot(ip, Heap::kEmptyStringRootIndex);
2961
 
  __ cmp(scratch, ip);
 
3447
  __ cmp(result, ip);
2962
3448
  __ b(ne, deferred->entry());
2963
3449
  // Get the first of the two strings and load its instance type.
2964
3450
  __ ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
 
3451
 
 
3452
  __ bind(&indirect_string_loaded);
2965
3453
  __ ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
2966
3454
  __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
2967
 
  // If the first cons component is also non-flat, then go to runtime.
 
3455
 
 
3456
  // Check whether the string is sequential. The only non-sequential
 
3457
  // shapes we support have just been unwrapped above.
 
3458
  __ bind(&check_sequential);
2968
3459
  STATIC_ASSERT(kSeqStringTag == 0);
2969
3460
  __ tst(result, Operand(kStringRepresentationMask));
2970
3461
  __ b(ne, deferred->entry());
2971
3462
 
2972
 
  // Check for 1-byte or 2-byte string.
2973
 
  __ bind(&flat_string);
2974
 
  STATIC_ASSERT(kAsciiStringTag != 0);
 
3463
  // Dispatch on the encoding: ASCII or two-byte.
 
3464
  Label ascii_string;
 
3465
  STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0);
 
3466
  STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
2975
3467
  __ tst(result, Operand(kStringEncodingMask));
2976
3468
  __ b(ne, &ascii_string);
2977
3469
 
2978
 
  // 2-byte string.
2979
 
  // Load the 2-byte character code into the result register.
2980
 
  STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2981
 
  if (instr->index()->IsConstantOperand()) {
2982
 
    __ ldrh(result,
2983
 
            FieldMemOperand(string,
2984
 
                            SeqTwoByteString::kHeaderSize + 2 * const_index));
2985
 
  } else {
2986
 
    __ add(scratch,
2987
 
           string,
2988
 
           Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
2989
 
    __ ldrh(result, MemOperand(scratch, index, LSL, 1));
2990
 
  }
 
3470
  // Two-byte string.
 
3471
  // Load the two-byte character code into the result register.
 
3472
  Label done;
 
3473
  __ add(result,
 
3474
         string,
 
3475
         Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
 
3476
  __ ldrh(result, MemOperand(result, index, LSL, 1));
2991
3477
  __ jmp(&done);
2992
3478
 
2993
3479
  // ASCII string.
2994
3480
  // Load the byte into the result register.
2995
3481
  __ bind(&ascii_string);
2996
 
  if (instr->index()->IsConstantOperand()) {
2997
 
    __ ldrb(result, FieldMemOperand(string,
2998
 
                                    SeqAsciiString::kHeaderSize + const_index));
2999
 
  } else {
3000
 
    __ add(scratch,
3001
 
           string,
3002
 
           Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3003
 
    __ ldrb(result, MemOperand(scratch, index));
3004
 
  }
 
3482
  __ add(result,
 
3483
         string,
 
3484
         Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
 
3485
  __ ldrb(result, MemOperand(result, index));
 
3486
 
3005
3487
  __ bind(&done);
3006
3488
  __ bind(deferred->exit());
3007
3489
}
3039
3521
}
3040
3522
 
3041
3523
 
 
3524
void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
 
3525
  class DeferredStringCharFromCode: public LDeferredCode {
 
3526
   public:
 
3527
    DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
 
3528
        : LDeferredCode(codegen), instr_(instr) { }
 
3529
    virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
 
3530
   private:
 
3531
    LStringCharFromCode* instr_;
 
3532
  };
 
3533
 
 
3534
  DeferredStringCharFromCode* deferred =
 
3535
      new DeferredStringCharFromCode(this, instr);
 
3536
 
 
3537
  ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
 
3538
  Register char_code = ToRegister(instr->char_code());
 
3539
  Register result = ToRegister(instr->result());
 
3540
  ASSERT(!char_code.is(result));
 
3541
 
 
3542
  __ cmp(char_code, Operand(String::kMaxAsciiCharCode));
 
3543
  __ b(hi, deferred->entry());
 
3544
  __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
 
3545
  __ add(result, result, Operand(char_code, LSL, kPointerSizeLog2));
 
3546
  __ ldr(result, FieldMemOperand(result, FixedArray::kHeaderSize));
 
3547
  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
 
3548
  __ cmp(result, ip);
 
3549
  __ b(eq, deferred->entry());
 
3550
  __ bind(deferred->exit());
 
3551
}
 
3552
 
 
3553
 
 
3554
void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
 
3555
  Register char_code = ToRegister(instr->char_code());
 
3556
  Register result = ToRegister(instr->result());
 
3557
 
 
3558
  // TODO(3095996): Get rid of this. For now, we need to make the
 
3559
  // result register contain a valid pointer because it is already
 
3560
  // contained in the register pointer map.
 
3561
  __ mov(result, Operand(0));
 
3562
 
 
3563
  PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
 
3564
  __ SmiTag(char_code);
 
3565
  __ push(char_code);
 
3566
  CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr);
 
3567
  __ StoreToSafepointRegisterSlot(r0, result);
 
3568
}
 
3569
 
 
3570
 
3042
3571
void LCodeGen::DoStringLength(LStringLength* instr) {
3043
3572
  Register string = ToRegister(instr->InputAt(0));
3044
3573
  Register result = ToRegister(instr->result());
3087
3616
void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) {
3088
3617
  Label slow;
3089
3618
  Register reg = ToRegister(instr->InputAt(0));
3090
 
  DoubleRegister dbl_scratch = d0;
3091
 
  SwVfpRegister flt_scratch = s0;
 
3619
  DoubleRegister dbl_scratch = double_scratch0();
 
3620
  SwVfpRegister flt_scratch = dbl_scratch.low();
3092
3621
 
3093
3622
  // Preserve the value of all registers.
3094
3623
  PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
3182
3711
  LOperand* input = instr->InputAt(0);
3183
3712
  ASSERT(input->IsRegister() && input->Equals(instr->result()));
3184
3713
  if (instr->needs_check()) {
3185
 
    __ tst(ToRegister(input), Operand(kSmiTagMask));
3186
 
    DeoptimizeIf(ne, instr->environment());
 
3714
    STATIC_ASSERT(kHeapObjectTag == 1);
 
3715
    // If the input is a HeapObject, SmiUntag will set the carry flag.
 
3716
    __ SmiUntag(ToRegister(input), SetCC);
 
3717
    DeoptimizeIf(cs, instr->environment());
 
3718
  } else {
 
3719
    __ SmiUntag(ToRegister(input));
3187
3720
  }
3188
 
  __ SmiUntag(ToRegister(input));
3189
3721
}
3190
3722
 
3191
3723
 
3192
3724
void LCodeGen::EmitNumberUntagD(Register input_reg,
3193
3725
                                DoubleRegister result_reg,
 
3726
                                bool deoptimize_on_undefined,
3194
3727
                                LEnvironment* env) {
3195
3728
  Register scratch = scratch0();
3196
 
  SwVfpRegister flt_scratch = s0;
3197
 
  ASSERT(!result_reg.is(d0));
 
3729
  SwVfpRegister flt_scratch = double_scratch0().low();
 
3730
  ASSERT(!result_reg.is(double_scratch0()));
3198
3731
 
3199
3732
  Label load_smi, heap_number, done;
3200
3733
 
3201
3734
  // Smi check.
3202
 
  __ tst(input_reg, Operand(kSmiTagMask));
3203
 
  __ b(eq, &load_smi);
 
3735
  __ JumpIfSmi(input_reg, &load_smi);
3204
3736
 
3205
3737
  // Heap number map check.
3206
3738
  __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
3207
3739
  __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3208
3740
  __ cmp(scratch, Operand(ip));
3209
 
  __ b(eq, &heap_number);
3210
 
 
3211
 
  __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
3212
 
  __ cmp(input_reg, Operand(ip));
3213
 
  DeoptimizeIf(ne, env);
3214
 
 
3215
 
  // Convert undefined to NaN.
3216
 
  __ LoadRoot(ip, Heap::kNanValueRootIndex);
3217
 
  __ sub(ip, ip, Operand(kHeapObjectTag));
3218
 
  __ vldr(result_reg, ip, HeapNumber::kValueOffset);
3219
 
  __ jmp(&done);
3220
 
 
 
3741
  if (deoptimize_on_undefined) {
 
3742
    DeoptimizeIf(ne, env);
 
3743
  } else {
 
3744
    Label heap_number;
 
3745
    __ b(eq, &heap_number);
 
3746
 
 
3747
    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
 
3748
    __ cmp(input_reg, Operand(ip));
 
3749
    DeoptimizeIf(ne, env);
 
3750
 
 
3751
    // Convert undefined to NaN.
 
3752
    __ LoadRoot(ip, Heap::kNanValueRootIndex);
 
3753
    __ sub(ip, ip, Operand(kHeapObjectTag));
 
3754
    __ vldr(result_reg, ip, HeapNumber::kValueOffset);
 
3755
    __ jmp(&done);
 
3756
 
 
3757
    __ bind(&heap_number);
 
3758
  }
3221
3759
  // Heap number to double register conversion.
3222
 
  __ bind(&heap_number);
3223
3760
  __ sub(ip, input_reg, Operand(kHeapObjectTag));
3224
3761
  __ vldr(result_reg, ip, HeapNumber::kValueOffset);
3225
3762
  __ jmp(&done);
3245
3782
 
3246
3783
 
3247
3784
void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
3248
 
  Label done;
3249
3785
  Register input_reg = ToRegister(instr->InputAt(0));
3250
 
  Register scratch = scratch0();
3251
 
  DoubleRegister dbl_scratch = d0;
3252
 
  SwVfpRegister flt_scratch = s0;
3253
 
  DoubleRegister dbl_tmp = ToDoubleRegister(instr->TempAt(0));
 
3786
  Register scratch1 = scratch0();
 
3787
  Register scratch2 = ToRegister(instr->TempAt(0));
 
3788
  DwVfpRegister double_scratch = double_scratch0();
 
3789
  SwVfpRegister single_scratch = double_scratch.low();
 
3790
 
 
3791
  ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
 
3792
  ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
 
3793
 
 
3794
  Label done;
 
3795
 
 
3796
  // The input was optimistically untagged; revert it.
 
3797
  // The carry flag is set when we reach this deferred code as we just executed
 
3798
  // SmiUntag(heap_object, SetCC)
 
3799
  STATIC_ASSERT(kHeapObjectTag == 1);
 
3800
  __ adc(input_reg, input_reg, Operand(input_reg));
3254
3801
 
3255
3802
  // Heap number map check.
3256
 
  __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
 
3803
  __ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
3257
3804
  __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3258
 
  __ cmp(scratch, Operand(ip));
 
3805
  __ cmp(scratch1, Operand(ip));
3259
3806
 
3260
3807
  if (instr->truncating()) {
 
3808
    Register scratch3 = ToRegister(instr->TempAt(1));
 
3809
    DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2));
 
3810
    ASSERT(!scratch3.is(input_reg) &&
 
3811
           !scratch3.is(scratch1) &&
 
3812
           !scratch3.is(scratch2));
 
3813
    // Performs a truncating conversion of a floating point number as used by
 
3814
    // the JS bitwise operations.
3261
3815
    Label heap_number;
3262
3816
    __ b(eq, &heap_number);
3263
3817
    // Check for undefined. Undefined is converted to zero for truncating
3269
3823
    __ b(&done);
3270
3824
 
3271
3825
    __ bind(&heap_number);
3272
 
    __ sub(ip, input_reg, Operand(kHeapObjectTag));
3273
 
    __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset);
3274
 
    __ vcmp(dbl_tmp, 0.0);  // Sets overflow bit in FPSCR flags if NaN.
3275
 
    __ vcvt_s32_f64(flt_scratch, dbl_tmp);
3276
 
    __ vmov(input_reg, flt_scratch);  // 32-bit result of conversion.
3277
 
    __ vmrs(pc);  // Move vector status bits to normal status bits.
3278
 
    // Overflow bit is set if dbl_tmp is Nan.
3279
 
    __ cmn(input_reg, Operand(1), vc);  // 0x7fffffff + 1 -> overflow.
3280
 
    __ cmp(input_reg, Operand(1), vc);  // 0x80000000 - 1 -> overflow.
3281
 
    DeoptimizeIf(vs, instr->environment());  // Saturation may have occured.
 
3826
    __ sub(scratch1, input_reg, Operand(kHeapObjectTag));
 
3827
    __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
 
3828
 
 
3829
    __ EmitECMATruncate(input_reg,
 
3830
                        double_scratch2,
 
3831
                        single_scratch,
 
3832
                        scratch1,
 
3833
                        scratch2,
 
3834
                        scratch3);
3282
3835
 
3283
3836
  } else {
 
3837
    CpuFeatures::Scope scope(VFP3);
3284
3838
    // Deoptimize if we don't have a heap number.
3285
3839
    DeoptimizeIf(ne, instr->environment());
3286
3840
 
3287
3841
    __ sub(ip, input_reg, Operand(kHeapObjectTag));
3288
 
    __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset);
3289
 
    __ vcvt_s32_f64(flt_scratch, dbl_tmp);
3290
 
    __ vmov(input_reg, flt_scratch);  // 32-bit result of conversion.
3291
 
    // Non-truncating conversion means that we cannot lose bits, so we convert
3292
 
    // back to check; note that using non-overlapping s and d regs would be
3293
 
    // slightly faster.
3294
 
    __ vcvt_f64_s32(dbl_scratch, flt_scratch);
3295
 
    __ VFPCompareAndSetFlags(dbl_scratch, dbl_tmp);
3296
 
    DeoptimizeIf(ne, instr->environment());  // Not equal or unordered.
 
3842
    __ vldr(double_scratch, ip, HeapNumber::kValueOffset);
 
3843
    __ EmitVFPTruncate(kRoundToZero,
 
3844
                       single_scratch,
 
3845
                       double_scratch,
 
3846
                       scratch1,
 
3847
                       scratch2,
 
3848
                       kCheckForInexactConversion);
 
3849
    DeoptimizeIf(ne, instr->environment());
 
3850
    // Load the result.
 
3851
    __ vmov(input_reg, single_scratch);
 
3852
 
3297
3853
    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3298
 
      __ tst(input_reg, Operand(input_reg));
 
3854
      __ cmp(input_reg, Operand(0));
3299
3855
      __ b(ne, &done);
3300
 
      __ vmov(lr, ip, dbl_tmp);
3301
 
      __ tst(ip, Operand(1 << 31));  // Test sign bit.
 
3856
      __ vmov(scratch1, double_scratch.high());
 
3857
      __ tst(scratch1, Operand(HeapNumber::kSignMask));
3302
3858
      DeoptimizeIf(ne, instr->environment());
3303
3859
    }
3304
3860
  }
3315
3871
 
3316
3872
  DeferredTaggedToI* deferred = new DeferredTaggedToI(this, instr);
3317
3873
 
3318
 
  // Smi check.
3319
 
  __ tst(input_reg, Operand(kSmiTagMask));
3320
 
  __ b(ne, deferred->entry());
3321
 
 
3322
 
  // Smi to int32 conversion
3323
 
  __ SmiUntag(input_reg);  // Untag smi.
3324
 
 
 
3874
  // Optimistically untag the input.
 
3875
  // If the input is a HeapObject, SmiUntag will set the carry flag.
 
3876
  __ SmiUntag(input_reg, SetCC);
 
3877
  // Branch to deferred code if the input was tagged.
 
3878
  // The deferred code will take care of restoring the tag.
 
3879
  __ b(cs, deferred->entry());
3325
3880
  __ bind(deferred->exit());
3326
3881
}
3327
3882
 
3335
3890
  Register input_reg = ToRegister(input);
3336
3891
  DoubleRegister result_reg = ToDoubleRegister(result);
3337
3892
 
3338
 
  EmitNumberUntagD(input_reg, result_reg, instr->environment());
 
3893
  EmitNumberUntagD(input_reg, result_reg,
 
3894
                   instr->hydrogen()->deoptimize_on_undefined(),
 
3895
                   instr->environment());
3339
3896
}
3340
3897
 
3341
3898
 
3342
3899
void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
3343
 
  LOperand* input = instr->InputAt(0);
3344
 
  ASSERT(input->IsDoubleRegister());
3345
 
  LOperand* result = instr->result();
3346
 
  ASSERT(result->IsRegister());
3347
 
 
3348
 
  DoubleRegister double_input = ToDoubleRegister(input);
3349
 
  Register result_reg = ToRegister(result);
3350
 
  SwVfpRegister single_scratch = double_scratch0().low();
 
3900
  Register result_reg = ToRegister(instr->result());
3351
3901
  Register scratch1 = scratch0();
3352
3902
  Register scratch2 = ToRegister(instr->TempAt(0));
3353
 
 
3354
 
  __ EmitVFPTruncate(kRoundToZero,
3355
 
                     single_scratch,
3356
 
                     double_input,
3357
 
                     scratch1,
3358
 
                     scratch2);
3359
 
 
3360
 
  // Deoptimize if we had a vfp invalid exception.
3361
 
  DeoptimizeIf(ne, instr->environment());
3362
 
 
3363
 
  // Retrieve the result.
3364
 
  __ vmov(result_reg, single_scratch);
3365
 
 
3366
 
  if (!instr->truncating()) {
3367
 
    // Convert result back to double and compare with input
3368
 
    // to check if the conversion was exact.
3369
 
    __ vmov(single_scratch, result_reg);
3370
 
    __ vcvt_f64_s32(double_scratch0(), single_scratch);
3371
 
    __ VFPCompareAndSetFlags(double_scratch0(), double_input);
 
3903
  DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0));
 
3904
  SwVfpRegister single_scratch = double_scratch0().low();
 
3905
 
 
3906
  Label done;
 
3907
 
 
3908
  if (instr->truncating()) {
 
3909
    Register scratch3 = ToRegister(instr->TempAt(1));
 
3910
    __ EmitECMATruncate(result_reg,
 
3911
                        double_input,
 
3912
                        single_scratch,
 
3913
                        scratch1,
 
3914
                        scratch2,
 
3915
                        scratch3);
 
3916
  } else {
 
3917
    VFPRoundingMode rounding_mode = kRoundToMinusInf;
 
3918
    __ EmitVFPTruncate(rounding_mode,
 
3919
                       single_scratch,
 
3920
                       double_input,
 
3921
                       scratch1,
 
3922
                       scratch2,
 
3923
                       kCheckForInexactConversion);
 
3924
    // Deoptimize if we had a vfp invalid exception,
 
3925
    // including inexact operation.
3372
3926
    DeoptimizeIf(ne, instr->environment());
3373
 
    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
3374
 
      Label done;
3375
 
      __ cmp(result_reg, Operand(0));
3376
 
      __ b(ne, &done);
3377
 
      // Check for -0.
3378
 
      __ vmov(scratch1, double_input.high());
3379
 
      __ tst(scratch1, Operand(HeapNumber::kSignMask));
3380
 
      DeoptimizeIf(ne, instr->environment());
3381
 
 
3382
 
      __ bind(&done);
3383
 
    }
 
3927
    // Retrieve the result.
 
3928
    __ vmov(result_reg, single_scratch);
3384
3929
  }
 
3930
    __ bind(&done);
3385
3931
}
3386
3932
 
3387
3933
 
3388
3934
void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
3389
3935
  LOperand* input = instr->InputAt(0);
3390
 
  ASSERT(input->IsRegister());
3391
 
  __ tst(ToRegister(input), Operand(kSmiTagMask));
3392
 
  DeoptimizeIf(instr->condition(), instr->environment());
 
3936
  __ tst(ToRegister(input), Operand(kSmiTagMask));
 
3937
  DeoptimizeIf(ne, instr->environment());
 
3938
}
 
3939
 
 
3940
 
 
3941
void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
 
3942
  LOperand* input = instr->InputAt(0);
 
3943
  __ tst(ToRegister(input), Operand(kSmiTagMask));
 
3944
  DeoptimizeIf(eq, instr->environment());
3393
3945
}
3394
3946
 
3395
3947
 
3396
3948
void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
3397
3949
  Register input = ToRegister(instr->InputAt(0));
3398
3950
  Register scratch = scratch0();
3399
 
  InstanceType first = instr->hydrogen()->first();
3400
 
  InstanceType last = instr->hydrogen()->last();
3401
3951
 
3402
3952
  __ ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
3403
3953
  __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
3404
 
  __ cmp(scratch, Operand(first));
3405
 
 
3406
 
  // If there is only one type in the interval check for equality.
3407
 
  if (first == last) {
3408
 
    DeoptimizeIf(ne, instr->environment());
 
3954
 
 
3955
  if (instr->hydrogen()->is_interval_check()) {
 
3956
    InstanceType first;
 
3957
    InstanceType last;
 
3958
    instr->hydrogen()->GetCheckInterval(&first, &last);
 
3959
 
 
3960
    __ cmp(scratch, Operand(first));
 
3961
 
 
3962
    // If there is only one type in the interval check for equality.
 
3963
    if (first == last) {
 
3964
      DeoptimizeIf(ne, instr->environment());
 
3965
    } else {
 
3966
      DeoptimizeIf(lo, instr->environment());
 
3967
      // Omit check for the last type.
 
3968
      if (last != LAST_TYPE) {
 
3969
        __ cmp(scratch, Operand(last));
 
3970
        DeoptimizeIf(hi, instr->environment());
 
3971
      }
 
3972
    }
3409
3973
  } else {
3410
 
    DeoptimizeIf(lo, instr->environment());
3411
 
    // Omit check for the last type.
3412
 
    if (last != LAST_TYPE) {
3413
 
      __ cmp(scratch, Operand(last));
3414
 
      DeoptimizeIf(hi, instr->environment());
 
3974
    uint8_t mask;
 
3975
    uint8_t tag;
 
3976
    instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
 
3977
 
 
3978
    if (IsPowerOf2(mask)) {
 
3979
      ASSERT(tag == 0 || IsPowerOf2(tag));
 
3980
      __ tst(scratch, Operand(mask));
 
3981
      DeoptimizeIf(tag == 0 ? ne : eq, instr->environment());
 
3982
    } else {
 
3983
      __ and_(scratch, scratch, Operand(mask));
 
3984
      __ cmp(scratch, Operand(tag));
 
3985
      DeoptimizeIf(ne, instr->environment());
3415
3986
    }
3416
3987
  }
3417
3988
}
3436
4007
}
3437
4008
 
3438
4009
 
 
4010
void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
 
4011
  DoubleRegister value_reg = ToDoubleRegister(instr->unclamped());
 
4012
  Register result_reg = ToRegister(instr->result());
 
4013
  DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
 
4014
  __ ClampDoubleToUint8(result_reg, value_reg, temp_reg);
 
4015
}
 
4016
 
 
4017
 
 
4018
void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
 
4019
  Register unclamped_reg = ToRegister(instr->unclamped());
 
4020
  Register result_reg = ToRegister(instr->result());
 
4021
  __ ClampUint8(result_reg, unclamped_reg);
 
4022
}
 
4023
 
 
4024
 
 
4025
void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
 
4026
  Register scratch = scratch0();
 
4027
  Register input_reg = ToRegister(instr->unclamped());
 
4028
  Register result_reg = ToRegister(instr->result());
 
4029
  DoubleRegister temp_reg = ToDoubleRegister(instr->TempAt(0));
 
4030
  Label is_smi, done, heap_number;
 
4031
 
 
4032
  // Both smi and heap number cases are handled.
 
4033
  __ JumpIfSmi(input_reg, &is_smi);
 
4034
 
 
4035
  // Check for heap number
 
4036
  __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
 
4037
  __ cmp(scratch, Operand(factory()->heap_number_map()));
 
4038
  __ b(eq, &heap_number);
 
4039
 
 
4040
  // Check for undefined. Undefined is converted to zero for clamping
 
4041
  // conversions.
 
4042
  __ cmp(input_reg, Operand(factory()->undefined_value()));
 
4043
  DeoptimizeIf(ne, instr->environment());
 
4044
  __ mov(result_reg, Operand(0));
 
4045
  __ jmp(&done);
 
4046
 
 
4047
  // Heap number
 
4048
  __ bind(&heap_number);
 
4049
  __ vldr(double_scratch0(), FieldMemOperand(input_reg,
 
4050
                                             HeapNumber::kValueOffset));
 
4051
  __ ClampDoubleToUint8(result_reg, double_scratch0(), temp_reg);
 
4052
  __ jmp(&done);
 
4053
 
 
4054
  // smi
 
4055
  __ bind(&is_smi);
 
4056
  __ SmiUntag(result_reg, input_reg);
 
4057
  __ ClampUint8(result_reg, result_reg);
 
4058
 
 
4059
  __ bind(&done);
 
4060
}
 
4061
 
 
4062
 
3439
4063
void LCodeGen::LoadHeapObject(Register result,
3440
4064
                              Handle<HeapObject> object) {
3441
 
  if (Heap::InNewSpace(*object)) {
 
4065
  if (heap()->InNewSpace(*object)) {
3442
4066
    Handle<JSGlobalPropertyCell> cell =
3443
 
        Factory::NewJSGlobalPropertyCell(object);
 
4067
        factory()->NewJSGlobalPropertyCell(object);
3444
4068
    __ mov(result, Operand(cell));
3445
4069
    __ ldr(result, FieldMemOperand(result, JSGlobalPropertyCell::kValueOffset));
3446
4070
  } else {
3522
4146
}
3523
4147
 
3524
4148
 
 
4149
void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
 
4150
  ASSERT(ToRegister(instr->InputAt(0)).is(r0));
 
4151
  __ push(r0);
 
4152
  CallRuntime(Runtime::kToFastProperties, 1, instr);
 
4153
}
 
4154
 
 
4155
 
3525
4156
void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
3526
4157
  Label materialized;
3527
4158
  // Registers will be used as follows:
3582
4213
  // space for nested functions that don't need literals cloning.
3583
4214
  Handle<SharedFunctionInfo> shared_info = instr->shared_info();
3584
4215
  bool pretenure = instr->hydrogen()->pretenure();
3585
 
  if (shared_info->num_literals() == 0 && !pretenure) {
3586
 
    FastNewClosureStub stub;
 
4216
  if (!pretenure && shared_info->num_literals() == 0) {
 
4217
    FastNewClosureStub stub(
 
4218
        shared_info->strict_mode() ? kStrictMode : kNonStrictMode);
3587
4219
    __ mov(r1, Operand(shared_info));
3588
4220
    __ push(r1);
3589
4221
    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3590
4222
  } else {
3591
4223
    __ mov(r2, Operand(shared_info));
3592
4224
    __ mov(r1, Operand(pretenure
3593
 
                       ? Factory::true_value()
3594
 
                       : Factory::false_value()));
 
4225
                       ? factory()->true_value()
 
4226
                       : factory()->false_value()));
3595
4227
    __ Push(cp, r2, r1);
3596
4228
    CallRuntime(Runtime::kNewClosure, 3, instr);
3597
4229
  }
3605
4237
}
3606
4238
 
3607
4239
 
3608
 
void LCodeGen::DoTypeofIs(LTypeofIs* instr) {
3609
 
  Register input = ToRegister(instr->InputAt(0));
3610
 
  Register result = ToRegister(instr->result());
3611
 
  Label true_label;
3612
 
  Label false_label;
3613
 
  Label done;
3614
 
 
3615
 
  Condition final_branch_condition = EmitTypeofIs(&true_label,
3616
 
                                                  &false_label,
3617
 
                                                  input,
3618
 
                                                  instr->type_literal());
3619
 
  __ b(final_branch_condition, &true_label);
3620
 
  __ bind(&false_label);
3621
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex);
3622
 
  __ b(&done);
3623
 
 
3624
 
  __ bind(&true_label);
3625
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex);
3626
 
 
3627
 
  __ bind(&done);
3628
 
}
3629
 
 
3630
 
 
3631
4240
void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
3632
4241
  Register input = ToRegister(instr->InputAt(0));
3633
4242
  int true_block = chunk_->LookupDestination(instr->true_block_id());
3650
4259
                                 Handle<String> type_name) {
3651
4260
  Condition final_branch_condition = kNoCondition;
3652
4261
  Register scratch = scratch0();
3653
 
  if (type_name->Equals(Heap::number_symbol())) {
3654
 
    __ tst(input, Operand(kSmiTagMask));
3655
 
    __ b(eq, true_label);
 
4262
  if (type_name->Equals(heap()->number_symbol())) {
 
4263
    __ JumpIfSmi(input, true_label);
3656
4264
    __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
3657
4265
    __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3658
4266
    __ cmp(input, Operand(ip));
3659
4267
    final_branch_condition = eq;
3660
4268
 
3661
 
  } else if (type_name->Equals(Heap::string_symbol())) {
3662
 
    __ tst(input, Operand(kSmiTagMask));
3663
 
    __ b(eq, false_label);
3664
 
    __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
 
4269
  } else if (type_name->Equals(heap()->string_symbol())) {
 
4270
    __ JumpIfSmi(input, false_label);
 
4271
    __ CompareObjectType(input, input, scratch, FIRST_NONSTRING_TYPE);
 
4272
    __ b(ge, false_label);
3665
4273
    __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
3666
4274
    __ tst(ip, Operand(1 << Map::kIsUndetectable));
3667
 
    __ b(ne, false_label);
3668
 
    __ CompareInstanceType(input, scratch, FIRST_NONSTRING_TYPE);
3669
 
    final_branch_condition = lo;
3670
 
 
3671
 
  } else if (type_name->Equals(Heap::boolean_symbol())) {
3672
 
    __ LoadRoot(ip, Heap::kTrueValueRootIndex);
3673
 
    __ cmp(input, ip);
3674
 
    __ b(eq, true_label);
3675
 
    __ LoadRoot(ip, Heap::kFalseValueRootIndex);
3676
 
    __ cmp(input, ip);
3677
 
    final_branch_condition = eq;
3678
 
 
3679
 
  } else if (type_name->Equals(Heap::undefined_symbol())) {
3680
 
    __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
3681
 
    __ cmp(input, ip);
3682
 
    __ b(eq, true_label);
3683
 
    __ tst(input, Operand(kSmiTagMask));
3684
 
    __ b(eq, false_label);
 
4275
    final_branch_condition = eq;
 
4276
 
 
4277
  } else if (type_name->Equals(heap()->boolean_symbol())) {
 
4278
    __ CompareRoot(input, Heap::kTrueValueRootIndex);
 
4279
    __ b(eq, true_label);
 
4280
    __ CompareRoot(input, Heap::kFalseValueRootIndex);
 
4281
    final_branch_condition = eq;
 
4282
 
 
4283
  } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_symbol())) {
 
4284
    __ CompareRoot(input, Heap::kNullValueRootIndex);
 
4285
    final_branch_condition = eq;
 
4286
 
 
4287
  } else if (type_name->Equals(heap()->undefined_symbol())) {
 
4288
    __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
 
4289
    __ b(eq, true_label);
 
4290
    __ JumpIfSmi(input, false_label);
3685
4291
    // Check for undetectable objects => true.
3686
4292
    __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
3687
4293
    __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
3688
4294
    __ tst(ip, Operand(1 << Map::kIsUndetectable));
3689
4295
    final_branch_condition = ne;
3690
4296
 
3691
 
  } else if (type_name->Equals(Heap::function_symbol())) {
3692
 
    __ tst(input, Operand(kSmiTagMask));
3693
 
    __ b(eq, false_label);
3694
 
    __ CompareObjectType(input, input, scratch, JS_FUNCTION_TYPE);
3695
 
    __ b(eq, true_label);
3696
 
    // Regular expressions => 'function' (they are callable).
3697
 
    __ CompareInstanceType(input, scratch, JS_REGEXP_TYPE);
3698
 
    final_branch_condition = eq;
 
4297
  } else if (type_name->Equals(heap()->function_symbol())) {
 
4298
    __ JumpIfSmi(input, false_label);
 
4299
    __ CompareObjectType(input, input, scratch,
 
4300
                         FIRST_CALLABLE_SPEC_OBJECT_TYPE);
 
4301
    final_branch_condition = ge;
3699
4302
 
3700
 
  } else if (type_name->Equals(Heap::object_symbol())) {
3701
 
    __ tst(input, Operand(kSmiTagMask));
3702
 
    __ b(eq, false_label);
3703
 
    __ LoadRoot(ip, Heap::kNullValueRootIndex);
3704
 
    __ cmp(input, ip);
3705
 
    __ b(eq, true_label);
3706
 
    // Regular expressions => 'function', not 'object'.
3707
 
    __ CompareObjectType(input, input, scratch, JS_REGEXP_TYPE);
3708
 
    __ b(eq, false_label);
 
4303
  } else if (type_name->Equals(heap()->object_symbol())) {
 
4304
    __ JumpIfSmi(input, false_label);
 
4305
    if (!FLAG_harmony_typeof) {
 
4306
      __ CompareRoot(input, Heap::kNullValueRootIndex);
 
4307
      __ b(eq, true_label);
 
4308
    }
 
4309
    __ CompareObjectType(input, input, scratch,
 
4310
                         FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
 
4311
    __ b(lt, false_label);
 
4312
    __ CompareInstanceType(input, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
 
4313
    __ b(gt, false_label);
3709
4314
    // Check for undetectable objects => false.
3710
4315
    __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
3711
4316
    __ tst(ip, Operand(1 << Map::kIsUndetectable));
3712
 
    __ b(ne, false_label);
3713
 
    // Check for JS objects => true.
3714
 
    __ CompareInstanceType(input, scratch, FIRST_JS_OBJECT_TYPE);
3715
 
    __ b(lo, false_label);
3716
 
    __ CompareInstanceType(input, scratch, LAST_JS_OBJECT_TYPE);
3717
 
    final_branch_condition = ls;
 
4317
    final_branch_condition = eq;
3718
4318
 
3719
4319
  } else {
3720
4320
    final_branch_condition = ne;
3726
4326
}
3727
4327
 
3728
4328
 
3729
 
void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
3730
 
  Register result = ToRegister(instr->result());
3731
 
  Label true_label;
3732
 
  Label false_label;
3733
 
  Label done;
3734
 
 
3735
 
  EmitIsConstructCall(result, scratch0());
3736
 
  __ b(eq, &true_label);
3737
 
 
3738
 
  __ LoadRoot(result, Heap::kFalseValueRootIndex);
3739
 
  __ b(&done);
3740
 
 
3741
 
 
3742
 
  __ bind(&true_label);
3743
 
  __ LoadRoot(result, Heap::kTrueValueRootIndex);
3744
 
 
3745
 
  __ bind(&done);
3746
 
}
3747
 
 
3748
 
 
3749
4329
void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
3750
4330
  Register temp1 = ToRegister(instr->TempAt(0));
3751
4331
  int true_block = chunk_->LookupDestination(instr->true_block_id());
3775
4355
}
3776
4356
 
3777
4357
 
 
4358
void LCodeGen::EnsureSpaceForLazyDeopt() {
 
4359
  // Ensure that we have enough space after the previous lazy-bailout
 
4360
  // instruction for patching the code here.
 
4361
  int current_pc = masm()->pc_offset();
 
4362
  int patch_size = Deoptimizer::patch_size();
 
4363
  if (current_pc < last_lazy_deopt_pc_ + patch_size) {
 
4364
    int padding_size = last_lazy_deopt_pc_ + patch_size - current_pc;
 
4365
    ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
 
4366
    while (padding_size > 0) {
 
4367
      __ nop();
 
4368
      padding_size -= Assembler::kInstrSize;
 
4369
    }
 
4370
  }
 
4371
  last_lazy_deopt_pc_ = masm()->pc_offset();
 
4372
}
 
4373
 
 
4374
 
3778
4375
void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
3779
 
  // No code for lazy bailout instruction. Used to capture environment after a
3780
 
  // call for populating the safepoint data with deoptimization data.
 
4376
  EnsureSpaceForLazyDeopt();
 
4377
  ASSERT(instr->HasEnvironment());
 
4378
  LEnvironment* env = instr->environment();
 
4379
  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
 
4380
  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
3781
4381
}
3782
4382
 
3783
4383
 
3794
4394
  __ Push(object, key, strict);
3795
4395
  ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
3796
4396
  LPointerMap* pointers = instr->pointer_map();
3797
 
  LEnvironment* env = instr->deoptimization_environment();
3798
 
  RecordPosition(pointers->position());
3799
 
  RegisterEnvironmentForDeoptimization(env);
3800
 
  SafepointGenerator safepoint_generator(this,
3801
 
                                         pointers,
3802
 
                                         env->deoptimization_index());
3803
 
  __ InvokeBuiltin(Builtins::DELETE, CALL_JS, &safepoint_generator);
 
4397
  RecordPosition(pointers->position());
 
4398
  SafepointGenerator safepoint_generator(
 
4399
      this, pointers, Safepoint::kLazyDeopt);
 
4400
  __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, safepoint_generator);
 
4401
}
 
4402
 
 
4403
 
 
4404
void LCodeGen::DoIn(LIn* instr) {
 
4405
  Register obj = ToRegister(instr->object());
 
4406
  Register key = ToRegister(instr->key());
 
4407
  __ Push(key, obj);
 
4408
  ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
 
4409
  LPointerMap* pointers = instr->pointer_map();
 
4410
  RecordPosition(pointers->position());
 
4411
  SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
 
4412
  __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION, safepoint_generator);
 
4413
}
 
4414
 
 
4415
 
 
4416
void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
 
4417
  PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
 
4418
  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
 
4419
  RecordSafepointWithLazyDeopt(
 
4420
      instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
 
4421
  ASSERT(instr->HasEnvironment());
 
4422
  LEnvironment* env = instr->environment();
 
4423
  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
3804
4424
}
3805
4425
 
3806
4426
 
3807
4427
void LCodeGen::DoStackCheck(LStackCheck* instr) {
3808
 
  // Perform stack overflow check.
3809
 
  Label ok;
3810
 
  __ LoadRoot(ip, Heap::kStackLimitRootIndex);
3811
 
  __ cmp(sp, Operand(ip));
3812
 
  __ b(hs, &ok);
3813
 
  StackCheckStub stub;
3814
 
  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
3815
 
  __ bind(&ok);
 
4428
  class DeferredStackCheck: public LDeferredCode {
 
4429
   public:
 
4430
    DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
 
4431
        : LDeferredCode(codegen), instr_(instr) { }
 
4432
    virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
 
4433
   private:
 
4434
    LStackCheck* instr_;
 
4435
  };
 
4436
 
 
4437
  ASSERT(instr->HasEnvironment());
 
4438
  LEnvironment* env = instr->environment();
 
4439
  // There is no LLazyBailout instruction for stack-checks. We have to
 
4440
  // prepare for lazy deoptimization explicitly here.
 
4441
  if (instr->hydrogen()->is_function_entry()) {
 
4442
    // Perform stack overflow check.
 
4443
    Label done;
 
4444
    __ LoadRoot(ip, Heap::kStackLimitRootIndex);
 
4445
    __ cmp(sp, Operand(ip));
 
4446
    __ b(hs, &done);
 
4447
    StackCheckStub stub;
 
4448
    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
 
4449
    EnsureSpaceForLazyDeopt();
 
4450
    __ bind(&done);
 
4451
    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
 
4452
    safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
 
4453
  } else {
 
4454
    ASSERT(instr->hydrogen()->is_backwards_branch());
 
4455
    // Perform stack overflow check if this goto needs it before jumping.
 
4456
    DeferredStackCheck* deferred_stack_check =
 
4457
        new DeferredStackCheck(this, instr);
 
4458
    __ LoadRoot(ip, Heap::kStackLimitRootIndex);
 
4459
    __ cmp(sp, Operand(ip));
 
4460
    __ b(lo, deferred_stack_check->entry());
 
4461
    EnsureSpaceForLazyDeopt();
 
4462
    __ bind(instr->done_label());
 
4463
    deferred_stack_check->SetExit(instr->done_label());
 
4464
    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
 
4465
    // Don't record a deoptimization index for the safepoint here.
 
4466
    // This will be done explicitly when emitting call and the safepoint in
 
4467
    // the deferred code.
 
4468
  }
3816
4469
}
3817
4470
 
3818
4471
 
3827
4480
  // If the environment were already registered, we would have no way of
3828
4481
  // backpatching it with the spill slot operands.
3829
4482
  ASSERT(!environment->HasBeenRegistered());
3830
 
  RegisterEnvironmentForDeoptimization(environment);
 
4483
  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
3831
4484
  ASSERT(osr_pc_offset_ == -1);
3832
4485
  osr_pc_offset_ = masm()->pc_offset();
3833
4486
}
3834
4487
 
3835
4488
 
 
4489
 
 
4490
 
3836
4491
#undef __
3837
4492
 
3838
4493
} }  // namespace v8::internal