| Index: src/arm/lithium-codegen-arm.cc
|
| ===================================================================
|
| --- src/arm/lithium-codegen-arm.cc (revision 7180)
|
| +++ src/arm/lithium-codegen-arm.cc (working copy)
|
| @@ -26,6 +26,7 @@
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| #include "arm/lithium-codegen-arm.h"
|
| +#include "arm/lithium-gap-resolver-arm.h"
|
| #include "code-stubs.h"
|
| #include "stub-cache.h"
|
|
|
| @@ -33,7 +34,7 @@
|
| namespace internal {
|
|
|
|
|
| -class SafepointGenerator : public PostCallGenerator {
|
| +class SafepointGenerator : public CallWrapper {
|
| public:
|
| SafepointGenerator(LCodeGen* codegen,
|
| LPointerMap* pointers,
|
| @@ -43,7 +44,24 @@
|
| deoptimization_index_(deoptimization_index) { }
|
| virtual ~SafepointGenerator() { }
|
|
|
| - virtual void Generate() {
|
| + virtual void BeforeCall(int call_size) {
|
| + ASSERT(call_size >= 0);
|
| + // Ensure that we have enough space after the previous safepoint position
|
| + // for the generated code there.
|
| + int call_end = codegen_->masm()->pc_offset() + call_size;
|
| + int prev_jump_end =
|
| + codegen_->LastSafepointEnd() + Deoptimizer::patch_size();
|
| + if (call_end < prev_jump_end) {
|
| + int padding_size = prev_jump_end - call_end;
|
| + ASSERT_EQ(0, padding_size % Assembler::kInstrSize);
|
| + while (padding_size > 0) {
|
| + codegen_->masm()->nop();
|
| + padding_size -= Assembler::kInstrSize;
|
| + }
|
| + }
|
| + }
|
| +
|
| + virtual void AfterCall() {
|
| codegen_->RecordSafepoint(pointers_, deoptimization_index_);
|
| }
|
|
|
| @@ -54,157 +72,6 @@
|
| };
|
|
|
|
|
| -class LGapNode: public ZoneObject {
|
| - public:
|
| - explicit LGapNode(LOperand* operand)
|
| - : operand_(operand), resolved_(false), visited_id_(-1) { }
|
| -
|
| - LOperand* operand() const { return operand_; }
|
| - bool IsResolved() const { return !IsAssigned() || resolved_; }
|
| - void MarkResolved() {
|
| - ASSERT(!IsResolved());
|
| - resolved_ = true;
|
| - }
|
| - int visited_id() const { return visited_id_; }
|
| - void set_visited_id(int id) {
|
| - ASSERT(id > visited_id_);
|
| - visited_id_ = id;
|
| - }
|
| -
|
| - bool IsAssigned() const { return assigned_from_.is_set(); }
|
| - LGapNode* assigned_from() const { return assigned_from_.get(); }
|
| - void set_assigned_from(LGapNode* n) { assigned_from_.set(n); }
|
| -
|
| - private:
|
| - LOperand* operand_;
|
| - SetOncePointer<LGapNode> assigned_from_;
|
| - bool resolved_;
|
| - int visited_id_;
|
| -};
|
| -
|
| -
|
| -LGapResolver::LGapResolver()
|
| - : nodes_(32),
|
| - identified_cycles_(4),
|
| - result_(16),
|
| - next_visited_id_(0) {
|
| -}
|
| -
|
| -
|
| -const ZoneList<LMoveOperands>* LGapResolver::Resolve(
|
| - const ZoneList<LMoveOperands>* moves,
|
| - LOperand* marker_operand) {
|
| - nodes_.Rewind(0);
|
| - identified_cycles_.Rewind(0);
|
| - result_.Rewind(0);
|
| - next_visited_id_ = 0;
|
| -
|
| - for (int i = 0; i < moves->length(); ++i) {
|
| - LMoveOperands move = moves->at(i);
|
| - if (!move.IsRedundant()) RegisterMove(move);
|
| - }
|
| -
|
| - for (int i = 0; i < identified_cycles_.length(); ++i) {
|
| - ResolveCycle(identified_cycles_[i], marker_operand);
|
| - }
|
| -
|
| - int unresolved_nodes;
|
| - do {
|
| - unresolved_nodes = 0;
|
| - for (int j = 0; j < nodes_.length(); j++) {
|
| - LGapNode* node = nodes_[j];
|
| - if (!node->IsResolved() && node->assigned_from()->IsResolved()) {
|
| - AddResultMove(node->assigned_from(), node);
|
| - node->MarkResolved();
|
| - }
|
| - if (!node->IsResolved()) ++unresolved_nodes;
|
| - }
|
| - } while (unresolved_nodes > 0);
|
| - return &result_;
|
| -}
|
| -
|
| -
|
| -void LGapResolver::AddResultMove(LGapNode* from, LGapNode* to) {
|
| - AddResultMove(from->operand(), to->operand());
|
| -}
|
| -
|
| -
|
| -void LGapResolver::AddResultMove(LOperand* from, LOperand* to) {
|
| - result_.Add(LMoveOperands(from, to));
|
| -}
|
| -
|
| -
|
| -void LGapResolver::ResolveCycle(LGapNode* start, LOperand* marker_operand) {
|
| - ZoneList<LOperand*> cycle_operands(8);
|
| - cycle_operands.Add(marker_operand);
|
| - LGapNode* cur = start;
|
| - do {
|
| - cur->MarkResolved();
|
| - cycle_operands.Add(cur->operand());
|
| - cur = cur->assigned_from();
|
| - } while (cur != start);
|
| - cycle_operands.Add(marker_operand);
|
| -
|
| - for (int i = cycle_operands.length() - 1; i > 0; --i) {
|
| - LOperand* from = cycle_operands[i];
|
| - LOperand* to = cycle_operands[i - 1];
|
| - AddResultMove(from, to);
|
| - }
|
| -}
|
| -
|
| -
|
| -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b, int visited_id) {
|
| - ASSERT(a != b);
|
| - LGapNode* cur = a;
|
| - while (cur != b && cur->visited_id() != visited_id && cur->IsAssigned()) {
|
| - cur->set_visited_id(visited_id);
|
| - cur = cur->assigned_from();
|
| - }
|
| -
|
| - return cur == b;
|
| -}
|
| -
|
| -
|
| -bool LGapResolver::CanReach(LGapNode* a, LGapNode* b) {
|
| - ASSERT(a != b);
|
| - return CanReach(a, b, next_visited_id_++);
|
| -}
|
| -
|
| -
|
| -void LGapResolver::RegisterMove(LMoveOperands move) {
|
| - if (move.source()->IsConstantOperand()) {
|
| - // Constant moves should be last in the machine code. Therefore add them
|
| - // first to the result set.
|
| - AddResultMove(move.source(), move.destination());
|
| - } else {
|
| - LGapNode* from = LookupNode(move.source());
|
| - LGapNode* to = LookupNode(move.destination());
|
| - if (to->IsAssigned() && to->assigned_from() == from) {
|
| - move.Eliminate();
|
| - return;
|
| - }
|
| - ASSERT(!to->IsAssigned());
|
| - if (CanReach(from, to)) {
|
| - // This introduces a cycle. Save.
|
| - identified_cycles_.Add(from);
|
| - }
|
| - to->set_assigned_from(from);
|
| - }
|
| -}
|
| -
|
| -
|
| -LGapNode* LGapResolver::LookupNode(LOperand* operand) {
|
| - for (int i = 0; i < nodes_.length(); ++i) {
|
| - if (nodes_[i]->operand()->Equals(operand)) return nodes_[i];
|
| - }
|
| -
|
| - // No node found => create a new one.
|
| - LGapNode* result = new LGapNode(operand);
|
| - nodes_.Add(result);
|
| - return result;
|
| -}
|
| -
|
| -
|
| #define __ masm()->
|
|
|
| bool LCodeGen::GenerateCode() {
|
| @@ -230,8 +97,8 @@
|
|
|
| void LCodeGen::Abort(const char* format, ...) {
|
| if (FLAG_trace_bailout) {
|
| - SmartPointer<char> debug_name = graph()->debug_name()->ToCString();
|
| - PrintF("Aborting LCodeGen in @\"%s\": ", *debug_name);
|
| + SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString());
|
| + PrintF("Aborting LCodeGen in @\"%s\": ", *name);
|
| va_list arguments;
|
| va_start(arguments, format);
|
| OS::VPrint(format, arguments);
|
| @@ -294,6 +161,44 @@
|
| }
|
| }
|
|
|
| + // Possibly allocate a local context.
|
| + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
| + if (heap_slots > 0) {
|
| + Comment(";;; Allocate local context");
|
| + // Argument to NewContext is the function, which is in r1.
|
| + __ push(r1);
|
| + if (heap_slots <= FastNewContextStub::kMaximumSlots) {
|
| + FastNewContextStub stub(heap_slots);
|
| + __ CallStub(&stub);
|
| + } else {
|
| + __ CallRuntime(Runtime::kNewContext, 1);
|
| + }
|
| + RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
| + // Context is returned in both r0 and cp. It replaces the context
|
| + // passed to us. It's saved in the stack and kept live in cp.
|
| + __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
| + // Copy any necessary parameters into the context.
|
| + int num_parameters = scope()->num_parameters();
|
| + for (int i = 0; i < num_parameters; i++) {
|
| + Slot* slot = scope()->parameter(i)->AsSlot();
|
| + if (slot != NULL && slot->type() == Slot::CONTEXT) {
|
| + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
| + (num_parameters - 1 - i) * kPointerSize;
|
| + // Load parameter from stack.
|
| + __ ldr(r0, MemOperand(fp, parameter_offset));
|
| + // Store it in the context.
|
| + __ mov(r1, Operand(Context::SlotOffset(slot->index())));
|
| + __ str(r0, MemOperand(cp, r1));
|
| + // Update the write barrier. This clobbers all involved
|
| + // registers, so we have to use two more registers to avoid
|
| + // clobbering cp.
|
| + __ mov(r2, Operand(cp));
|
| + __ RecordWrite(r2, Operand(r1), r3, r0);
|
| + }
|
| + }
|
| + Comment(";;; End allocate local context");
|
| + }
|
| +
|
| // Trace the call.
|
| if (FLAG_trace) {
|
| __ CallRuntime(Runtime::kTraceEnter, 0);
|
| @@ -464,7 +369,6 @@
|
|
|
|
|
| MemOperand LCodeGen::ToMemOperand(LOperand* op) const {
|
| - // TODO(regis): Revisit.
|
| ASSERT(!op->IsRegister());
|
| ASSERT(!op->IsDoubleRegister());
|
| ASSERT(op->IsStackSlot() || op->IsDoubleStackSlot());
|
| @@ -480,6 +384,21 @@
|
| }
|
|
|
|
|
| +MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
|
| + ASSERT(op->IsDoubleStackSlot());
|
| + int index = op->index();
|
| + if (index >= 0) {
|
| + // Local or spill slot. Skip the frame pointer, function, context,
|
| + // and the first word of the double in the fixed part of the frame.
|
| + return MemOperand(fp, -(index + 3) * kPointerSize + kPointerSize);
|
| + } else {
|
| + // Incoming parameter. Skip the return address and the first word of
|
| + // the double.
|
| + return MemOperand(fp, -(index - 1) * kPointerSize + kPointerSize);
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::WriteTranslation(LEnvironment* environment,
|
| Translation* translation) {
|
| if (environment == NULL) return;
|
| @@ -671,7 +590,8 @@
|
| Handle<DeoptimizationInputData> data =
|
| Factory::NewDeoptimizationInputData(length, TENURED);
|
|
|
| - data->SetTranslationByteArray(*translations_.CreateByteArray());
|
| + Handle<ByteArray> translations = translations_.CreateByteArray();
|
| + data->SetTranslationByteArray(*translations);
|
| data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
|
|
|
| Handle<FixedArray> literals =
|
| @@ -751,6 +671,12 @@
|
| }
|
|
|
|
|
| +void LCodeGen::RecordSafepoint(int deoptimization_index) {
|
| + LPointerMap empty_pointers(RelocInfo::kNoPosition);
|
| + RecordSafepoint(&empty_pointers, deoptimization_index);
|
| +}
|
| +
|
| +
|
| void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
|
| int arguments,
|
| int deoptimization_index) {
|
| @@ -787,116 +713,7 @@
|
|
|
|
|
| void LCodeGen::DoParallelMove(LParallelMove* move) {
|
| - // d0 must always be a scratch register.
|
| - DoubleRegister dbl_scratch = d0;
|
| - LUnallocated marker_operand(LUnallocated::NONE);
|
| -
|
| - Register core_scratch = scratch0();
|
| - bool destroys_core_scratch = false;
|
| -
|
| - const ZoneList<LMoveOperands>* moves =
|
| - resolver_.Resolve(move->move_operands(), &marker_operand);
|
| - for (int i = moves->length() - 1; i >= 0; --i) {
|
| - LMoveOperands move = moves->at(i);
|
| - LOperand* from = move.source();
|
| - LOperand* to = move.destination();
|
| - ASSERT(!from->IsDoubleRegister() ||
|
| - !ToDoubleRegister(from).is(dbl_scratch));
|
| - ASSERT(!to->IsDoubleRegister() || !ToDoubleRegister(to).is(dbl_scratch));
|
| - ASSERT(!from->IsRegister() || !ToRegister(from).is(core_scratch));
|
| - ASSERT(!to->IsRegister() || !ToRegister(to).is(core_scratch));
|
| - if (from == &marker_operand) {
|
| - if (to->IsRegister()) {
|
| - __ mov(ToRegister(to), core_scratch);
|
| - ASSERT(destroys_core_scratch);
|
| - } else if (to->IsStackSlot()) {
|
| - __ str(core_scratch, ToMemOperand(to));
|
| - ASSERT(destroys_core_scratch);
|
| - } else if (to->IsDoubleRegister()) {
|
| - __ vmov(ToDoubleRegister(to), dbl_scratch);
|
| - } else {
|
| - ASSERT(to->IsDoubleStackSlot());
|
| - // TODO(regis): Why is vstr not taking a MemOperand?
|
| - // __ vstr(dbl_scratch, ToMemOperand(to));
|
| - MemOperand to_operand = ToMemOperand(to);
|
| - __ vstr(dbl_scratch, to_operand.rn(), to_operand.offset());
|
| - }
|
| - } else if (to == &marker_operand) {
|
| - if (from->IsRegister() || from->IsConstantOperand()) {
|
| - __ mov(core_scratch, ToOperand(from));
|
| - destroys_core_scratch = true;
|
| - } else if (from->IsStackSlot()) {
|
| - __ ldr(core_scratch, ToMemOperand(from));
|
| - destroys_core_scratch = true;
|
| - } else if (from->IsDoubleRegister()) {
|
| - __ vmov(dbl_scratch, ToDoubleRegister(from));
|
| - } else {
|
| - ASSERT(from->IsDoubleStackSlot());
|
| - // TODO(regis): Why is vldr not taking a MemOperand?
|
| - // __ vldr(dbl_scratch, ToMemOperand(from));
|
| - MemOperand from_operand = ToMemOperand(from);
|
| - __ vldr(dbl_scratch, from_operand.rn(), from_operand.offset());
|
| - }
|
| - } else if (from->IsConstantOperand()) {
|
| - if (to->IsRegister()) {
|
| - __ mov(ToRegister(to), ToOperand(from));
|
| - } else {
|
| - ASSERT(to->IsStackSlot());
|
| - __ mov(ip, ToOperand(from));
|
| - __ str(ip, ToMemOperand(to));
|
| - }
|
| - } else if (from->IsRegister()) {
|
| - if (to->IsRegister()) {
|
| - __ mov(ToRegister(to), ToOperand(from));
|
| - } else {
|
| - ASSERT(to->IsStackSlot());
|
| - __ str(ToRegister(from), ToMemOperand(to));
|
| - }
|
| - } else if (to->IsRegister()) {
|
| - ASSERT(from->IsStackSlot());
|
| - __ ldr(ToRegister(to), ToMemOperand(from));
|
| - } else if (from->IsStackSlot()) {
|
| - ASSERT(to->IsStackSlot());
|
| - __ ldr(ip, ToMemOperand(from));
|
| - __ str(ip, ToMemOperand(to));
|
| - } else if (from->IsDoubleRegister()) {
|
| - if (to->IsDoubleRegister()) {
|
| - __ vmov(ToDoubleRegister(to), ToDoubleRegister(from));
|
| - } else {
|
| - ASSERT(to->IsDoubleStackSlot());
|
| - // TODO(regis): Why is vstr not taking a MemOperand?
|
| - // __ vstr(dbl_scratch, ToMemOperand(to));
|
| - MemOperand to_operand = ToMemOperand(to);
|
| - __ vstr(ToDoubleRegister(from), to_operand.rn(), to_operand.offset());
|
| - }
|
| - } else if (to->IsDoubleRegister()) {
|
| - ASSERT(from->IsDoubleStackSlot());
|
| - // TODO(regis): Why is vldr not taking a MemOperand?
|
| - // __ vldr(ToDoubleRegister(to), ToMemOperand(from));
|
| - MemOperand from_operand = ToMemOperand(from);
|
| - __ vldr(ToDoubleRegister(to), from_operand.rn(), from_operand.offset());
|
| - } else {
|
| - ASSERT(to->IsDoubleStackSlot() && from->IsDoubleStackSlot());
|
| - // TODO(regis): Why is vldr not taking a MemOperand?
|
| - // __ vldr(dbl_scratch, ToMemOperand(from));
|
| - MemOperand from_operand = ToMemOperand(from);
|
| - __ vldr(dbl_scratch, from_operand.rn(), from_operand.offset());
|
| - // TODO(regis): Why is vstr not taking a MemOperand?
|
| - // __ vstr(dbl_scratch, ToMemOperand(to));
|
| - MemOperand to_operand = ToMemOperand(to);
|
| - __ vstr(dbl_scratch, to_operand.rn(), to_operand.offset());
|
| - }
|
| - }
|
| -
|
| - if (destroys_core_scratch) {
|
| - __ ldr(core_scratch, MemOperand(fp, -kPointerSize));
|
| - }
|
| -
|
| - LInstruction* next = GetNextInstruction();
|
| - if (next != NULL && next->IsLazyBailout()) {
|
| - int pc = masm()->pc_offset();
|
| - safepoints_.SetPcAfterGap(pc);
|
| - }
|
| + resolver_.Resolve(move);
|
| }
|
|
|
|
|
| @@ -940,15 +757,6 @@
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| break;
|
| }
|
| - case CodeStub::StringCharAt: {
|
| - StringCharAtStub stub;
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| - break;
|
| - }
|
| - case CodeStub::MathPow: {
|
| - Abort("MathPowStub unimplemented.");
|
| - break;
|
| - }
|
| case CodeStub::NumberToString: {
|
| NumberToStringStub stub;
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| @@ -966,7 +774,8 @@
|
| }
|
| case CodeStub::TranscendentalCache: {
|
| __ ldr(r0, MemOperand(sp, 0));
|
| - TranscendentalCacheStub stub(instr->transcendental_type());
|
| + TranscendentalCacheStub stub(instr->transcendental_type(),
|
| + TranscendentalCacheStub::TAGGED);
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| break;
|
| }
|
| @@ -982,12 +791,36 @@
|
|
|
|
|
| void LCodeGen::DoModI(LModI* instr) {
|
| + if (instr->hydrogen()->HasPowerOf2Divisor()) {
|
| + Register dividend = ToRegister(instr->InputAt(0));
|
| +
|
| + int32_t divisor =
|
| + HConstant::cast(instr->hydrogen()->right())->Integer32Value();
|
| +
|
| + if (divisor < 0) divisor = -divisor;
|
| +
|
| + Label positive_dividend, done;
|
| + __ tst(dividend, Operand(dividend));
|
| + __ b(pl, &positive_dividend);
|
| + __ rsb(dividend, dividend, Operand(0));
|
| + __ and_(dividend, dividend, Operand(divisor - 1));
|
| + __ rsb(dividend, dividend, Operand(0), SetCC);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + __ b(ne, &done);
|
| + DeoptimizeIf(al, instr->environment());
|
| + }
|
| + __ bind(&positive_dividend);
|
| + __ and_(dividend, dividend, Operand(divisor - 1));
|
| + __ bind(&done);
|
| + return;
|
| + }
|
| +
|
| class DeferredModI: public LDeferredCode {
|
| public:
|
| DeferredModI(LCodeGen* codegen, LModI* instr)
|
| : LDeferredCode(codegen), instr_(instr) { }
|
| virtual void Generate() {
|
| - codegen()->DoDeferredGenericBinaryStub(instr_, Token::MOD);
|
| + codegen()->DoDeferredBinaryOpStub(instr_, Token::MOD);
|
| }
|
| private:
|
| LModI* instr_;
|
| @@ -1016,7 +849,7 @@
|
| __ bind(&ok);
|
| }
|
|
|
| - // Try a few common cases before using the generic stub.
|
| + // Try a few common cases before using the stub.
|
| Label call_stub;
|
| const int kUnfolds = 3;
|
| // Skip if either side is negative.
|
| @@ -1042,9 +875,10 @@
|
| __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
|
| // Perform modulo operation (scratch contains right - 1).
|
| __ and_(result, scratch, Operand(left));
|
| + __ b(&done);
|
|
|
| __ bind(&call_stub);
|
| - // Call the generic stub. The numbers in r0 and r1 have
|
| + // Call the stub. The numbers in r0 and r1 have
|
| // to be tagged to Smis. If that is not possible, deoptimize.
|
| DeferredModI* deferred = new DeferredModI(this, instr);
|
| __ TrySmiTag(left, &deoptimize, scratch);
|
| @@ -1070,7 +904,7 @@
|
| DeferredDivI(LCodeGen* codegen, LDivI* instr)
|
| : LDeferredCode(codegen), instr_(instr) { }
|
| virtual void Generate() {
|
| - codegen()->DoDeferredGenericBinaryStub(instr_, Token::DIV);
|
| + codegen()->DoDeferredBinaryOpStub(instr_, Token::DIV);
|
| }
|
| private:
|
| LDivI* instr_;
|
| @@ -1123,7 +957,7 @@
|
| __ mov(result, Operand(left, ASR, 2), LeaveCC, eq);
|
| __ b(eq, &done);
|
|
|
| - // Call the generic stub. The numbers in r0 and r1 have
|
| + // Call the stub. The numbers in r0 and r1 have
|
| // to be tagged to Smis. If that is not possible, deoptimize.
|
| DeferredDivI* deferred = new DeferredDivI(this, instr);
|
|
|
| @@ -1145,19 +979,33 @@
|
|
|
|
|
| template<int T>
|
| -void LCodeGen::DoDeferredGenericBinaryStub(LTemplateInstruction<1, 2, T>* instr,
|
| - Token::Value op) {
|
| +void LCodeGen::DoDeferredBinaryOpStub(LTemplateInstruction<1, 2, T>* instr,
|
| + Token::Value op) {
|
| Register left = ToRegister(instr->InputAt(0));
|
| Register right = ToRegister(instr->InputAt(1));
|
|
|
| __ PushSafepointRegistersAndDoubles();
|
| - GenericBinaryOpStub stub(op, OVERWRITE_LEFT, left, right);
|
| + // Move left to r1 and right to r0 for the stub call.
|
| + if (left.is(r1)) {
|
| + __ Move(r0, right);
|
| + } else if (left.is(r0) && right.is(r1)) {
|
| + __ Swap(r0, r1, r2);
|
| + } else if (left.is(r0)) {
|
| + ASSERT(!right.is(r1));
|
| + __ mov(r1, r0);
|
| + __ mov(r0, right);
|
| + } else {
|
| + ASSERT(!left.is(r0) && !right.is(r0));
|
| + __ mov(r0, right);
|
| + __ mov(r1, left);
|
| + }
|
| + TypeRecordingBinaryOpStub stub(op, OVERWRITE_LEFT);
|
| __ CallStub(&stub);
|
| RecordSafepointWithRegistersAndDoubles(instr->pointer_map(),
|
| 0,
|
| Safepoint::kNoDeoptimizationIndex);
|
| // Overwrite the stored value of r0 with the result of the stub.
|
| - __ StoreToSafepointRegistersAndDoublesSlot(r0);
|
| + __ StoreToSafepointRegistersAndDoublesSlot(r0, r0);
|
| __ PopSafepointRegistersAndDoubles();
|
| }
|
|
|
| @@ -1322,10 +1170,10 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
|
| +void LCodeGen::DoExternalArrayLength(LExternalArrayLength* instr) {
|
| Register result = ToRegister(instr->result());
|
| Register array = ToRegister(instr->InputAt(0));
|
| - __ ldr(result, FieldMemOperand(array, PixelArray::kLengthOffset));
|
| + __ ldr(result, FieldMemOperand(array, ExternalArray::kLengthOffset));
|
| }
|
|
|
|
|
| @@ -1413,7 +1261,7 @@
|
| __ vmov(r2, r3, right);
|
| __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
|
| // Move the result in the double result register.
|
| - __ vmov(ToDoubleRegister(instr->result()), r0, r1);
|
| + __ GetCFunctionDoubleResult(ToDoubleRegister(instr->result()));
|
|
|
| // Restore r0-r3.
|
| __ ldm(ia_w, sp, r0.bit() | r1.bit() | r2.bit() | r3.bit());
|
| @@ -1431,10 +1279,7 @@
|
| ASSERT(ToRegister(instr->InputAt(1)).is(r0));
|
| ASSERT(ToRegister(instr->result()).is(r0));
|
|
|
| - // TODO(regis): Implement TypeRecordingBinaryOpStub and replace current
|
| - // GenericBinaryOpStub:
|
| - // TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
|
| - GenericBinaryOpStub stub(instr->op(), NO_OVERWRITE, r1, r0);
|
| + TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -1896,6 +1741,19 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
| +
|
| + if (FLAG_debug_code) {
|
| + __ AbortIfNotString(input);
|
| + }
|
| +
|
| + __ ldr(result, FieldMemOperand(input, String::kHashFieldOffset));
|
| + __ IndexFromHash(result, result);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoHasCachedArrayIndex(LHasCachedArrayIndex* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| @@ -1903,10 +1761,10 @@
|
|
|
| ASSERT(instr->hydrogen()->value()->representation().IsTagged());
|
| __ ldr(scratch,
|
| - FieldMemOperand(input, String::kContainsCachedArrayIndexMask));
|
| + FieldMemOperand(input, String::kHashFieldOffset));
|
| __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
|
| - __ LoadRoot(result, Heap::kTrueValueRootIndex, ne);
|
| - __ LoadRoot(result, Heap::kFalseValueRootIndex, eq);
|
| + __ LoadRoot(result, Heap::kTrueValueRootIndex, eq);
|
| + __ LoadRoot(result, Heap::kFalseValueRootIndex, ne);
|
| }
|
|
|
|
|
| @@ -1919,9 +1777,9 @@
|
| int false_block = chunk_->LookupDestination(instr->false_block_id());
|
|
|
| __ ldr(scratch,
|
| - FieldMemOperand(input, String::kContainsCachedArrayIndexMask));
|
| + FieldMemOperand(input, String::kHashFieldOffset));
|
| __ tst(scratch, Operand(String::kContainsCachedArrayIndexMask));
|
| - EmitBranch(true_block, false_block, ne);
|
| + EmitBranch(true_block, false_block, eq);
|
| }
|
|
|
|
|
| @@ -2164,15 +2022,11 @@
|
| __ bind(&before_push_delta);
|
| __ BlockConstPoolFor(kAdditionalDelta);
|
| __ mov(temp, Operand(delta * kPointerSize));
|
| - __ StoreToSafepointRegisterSlot(temp);
|
| - __ Call(stub.GetCode(), RelocInfo::CODE_TARGET);
|
| - ASSERT_EQ(kAdditionalDelta,
|
| - masm_->InstructionsGeneratedSince(&before_push_delta));
|
| - RecordSafepointWithRegisters(
|
| - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| + __ StoreToSafepointRegisterSlot(temp, temp);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| // Put the result value into the result register slot and
|
| // restore all registers.
|
| - __ StoreToSafepointRegisterSlot(result);
|
| + __ StoreToSafepointRegisterSlot(result, result);
|
|
|
| __ PopSafepointRegisters();
|
| }
|
| @@ -2292,17 +2146,13 @@
|
| void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
| Register context = ToRegister(instr->context());
|
| Register result = ToRegister(instr->result());
|
| - __ ldr(result,
|
| - MemOperand(context, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| - __ ldr(result, ContextOperand(result, instr->slot_index()));
|
| + __ ldr(result, ContextOperand(context, instr->slot_index()));
|
| }
|
|
|
|
|
| void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
| Register context = ToRegister(instr->context());
|
| Register value = ToRegister(instr->value());
|
| - __ ldr(context,
|
| - MemOperand(context, Context::SlotOffset(Context::FCONTEXT_INDEX)));
|
| __ str(value, ContextOperand(context, instr->slot_index()));
|
| if (instr->needs_write_barrier()) {
|
| int offset = Context::SlotOffset(instr->slot_index());
|
| @@ -2390,7 +2240,7 @@
|
| __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
| __ cmp(scratch, ip);
|
| __ b(eq, &done);
|
| - __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
|
| + __ LoadRoot(ip, Heap::kExternalPixelArrayMapRootIndex);
|
| __ cmp(scratch, ip);
|
| __ b(eq, &done);
|
| __ LoadRoot(ip, Heap::kFixedCOWArrayMapRootIndex);
|
| @@ -2401,11 +2251,12 @@
|
| }
|
|
|
|
|
| -void LCodeGen::DoLoadPixelArrayExternalPointer(
|
| - LLoadPixelArrayExternalPointer* instr) {
|
| +void LCodeGen::DoLoadExternalArrayPointer(
|
| + LLoadExternalArrayPointer* instr) {
|
| Register to_reg = ToRegister(instr->result());
|
| Register from_reg = ToRegister(instr->InputAt(0));
|
| - __ ldr(to_reg, FieldMemOperand(from_reg, PixelArray::kExternalPointerOffset));
|
| + __ ldr(to_reg, FieldMemOperand(from_reg,
|
| + ExternalArray::kExternalPointerOffset));
|
| }
|
|
|
|
|
| @@ -2446,12 +2297,12 @@
|
|
|
|
|
| void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
|
| - Register external_elements = ToRegister(instr->external_pointer());
|
| + Register external_pointer = ToRegister(instr->external_pointer());
|
| Register key = ToRegister(instr->key());
|
| Register result = ToRegister(instr->result());
|
|
|
| // Load the result.
|
| - __ ldrb(result, MemOperand(external_elements, key));
|
| + __ ldrb(result, MemOperand(external_pointer, key));
|
| }
|
|
|
|
|
| @@ -2621,7 +2472,7 @@
|
| LInstruction* instr) {
|
| // Change context if needed.
|
| bool change_context =
|
| - (graph()->info()->closure()->context() != function->context()) ||
|
| + (info()->closure()->context() != function->context()) ||
|
| scope()->contains_with() ||
|
| (scope()->num_heap_slots() > 0);
|
| if (change_context) {
|
| @@ -2705,7 +2556,7 @@
|
| // Set the pointer to the new heap number in tmp.
|
| if (!tmp1.is(r0)) __ mov(tmp1, Operand(r0));
|
| // Restore input_reg after call to runtime.
|
| - __ LoadFromSafepointRegisterSlot(input);
|
| + __ LoadFromSafepointRegisterSlot(input, input);
|
| __ ldr(exponent, FieldMemOperand(input, HeapNumber::kExponentOffset));
|
|
|
| __ bind(&allocated);
|
| @@ -2716,7 +2567,7 @@
|
| __ ldr(tmp2, FieldMemOperand(input, HeapNumber::kMantissaOffset));
|
| __ str(tmp2, FieldMemOperand(tmp1, HeapNumber::kMantissaOffset));
|
|
|
| - __ str(tmp1, masm()->SafepointRegisterSlot(input));
|
| + __ StoreToSafepointRegisterSlot(tmp1, input);
|
| __ PopSafepointRegisters();
|
|
|
| __ bind(&done);
|
| @@ -2770,41 +2621,6 @@
|
| }
|
|
|
|
|
| -// Truncates a double using a specific rounding mode.
|
| -// Clears the z flag (ne condition) if an overflow occurs.
|
| -void LCodeGen::EmitVFPTruncate(VFPRoundingMode rounding_mode,
|
| - SwVfpRegister result,
|
| - DwVfpRegister double_input,
|
| - Register scratch1,
|
| - Register scratch2) {
|
| - Register prev_fpscr = scratch1;
|
| - Register scratch = scratch2;
|
| -
|
| - // Set custom FPCSR:
|
| - // - Set rounding mode.
|
| - // - Clear vfp cumulative exception flags.
|
| - // - Make sure Flush-to-zero mode control bit is unset.
|
| - __ vmrs(prev_fpscr);
|
| - __ bic(scratch, prev_fpscr, Operand(kVFPExceptionMask |
|
| - kVFPRoundingModeMask |
|
| - kVFPFlushToZeroMask));
|
| - __ orr(scratch, scratch, Operand(rounding_mode));
|
| - __ vmsr(scratch);
|
| -
|
| - // Convert the argument to an integer.
|
| - __ vcvt_s32_f64(result,
|
| - double_input,
|
| - kFPSCRRounding);
|
| -
|
| - // Retrieve FPSCR.
|
| - __ vmrs(scratch);
|
| - // Restore FPSCR.
|
| - __ vmsr(prev_fpscr);
|
| - // Check for vfp exceptions.
|
| - __ tst(scratch, Operand(kVFPExceptionMask));
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
|
| DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| @@ -2812,11 +2628,11 @@
|
| Register scratch1 = scratch0();
|
| Register scratch2 = ToRegister(instr->TempAt(0));
|
|
|
| - EmitVFPTruncate(kRoundToMinusInf,
|
| - single_scratch,
|
| - input,
|
| - scratch1,
|
| - scratch2);
|
| + __ EmitVFPTruncate(kRoundToMinusInf,
|
| + single_scratch,
|
| + input,
|
| + scratch1,
|
| + scratch2);
|
| DeoptimizeIf(ne, instr->environment());
|
|
|
| // Move the result back to general purpose register r0.
|
| @@ -2833,6 +2649,30 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
|
| + DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
| + Register result = ToRegister(instr->result());
|
| + Register scratch1 = scratch0();
|
| + Register scratch2 = result;
|
| + __ EmitVFPTruncate(kRoundToNearest,
|
| + double_scratch0().low(),
|
| + input,
|
| + scratch1,
|
| + scratch2);
|
| + DeoptimizeIf(ne, instr->environment());
|
| + __ vmov(result, double_scratch0().low());
|
| +
|
| + // Test for -0.
|
| + Label done;
|
| + __ cmp(result, Operand(0));
|
| + __ b(ne, &done);
|
| + __ vmov(scratch1, input.high());
|
| + __ tst(scratch1, Operand(HeapNumber::kSignMask));
|
| + DeoptimizeIf(ne, instr->environment());
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoMathSqrt(LUnaryMathOperation* instr) {
|
| DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
| ASSERT(ToDoubleRegister(instr->result()).is(input));
|
| @@ -2840,6 +2680,104 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoMathPowHalf(LUnaryMathOperation* instr) {
|
| + DoubleRegister input = ToDoubleRegister(instr->InputAt(0));
|
| + Register scratch = scratch0();
|
| + SwVfpRegister single_scratch = double_scratch0().low();
|
| + DoubleRegister double_scratch = double_scratch0();
|
| + ASSERT(ToDoubleRegister(instr->result()).is(input));
|
| +
|
| + // Add +0 to convert -0 to +0.
|
| + __ mov(scratch, Operand(0));
|
| + __ vmov(single_scratch, scratch);
|
| + __ vcvt_f64_s32(double_scratch, single_scratch);
|
| + __ vadd(input, input, double_scratch);
|
| + __ vsqrt(input, input);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoPower(LPower* instr) {
|
| + LOperand* left = instr->InputAt(0);
|
| + LOperand* right = instr->InputAt(1);
|
| + Register scratch = scratch0();
|
| + DoubleRegister result_reg = ToDoubleRegister(instr->result());
|
| + Representation exponent_type = instr->hydrogen()->right()->representation();
|
| + if (exponent_type.IsDouble()) {
|
| + // Prepare arguments and call C function.
|
| + __ PrepareCallCFunction(4, scratch);
|
| + __ vmov(r0, r1, ToDoubleRegister(left));
|
| + __ vmov(r2, r3, ToDoubleRegister(right));
|
| + __ CallCFunction(ExternalReference::power_double_double_function(), 4);
|
| + } else if (exponent_type.IsInteger32()) {
|
| + ASSERT(ToRegister(right).is(r0));
|
| + // Prepare arguments and call C function.
|
| + __ PrepareCallCFunction(4, scratch);
|
| + __ mov(r2, ToRegister(right));
|
| + __ vmov(r0, r1, ToDoubleRegister(left));
|
| + __ CallCFunction(ExternalReference::power_double_int_function(), 4);
|
| + } else {
|
| + ASSERT(exponent_type.IsTagged());
|
| + ASSERT(instr->hydrogen()->left()->representation().IsDouble());
|
| +
|
| + Register right_reg = ToRegister(right);
|
| +
|
| + // Check for smi on the right hand side.
|
| + Label non_smi, call;
|
| + __ JumpIfNotSmi(right_reg, &non_smi);
|
| +
|
| + // Untag smi and convert it to a double.
|
| + __ SmiUntag(right_reg);
|
| + SwVfpRegister single_scratch = double_scratch0().low();
|
| + __ vmov(single_scratch, right_reg);
|
| + __ vcvt_f64_s32(result_reg, single_scratch);
|
| + __ jmp(&call);
|
| +
|
| + // Heap number map check.
|
| + __ bind(&non_smi);
|
| + __ ldr(scratch, FieldMemOperand(right_reg, HeapObject::kMapOffset));
|
| + __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
|
| + __ cmp(scratch, Operand(ip));
|
| + DeoptimizeIf(ne, instr->environment());
|
| + int32_t value_offset = HeapNumber::kValueOffset - kHeapObjectTag;
|
| + __ add(scratch, right_reg, Operand(value_offset));
|
| + __ vldr(result_reg, scratch, 0);
|
| +
|
| + // Prepare arguments and call C function.
|
| + __ bind(&call);
|
| + __ PrepareCallCFunction(4, scratch);
|
| + __ vmov(r0, r1, ToDoubleRegister(left));
|
| + __ vmov(r2, r3, result_reg);
|
| + __ CallCFunction(ExternalReference::power_double_double_function(), 4);
|
| + }
|
| + // Store the result in the result register.
|
| + __ GetCFunctionDoubleResult(result_reg);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
|
| + ASSERT(ToDoubleRegister(instr->result()).is(d2));
|
| + TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
| + TranscendentalCacheStub::UNTAGGED);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
|
| + ASSERT(ToDoubleRegister(instr->result()).is(d2));
|
| + TranscendentalCacheStub stub(TranscendentalCache::COS,
|
| + TranscendentalCacheStub::UNTAGGED);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
|
| + ASSERT(ToDoubleRegister(instr->result()).is(d2));
|
| + TranscendentalCacheStub stub(TranscendentalCache::SIN,
|
| + TranscendentalCacheStub::UNTAGGED);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
|
| switch (instr->op()) {
|
| case kMathAbs:
|
| @@ -2848,9 +2786,24 @@
|
| case kMathFloor:
|
| DoMathFloor(instr);
|
| break;
|
| + case kMathRound:
|
| + DoMathRound(instr);
|
| + break;
|
| case kMathSqrt:
|
| DoMathSqrt(instr);
|
| break;
|
| + case kMathPowHalf:
|
| + DoMathPowHalf(instr);
|
| + break;
|
| + case kMathCos:
|
| + DoMathCos(instr);
|
| + break;
|
| + case kMathSin:
|
| + DoMathSin(instr);
|
| + break;
|
| + case kMathLog:
|
| + DoMathLog(instr);
|
| + break;
|
| default:
|
| Abort("Unimplemented type of LUnaryMathOperation.");
|
| UNREACHABLE();
|
| @@ -2962,9 +2915,9 @@
|
|
|
| // Name is always in r2.
|
| __ mov(r2, Operand(instr->name()));
|
| - Handle<Code> ic(Builtins::builtin(info_->is_strict()
|
| - ? Builtins::StoreIC_Initialize_Strict
|
| - : Builtins::StoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -3001,12 +2954,25 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
|
| + Register external_pointer = ToRegister(instr->external_pointer());
|
| + Register key = ToRegister(instr->key());
|
| + Register value = ToRegister(instr->value());
|
| +
|
| + // Clamp the value to [0..255].
|
| + __ Usat(value, 8, Operand(value));
|
| + __ strb(value, MemOperand(external_pointer, key, LSL, 0));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
|
| ASSERT(ToRegister(instr->object()).is(r2));
|
| ASSERT(ToRegister(instr->key()).is(r1));
|
| ASSERT(ToRegister(instr->value()).is(r0));
|
|
|
| - Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
|
| + Handle<Code> ic(Builtins::builtin(
|
| + info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -3147,12 +3113,61 @@
|
| __ AbortIfNotSmi(r0);
|
| }
|
| __ SmiUntag(r0);
|
| - MemOperand result_stack_slot = masm()->SafepointRegisterSlot(result);
|
| - __ str(r0, result_stack_slot);
|
| + __ StoreToSafepointRegisterSlot(r0, result);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
|
|
| +void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
|
| + class DeferredStringCharFromCode: public LDeferredCode {
|
| + public:
|
| + DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
|
| + : LDeferredCode(codegen), instr_(instr) { }
|
| + virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
|
| + private:
|
| + LStringCharFromCode* instr_;
|
| + };
|
| +
|
| + DeferredStringCharFromCode* deferred =
|
| + new DeferredStringCharFromCode(this, instr);
|
| +
|
| + ASSERT(instr->hydrogen()->value()->representation().IsInteger32());
|
| + Register char_code = ToRegister(instr->char_code());
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(!char_code.is(result));
|
| +
|
| + __ cmp(char_code, Operand(String::kMaxAsciiCharCode));
|
| + __ b(hi, deferred->entry());
|
| + __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
|
| + __ add(result, result, Operand(char_code, LSL, kPointerSizeLog2));
|
| + __ ldr(result, FieldMemOperand(result, FixedArray::kHeaderSize));
|
| + __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| + __ cmp(result, ip);
|
| + __ b(eq, deferred->entry());
|
| + __ bind(deferred->exit());
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
|
| + Register char_code = ToRegister(instr->char_code());
|
| + Register result = ToRegister(instr->result());
|
| +
|
| + // TODO(3095996): Get rid of this. For now, we need to make the
|
| + // result register contain a valid pointer because it is already
|
| + // contained in the register pointer map.
|
| + __ mov(result, Operand(0));
|
| +
|
| + __ PushSafepointRegisters();
|
| + __ SmiTag(char_code);
|
| + __ push(char_code);
|
| + __ CallRuntimeSaveDoubles(Runtime::kCharFromCode);
|
| + RecordSafepointWithRegisters(
|
| + instr->pointer_map(), 1, Safepoint::kNoDeoptimizationIndex);
|
| + __ StoreToSafepointRegisterSlot(r0, result);
|
| + __ PopSafepointRegisters();
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoStringLength(LStringLength* instr) {
|
| Register string = ToRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| @@ -3229,9 +3244,7 @@
|
| // register is stored, as this register is in the pointer map, but contains an
|
| // integer value.
|
| __ mov(ip, Operand(0));
|
| - int reg_stack_index = __ SafepointRegisterStackIndex(reg.code());
|
| - __ str(ip, MemOperand(sp, reg_stack_index * kPointerSize));
|
| -
|
| + __ StoreToSafepointRegisterSlot(ip, reg);
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| @@ -3242,7 +3255,7 @@
|
| __ bind(&done);
|
| __ sub(ip, reg, Operand(kHeapObjectTag));
|
| __ vstr(dbl_scratch, ip, HeapNumber::kValueOffset);
|
| - __ str(reg, MemOperand(sp, reg_stack_index * kPointerSize));
|
| + __ StoreToSafepointRegisterSlot(reg, reg);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -3287,8 +3300,7 @@
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| - int reg_stack_index = __ SafepointRegisterStackIndex(reg.code());
|
| - __ str(r0, MemOperand(sp, reg_stack_index * kPointerSize));
|
| + __ StoreToSafepointRegisterSlot(r0, reg);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -3368,19 +3380,30 @@
|
|
|
|
|
| void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
|
| - Label done;
|
| Register input_reg = ToRegister(instr->InputAt(0));
|
| - Register scratch = scratch0();
|
| - DoubleRegister dbl_scratch = d0;
|
| - SwVfpRegister flt_scratch = s0;
|
| - DoubleRegister dbl_tmp = ToDoubleRegister(instr->TempAt(0));
|
| + Register scratch1 = scratch0();
|
| + Register scratch2 = ToRegister(instr->TempAt(0));
|
| + DwVfpRegister double_scratch = double_scratch0();
|
| + SwVfpRegister single_scratch = double_scratch.low();
|
|
|
| + ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
|
| + ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
|
| +
|
| + Label done;
|
| +
|
| // Heap number map check.
|
| - __ ldr(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset));
|
| + __ ldr(scratch1, FieldMemOperand(input_reg, HeapObject::kMapOffset));
|
| __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
|
| - __ cmp(scratch, Operand(ip));
|
| + __ cmp(scratch1, Operand(ip));
|
|
|
| if (instr->truncating()) {
|
| + Register scratch3 = ToRegister(instr->TempAt(1));
|
| + DwVfpRegister double_scratch2 = ToDoubleRegister(instr->TempAt(2));
|
| + ASSERT(!scratch3.is(input_reg) &&
|
| + !scratch3.is(scratch1) &&
|
| + !scratch3.is(scratch2));
|
| + // Performs a truncating conversion of a floating point number as used by
|
| + // the JS bitwise operations.
|
| Label heap_number;
|
| __ b(eq, &heap_number);
|
| // Check for undefined. Undefined is converted to zero for truncating
|
| @@ -3392,36 +3415,38 @@
|
| __ b(&done);
|
|
|
| __ bind(&heap_number);
|
| - __ sub(ip, input_reg, Operand(kHeapObjectTag));
|
| - __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset);
|
| - __ vcmp(dbl_tmp, 0.0); // Sets overflow bit in FPSCR flags if NaN.
|
| - __ vcvt_s32_f64(flt_scratch, dbl_tmp);
|
| - __ vmov(input_reg, flt_scratch); // 32-bit result of conversion.
|
| - __ vmrs(pc); // Move vector status bits to normal status bits.
|
| - // Overflow bit is set if dbl_tmp is Nan.
|
| - __ cmn(input_reg, Operand(1), vc); // 0x7fffffff + 1 -> overflow.
|
| - __ cmp(input_reg, Operand(1), vc); // 0x80000000 - 1 -> overflow.
|
| - DeoptimizeIf(vs, instr->environment()); // Saturation may have occured.
|
| + __ sub(scratch1, input_reg, Operand(kHeapObjectTag));
|
| + __ vldr(double_scratch2, scratch1, HeapNumber::kValueOffset);
|
|
|
| + __ EmitECMATruncate(input_reg,
|
| + double_scratch2,
|
| + single_scratch,
|
| + scratch1,
|
| + scratch2,
|
| + scratch3);
|
| +
|
| } else {
|
| + CpuFeatures::Scope scope(VFP3);
|
| // Deoptimize if we don't have a heap number.
|
| DeoptimizeIf(ne, instr->environment());
|
|
|
| __ sub(ip, input_reg, Operand(kHeapObjectTag));
|
| - __ vldr(dbl_tmp, ip, HeapNumber::kValueOffset);
|
| - __ vcvt_s32_f64(flt_scratch, dbl_tmp);
|
| - __ vmov(input_reg, flt_scratch); // 32-bit result of conversion.
|
| - // Non-truncating conversion means that we cannot lose bits, so we convert
|
| - // back to check; note that using non-overlapping s and d regs would be
|
| - // slightly faster.
|
| - __ vcvt_f64_s32(dbl_scratch, flt_scratch);
|
| - __ VFPCompareAndSetFlags(dbl_scratch, dbl_tmp);
|
| - DeoptimizeIf(ne, instr->environment()); // Not equal or unordered.
|
| + __ vldr(double_scratch, ip, HeapNumber::kValueOffset);
|
| + __ EmitVFPTruncate(kRoundToZero,
|
| + single_scratch,
|
| + double_scratch,
|
| + scratch1,
|
| + scratch2,
|
| + kCheckForInexactConversion);
|
| + DeoptimizeIf(ne, instr->environment());
|
| + // Load the result.
|
| + __ vmov(input_reg, single_scratch);
|
| +
|
| if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - __ tst(input_reg, Operand(input_reg));
|
| + __ cmp(input_reg, Operand(0));
|
| __ b(ne, &done);
|
| - __ vmov(lr, ip, dbl_tmp);
|
| - __ tst(ip, Operand(1 << 31)); // Test sign bit.
|
| + __ vmov(scratch1, double_scratch.high());
|
| + __ tst(scratch1, Operand(HeapNumber::kSignMask));
|
| DeoptimizeIf(ne, instr->environment());
|
| }
|
| }
|
| @@ -3463,42 +3488,38 @@
|
|
|
|
|
| void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
|
| - LOperand* input = instr->InputAt(0);
|
| - ASSERT(input->IsDoubleRegister());
|
| - LOperand* result = instr->result();
|
| - ASSERT(result->IsRegister());
|
| -
|
| - DoubleRegister double_input = ToDoubleRegister(input);
|
| - Register result_reg = ToRegister(result);
|
| - SwVfpRegister single_scratch = double_scratch0().low();
|
| + Register result_reg = ToRegister(instr->result());
|
| Register scratch1 = scratch0();
|
| Register scratch2 = ToRegister(instr->TempAt(0));
|
| + DwVfpRegister double_input = ToDoubleRegister(instr->InputAt(0));
|
| + DwVfpRegister double_scratch = double_scratch0();
|
| + SwVfpRegister single_scratch = double_scratch0().low();
|
|
|
| - VFPRoundingMode rounding_mode = instr->truncating() ? kRoundToMinusInf
|
| - : kRoundToNearest;
|
| + Label done;
|
|
|
| - EmitVFPTruncate(rounding_mode,
|
| - single_scratch,
|
| - double_input,
|
| - scratch1,
|
| - scratch2);
|
| - // Deoptimize if we had a vfp invalid exception.
|
| - DeoptimizeIf(ne, instr->environment());
|
| - // Retrieve the result.
|
| - __ vmov(result_reg, single_scratch);
|
| -
|
| - if (instr->truncating() &&
|
| - instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - Label done;
|
| - __ cmp(result_reg, Operand(0));
|
| - __ b(ne, &done);
|
| - // Check for -0.
|
| - __ vmov(scratch1, double_input.high());
|
| - __ tst(scratch1, Operand(HeapNumber::kSignMask));
|
| + if (instr->truncating()) {
|
| + Register scratch3 = ToRegister(instr->TempAt(1));
|
| + __ EmitECMATruncate(result_reg,
|
| + double_input,
|
| + single_scratch,
|
| + scratch1,
|
| + scratch2,
|
| + scratch3);
|
| + } else {
|
| + VFPRoundingMode rounding_mode = kRoundToMinusInf;
|
| + __ EmitVFPTruncate(rounding_mode,
|
| + single_scratch,
|
| + double_input,
|
| + scratch1,
|
| + scratch2,
|
| + kCheckForInexactConversion);
|
| + // Deoptimize if we had a vfp invalid exception,
|
| + // including inexact operation.
|
| DeoptimizeIf(ne, instr->environment());
|
| -
|
| + // Retrieve the result.
|
| + __ vmov(result_reg, single_scratch);
|
| + }
|
| __ bind(&done);
|
| - }
|
| }
|
|
|
|
|
| @@ -3768,37 +3789,30 @@
|
| Condition final_branch_condition = kNoCondition;
|
| Register scratch = scratch0();
|
| if (type_name->Equals(Heap::number_symbol())) {
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, true_label);
|
| + __ JumpIfSmi(input, true_label);
|
| __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
|
| __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
|
| __ cmp(input, Operand(ip));
|
| final_branch_condition = eq;
|
|
|
| } else if (type_name->Equals(Heap::string_symbol())) {
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, false_label);
|
| - __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
|
| + __ JumpIfSmi(input, false_label);
|
| + __ CompareObjectType(input, input, scratch, FIRST_NONSTRING_TYPE);
|
| + __ b(ge, false_label);
|
| __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
|
| __ tst(ip, Operand(1 << Map::kIsUndetectable));
|
| - __ b(ne, false_label);
|
| - __ CompareInstanceType(input, scratch, FIRST_NONSTRING_TYPE);
|
| - final_branch_condition = lo;
|
| + final_branch_condition = eq;
|
|
|
| } else if (type_name->Equals(Heap::boolean_symbol())) {
|
| - __ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
| - __ cmp(input, ip);
|
| + __ CompareRoot(input, Heap::kTrueValueRootIndex);
|
| __ b(eq, true_label);
|
| - __ LoadRoot(ip, Heap::kFalseValueRootIndex);
|
| - __ cmp(input, ip);
|
| + __ CompareRoot(input, Heap::kFalseValueRootIndex);
|
| final_branch_condition = eq;
|
|
|
| } else if (type_name->Equals(Heap::undefined_symbol())) {
|
| - __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
| - __ cmp(input, ip);
|
| + __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
|
| __ b(eq, true_label);
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, false_label);
|
| + __ JumpIfSmi(input, false_label);
|
| // Check for undetectable objects => true.
|
| __ ldr(input, FieldMemOperand(input, HeapObject::kMapOffset));
|
| __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
|
| @@ -3806,32 +3820,22 @@
|
| final_branch_condition = ne;
|
|
|
| } else if (type_name->Equals(Heap::function_symbol())) {
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, false_label);
|
| - __ CompareObjectType(input, input, scratch, JS_FUNCTION_TYPE);
|
| - __ b(eq, true_label);
|
| - // Regular expressions => 'function' (they are callable).
|
| - __ CompareInstanceType(input, scratch, JS_REGEXP_TYPE);
|
| - final_branch_condition = eq;
|
| + __ JumpIfSmi(input, false_label);
|
| + __ CompareObjectType(input, input, scratch, FIRST_FUNCTION_CLASS_TYPE);
|
| + final_branch_condition = ge;
|
|
|
| } else if (type_name->Equals(Heap::object_symbol())) {
|
| - __ tst(input, Operand(kSmiTagMask));
|
| - __ b(eq, false_label);
|
| - __ LoadRoot(ip, Heap::kNullValueRootIndex);
|
| - __ cmp(input, ip);
|
| + __ JumpIfSmi(input, false_label);
|
| + __ CompareRoot(input, Heap::kNullValueRootIndex);
|
| __ b(eq, true_label);
|
| - // Regular expressions => 'function', not 'object'.
|
| - __ CompareObjectType(input, input, scratch, JS_REGEXP_TYPE);
|
| - __ b(eq, false_label);
|
| + __ CompareObjectType(input, input, scratch, FIRST_JS_OBJECT_TYPE);
|
| + __ b(lo, false_label);
|
| + __ CompareInstanceType(input, scratch, FIRST_FUNCTION_CLASS_TYPE);
|
| + __ b(hs, false_label);
|
| // Check for undetectable objects => false.
|
| __ ldrb(ip, FieldMemOperand(input, Map::kBitFieldOffset));
|
| __ tst(ip, Operand(1 << Map::kIsUndetectable));
|
| - __ b(ne, false_label);
|
| - // Check for JS objects => true.
|
| - __ CompareInstanceType(input, scratch, FIRST_JS_OBJECT_TYPE);
|
| - __ b(lo, false_label);
|
| - __ CompareInstanceType(input, scratch, LAST_JS_OBJECT_TYPE);
|
| - final_branch_condition = ls;
|
| + final_branch_condition = eq;
|
|
|
| } else {
|
| final_branch_condition = ne;
|
|
|