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