LCOV - code coverage report
Current view: top level - js/src/jit/x64 - MacroAssembler-x64.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 173 474 36.5 %
Date: 2017-07-14 16:53:18 Functions: 18 41 43.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  * vim: set ts=8 sts=4 et sw=4 tw=99:
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "jit/x64/MacroAssembler-x64.h"
       8             : 
       9             : #include "jit/Bailouts.h"
      10             : #include "jit/BaselineFrame.h"
      11             : #include "jit/JitCompartment.h"
      12             : #include "jit/JitFrames.h"
      13             : #include "jit/MacroAssembler.h"
      14             : #include "jit/MoveEmitter.h"
      15             : 
      16             : #include "jit/MacroAssembler-inl.h"
      17             : 
      18             : using namespace js;
      19             : using namespace js::jit;
      20             : 
      21             : void
      22           0 : MacroAssemblerX64::loadConstantDouble(double d, FloatRegister dest)
      23             : {
      24           0 :     if (maybeInlineDouble(d, dest))
      25           0 :         return;
      26           0 :     Double* dbl = getDouble(d);
      27           0 :     if (!dbl)
      28           0 :         return;
      29             :     // The constants will be stored in a pool appended to the text (see
      30             :     // finish()), so they will always be a fixed distance from the
      31             :     // instructions which reference them. This allows the instructions to use
      32             :     // PC-relative addressing. Use "jump" label support code, because we need
      33             :     // the same PC-relative address patching that jumps use.
      34           0 :     JmpSrc j = masm.vmovsd_ripr(dest.encoding());
      35           0 :     propagateOOM(dbl->uses.append(CodeOffset(j.offset())));
      36             : }
      37             : 
      38             : void
      39           0 : MacroAssemblerX64::loadConstantFloat32(float f, FloatRegister dest)
      40             : {
      41           0 :     if (maybeInlineFloat(f, dest))
      42           0 :         return;
      43           0 :     Float* flt = getFloat(f);
      44           0 :     if (!flt)
      45           0 :         return;
      46             :     // See comment in loadConstantDouble
      47           0 :     JmpSrc j = masm.vmovss_ripr(dest.encoding());
      48           0 :     propagateOOM(flt->uses.append(CodeOffset(j.offset())));
      49             : }
      50             : 
      51             : void
      52           0 : MacroAssemblerX64::loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest)
      53             : {
      54           0 :     if (maybeInlineSimd128Int(v, dest))
      55           0 :         return;
      56           0 :     SimdData* val = getSimdData(v);
      57           0 :     if (!val)
      58           0 :         return;
      59           0 :     JmpSrc j = masm.vmovdqa_ripr(dest.encoding());
      60           0 :     propagateOOM(val->uses.append(CodeOffset(j.offset())));
      61             : }
      62             : 
      63             : void
      64           0 : MacroAssemblerX64::loadConstantSimd128Float(const SimdConstant&v, FloatRegister dest)
      65             : {
      66           0 :     if (maybeInlineSimd128Float(v, dest))
      67           0 :         return;
      68           0 :     SimdData* val = getSimdData(v);
      69           0 :     if (!val)
      70           0 :         return;
      71           0 :     JmpSrc j = masm.vmovaps_ripr(dest.encoding());
      72           0 :     propagateOOM(val->uses.append(CodeOffset(j.offset())));
      73             : }
      74             : 
      75             : void
      76           0 : MacroAssemblerX64::convertInt64ToDouble(Register64 input, FloatRegister output)
      77             : {
      78             :     // Zero the output register to break dependencies, see convertInt32ToDouble.
      79           0 :     zeroDouble(output);
      80             : 
      81           0 :     vcvtsq2sd(input.reg, output, output);
      82           0 : }
      83             : 
      84             : void
      85           0 : MacroAssemblerX64::convertInt64ToFloat32(Register64 input, FloatRegister output)
      86             : {
      87             :     // Zero the output register to break dependencies, see convertInt32ToDouble.
      88           0 :     zeroFloat32(output);
      89             : 
      90           0 :     vcvtsq2ss(input.reg, output, output);
      91           0 : }
      92             : 
      93             : bool
      94           0 : MacroAssemblerX64::convertUInt64ToDoubleNeedsTemp()
      95             : {
      96           0 :     return true;
      97             : }
      98             : 
      99             : void
     100           0 : MacroAssemblerX64::convertUInt64ToDouble(Register64 input, FloatRegister output, Register temp)
     101             : {
     102             :     // Zero the output register to break dependencies, see convertInt32ToDouble.
     103           0 :     zeroDouble(output);
     104             : 
     105             :     // If the input's sign bit is not set we use vcvtsq2sd directly.
     106             :     // Else, we divide by 2 and keep the LSB, convert to double, and multiply
     107             :     // the result by 2.
     108           0 :     Label done;
     109           0 :     Label isSigned;
     110             : 
     111           0 :     testq(input.reg, input.reg);
     112           0 :     j(Assembler::Signed, &isSigned);
     113           0 :     vcvtsq2sd(input.reg, output, output);
     114           0 :     jump(&done);
     115             : 
     116           0 :     bind(&isSigned);
     117             : 
     118           0 :     ScratchRegisterScope scratch(asMasm());
     119           0 :     mov(input.reg, scratch);
     120           0 :     mov(input.reg, temp);
     121           0 :     shrq(Imm32(1), scratch);
     122           0 :     andq(Imm32(1), temp);
     123           0 :     orq(temp, scratch);
     124             : 
     125           0 :     vcvtsq2sd(scratch, output, output);
     126           0 :     vaddsd(output, output, output);
     127             : 
     128           0 :     bind(&done);
     129           0 : }
     130             : 
     131             : void
     132           0 : MacroAssemblerX64::convertUInt64ToFloat32(Register64 input, FloatRegister output, Register temp)
     133             : {
     134             :     // Zero the output register to break dependencies, see convertInt32ToDouble.
     135           0 :     zeroFloat32(output);
     136             : 
     137             :     // See comment in convertUInt64ToDouble.
     138           0 :     Label done;
     139           0 :     Label isSigned;
     140             : 
     141           0 :     testq(input.reg, input.reg);
     142           0 :     j(Assembler::Signed, &isSigned);
     143           0 :     vcvtsq2ss(input.reg, output, output);
     144           0 :     jump(&done);
     145             : 
     146           0 :     bind(&isSigned);
     147             : 
     148           0 :     ScratchRegisterScope scratch(asMasm());
     149           0 :     mov(input.reg, scratch);
     150           0 :     mov(input.reg, temp);
     151           0 :     shrq(Imm32(1), scratch);
     152           0 :     andq(Imm32(1), temp);
     153           0 :     orq(temp, scratch);
     154             : 
     155           0 :     vcvtsq2ss(scratch, output, output);
     156           0 :     vaddss(output, output, output);
     157             : 
     158           0 :     bind(&done);
     159           0 : }
     160             : 
     161             : void
     162           0 : MacroAssemblerX64::wasmTruncateDoubleToInt64(FloatRegister input, Register64 output, Label* oolEntry,
     163             :                                              Label* oolRejoin, FloatRegister tempReg)
     164             : {
     165           0 :     vcvttsd2sq(input, output.reg);
     166           0 :     cmpq(Imm32(1), output.reg);
     167           0 :     j(Assembler::Overflow, oolEntry);
     168           0 :     bind(oolRejoin);
     169           0 : }
     170             : 
     171             : void
     172           0 : MacroAssemblerX64::wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output, Label* oolEntry,
     173             :                                               Label* oolRejoin, FloatRegister tempReg)
     174             : {
     175           0 :     vcvttss2sq(input, output.reg);
     176           0 :     cmpq(Imm32(1), output.reg);
     177           0 :     j(Assembler::Overflow, oolEntry);
     178           0 :     bind(oolRejoin);
     179           0 : }
     180             : 
     181             : void
     182           0 : MacroAssemblerX64::wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
     183             :                                               Label* oolRejoin, FloatRegister tempReg)
     184             : {
     185             :     // If the input < INT64_MAX, vcvttsd2sq will do the right thing, so
     186             :     // we use it directly. Else, we subtract INT64_MAX, convert to int64,
     187             :     // and then add INT64_MAX to the result.
     188             : 
     189           0 :     Label isLarge;
     190             : 
     191           0 :     ScratchDoubleScope scratch(asMasm());
     192           0 :     loadConstantDouble(double(0x8000000000000000), scratch);
     193           0 :     asMasm().branchDouble(Assembler::DoubleGreaterThanOrEqual, input, scratch, &isLarge);
     194           0 :     vcvttsd2sq(input, output.reg);
     195           0 :     testq(output.reg, output.reg);
     196           0 :     j(Assembler::Signed, oolEntry);
     197           0 :     jump(oolRejoin);
     198             : 
     199           0 :     bind(&isLarge);
     200             : 
     201           0 :     moveDouble(input, tempReg);
     202           0 :     vsubsd(scratch, tempReg, tempReg);
     203           0 :     vcvttsd2sq(tempReg, output.reg);
     204           0 :     testq(output.reg, output.reg);
     205           0 :     j(Assembler::Signed, oolEntry);
     206           0 :     asMasm().or64(Imm64(0x8000000000000000), output);
     207             : 
     208           0 :     bind(oolRejoin);
     209           0 : }
     210             : 
     211             : void
     212           0 : MacroAssemblerX64::wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output, Label* oolEntry,
     213             :                                                Label* oolRejoin, FloatRegister tempReg)
     214             : {
     215             :     // If the input < INT64_MAX, vcvttss2sq will do the right thing, so
     216             :     // we use it directly. Else, we subtract INT64_MAX, convert to int64,
     217             :     // and then add INT64_MAX to the result.
     218             : 
     219           0 :     Label isLarge;
     220             : 
     221           0 :     ScratchFloat32Scope scratch(asMasm());
     222           0 :     loadConstantFloat32(float(0x8000000000000000), scratch);
     223           0 :     asMasm().branchFloat(Assembler::DoubleGreaterThanOrEqual, input, scratch, &isLarge);
     224           0 :     vcvttss2sq(input, output.reg);
     225           0 :     testq(output.reg, output.reg);
     226           0 :     j(Assembler::Signed, oolEntry);
     227           0 :     jump(oolRejoin);
     228             : 
     229           0 :     bind(&isLarge);
     230             : 
     231           0 :     moveFloat32(input, tempReg);
     232           0 :     vsubss(scratch, tempReg, tempReg);
     233           0 :     vcvttss2sq(tempReg, output.reg);
     234           0 :     testq(output.reg, output.reg);
     235           0 :     j(Assembler::Signed, oolEntry);
     236           0 :     asMasm().or64(Imm64(0x8000000000000000), output);
     237             : 
     238           0 :     bind(oolRejoin);
     239           0 : }
     240             : 
     241             : void
     242           0 : MacroAssemblerX64::bindOffsets(const MacroAssemblerX86Shared::UsesVector& uses)
     243             : {
     244           0 :     for (CodeOffset use : uses) {
     245           0 :         JmpDst dst(currentOffset());
     246           0 :         JmpSrc src(use.offset());
     247             :         // Using linkJump here is safe, as explaind in the comment in
     248             :         // loadConstantDouble.
     249           0 :         masm.linkJump(src, dst);
     250             :     }
     251           0 : }
     252             : 
     253             : void
     254        4499 : MacroAssemblerX64::finish()
     255             : {
     256        4499 :     if (!doubles_.empty())
     257           0 :         masm.haltingAlign(sizeof(double));
     258        4499 :     for (const Double& d : doubles_) {
     259           0 :         bindOffsets(d.uses);
     260           0 :         masm.doubleConstant(d.value);
     261             :     }
     262             : 
     263        4499 :     if (!floats_.empty())
     264           0 :         masm.haltingAlign(sizeof(float));
     265        4499 :     for (const Float& f : floats_) {
     266           0 :         bindOffsets(f.uses);
     267           0 :         masm.floatConstant(f.value);
     268             :     }
     269             : 
     270             :     // SIMD memory values must be suitably aligned.
     271        4499 :     if (!simds_.empty())
     272           0 :         masm.haltingAlign(SimdMemoryAlignment);
     273        4499 :     for (const SimdData& v : simds_) {
     274           0 :         bindOffsets(v.uses);
     275           0 :         masm.simd128Constant(v.value.bytes());
     276             :     }
     277             : 
     278        4499 :     MacroAssemblerX86Shared::finish();
     279        4499 : }
     280             : 
     281             : void
     282         394 : MacroAssemblerX64::boxValue(JSValueType type, Register src, Register dest)
     283             : {
     284         394 :     MOZ_ASSERT(src != dest);
     285             : 
     286         394 :     JSValueShiftedTag tag = (JSValueShiftedTag)JSVAL_TYPE_TO_SHIFTED_TAG(type);
     287             : #ifdef DEBUG
     288         394 :     if (type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN) {
     289         456 :         Label upper32BitsZeroed;
     290         228 :         movePtr(ImmWord(UINT32_MAX), dest);
     291         228 :         asMasm().branchPtr(Assembler::BelowOrEqual, src, dest, &upper32BitsZeroed);
     292         228 :         breakpoint();
     293         228 :         bind(&upper32BitsZeroed);
     294             :     }
     295             : #endif
     296         394 :     mov(ImmShiftedTag(tag), dest);
     297         394 :     orq(src, dest);
     298         394 : }
     299             : 
     300             : void
     301           4 : MacroAssemblerX64::handleFailureWithHandlerTail(void* handler)
     302             : {
     303             :     // Reserve space for exception information.
     304           4 :     subq(Imm32(sizeof(ResumeFromException)), rsp);
     305           4 :     movq(rsp, rax);
     306             : 
     307             :     // Call the handler.
     308           4 :     asMasm().setupUnalignedABICall(rcx);
     309           4 :     asMasm().passABIArg(rax);
     310           4 :     asMasm().callWithABI(handler);
     311             : 
     312           8 :     Label entryFrame;
     313           8 :     Label catch_;
     314           8 :     Label finally;
     315           8 :     Label return_;
     316           8 :     Label bailout;
     317             : 
     318           4 :     load32(Address(rsp, offsetof(ResumeFromException, kind)), rax);
     319           4 :     asMasm().branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_ENTRY_FRAME), &entryFrame);
     320           4 :     asMasm().branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_CATCH), &catch_);
     321           4 :     asMasm().branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_FINALLY), &finally);
     322           4 :     asMasm().branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_FORCED_RETURN), &return_);
     323           4 :     asMasm().branch32(Assembler::Equal, rax, Imm32(ResumeFromException::RESUME_BAILOUT), &bailout);
     324             : 
     325           4 :     breakpoint(); // Invalid kind.
     326             : 
     327             :     // No exception handler. Load the error value, load the new stack pointer
     328             :     // and return from the entry frame.
     329           4 :     bind(&entryFrame);
     330           4 :     moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
     331           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, stackPointer)), rsp);
     332           4 :     ret();
     333             : 
     334             :     // If we found a catch handler, this must be a baseline frame. Restore state
     335             :     // and jump to the catch block.
     336           4 :     bind(&catch_);
     337           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, target)), rax);
     338           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, framePointer)), rbp);
     339           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, stackPointer)), rsp);
     340           4 :     jmp(Operand(rax));
     341             : 
     342             :     // If we found a finally block, this must be a baseline frame. Push
     343             :     // two values expected by JSOP_RETSUB: BooleanValue(true) and the
     344             :     // exception.
     345           4 :     bind(&finally);
     346           4 :     ValueOperand exception = ValueOperand(rcx);
     347           4 :     loadValue(Address(esp, offsetof(ResumeFromException, exception)), exception);
     348             : 
     349           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, target)), rax);
     350           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, framePointer)), rbp);
     351           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, stackPointer)), rsp);
     352             : 
     353           4 :     pushValue(BooleanValue(true));
     354           4 :     pushValue(exception);
     355           4 :     jmp(Operand(rax));
     356             : 
     357             :     // Only used in debug mode. Return BaselineFrame->returnValue() to the caller.
     358           4 :     bind(&return_);
     359           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, framePointer)), rbp);
     360           4 :     loadPtr(Address(rsp, offsetof(ResumeFromException, stackPointer)), rsp);
     361           4 :     loadValue(Address(rbp, BaselineFrame::reverseOffsetOfReturnValue()), JSReturnOperand);
     362           4 :     movq(rbp, rsp);
     363           4 :     pop(rbp);
     364             : 
     365             :     // If profiling is enabled, then update the lastProfilingFrame to refer to caller
     366             :     // frame before returning.
     367             :     {
     368           8 :         Label skipProfilingInstrumentation;
     369           4 :         AbsoluteAddress addressOfEnabled(GetJitContext()->runtime->geckoProfiler().addressOfEnabled());
     370           4 :         asMasm().branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skipProfilingInstrumentation);
     371           4 :         profilerExitFrame();
     372           4 :         bind(&skipProfilingInstrumentation);
     373             :     }
     374             : 
     375           4 :     ret();
     376             : 
     377             :     // If we are bailing out to baseline to handle an exception, jump to
     378             :     // the bailout tail stub.
     379           4 :     bind(&bailout);
     380           4 :     loadPtr(Address(esp, offsetof(ResumeFromException, bailoutInfo)), r9);
     381           4 :     mov(ImmWord(BAILOUT_RETURN_OK), rax);
     382           4 :     jmp(Operand(rsp, offsetof(ResumeFromException, target)));
     383           4 : }
     384             : 
     385             : void
     386         632 : MacroAssemblerX64::profilerEnterFrame(Register framePtr, Register scratch)
     387             : {
     388         632 :     asMasm().loadJSContext(scratch);
     389         632 :     loadPtr(Address(scratch, offsetof(JSContext, profilingActivation_)), scratch);
     390         632 :     storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
     391         632 :     storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
     392         632 : }
     393             : 
     394             : void
     395         631 : MacroAssemblerX64::profilerExitFrame()
     396             : {
     397         631 :     jmp(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
     398         631 : }
     399             : 
     400             : MacroAssembler&
     401       16092 : MacroAssemblerX64::asMasm()
     402             : {
     403       16092 :     return *static_cast<MacroAssembler*>(this);
     404             : }
     405             : 
     406             : const MacroAssembler&
     407           0 : MacroAssemblerX64::asMasm() const
     408             : {
     409           0 :     return *static_cast<const MacroAssembler*>(this);
     410             : }
     411             : 
     412             : void
     413       25400 : MacroAssembler::subFromStackPtr(Imm32 imm32)
     414             : {
     415       25400 :     if (imm32.value) {
     416             :         // On windows, we cannot skip very far down the stack without touching the
     417             :         // memory pages in-between.  This is a corner-case code for situations where the
     418             :         // Ion frame data for a piece of code is very large.  To handle this special case,
     419             :         // for frames over 4k in size we allocate memory on the stack incrementally, touching
     420             :         // it as we go.
     421             :         //
     422             :         // When the amount is quite large, which it can be, we emit an actual loop, in order
     423             :         // to keep the function prologue compact.  Compactness is a requirement for eg
     424             :         // Wasm's CodeRange data structure, which can encode only 8-bit offsets.
     425       25064 :         uint32_t amountLeft = imm32.value;
     426       25064 :         uint32_t fullPages = amountLeft / 4096;
     427       25064 :         if (fullPages <= 8) {
     428       25064 :             while (amountLeft > 4096) {
     429           0 :                 subq(Imm32(4096), StackPointer);
     430           0 :                 store32(Imm32(0), Address(StackPointer, 0));
     431           0 :                 amountLeft -= 4096;
     432             :             }
     433       25064 :             subq(Imm32(amountLeft), StackPointer);
     434             :         } else {
     435           0 :             ScratchRegisterScope scratch(*this);
     436           0 :             Label top;
     437           0 :             move32(Imm32(fullPages), scratch);
     438           0 :             bind(&top);
     439           0 :             subq(Imm32(4096), StackPointer);
     440           0 :             store32(Imm32(0), Address(StackPointer, 0));
     441           0 :             subl(Imm32(1), scratch);
     442           0 :             j(Assembler::NonZero, &top);
     443           0 :             amountLeft -= fullPages * 4096;
     444           0 :             if (amountLeft)
     445           0 :                 subq(Imm32(amountLeft), StackPointer);
     446             :         }
     447             :     }
     448       25400 : }
     449             : 
     450             : //{{{ check_macroassembler_style
     451             : // ===============================================================
     452             : // ABI function calls.
     453             : 
     454             : void
     455       13023 : MacroAssembler::setupUnalignedABICall(Register scratch)
     456             : {
     457       13023 :     MOZ_ASSERT(!IsCompilingWasm(), "wasm should only use aligned ABI calls");
     458       13023 :     setupABICall();
     459       13023 :     dynamicAlignment_ = true;
     460             : 
     461       13023 :     movq(rsp, scratch);
     462       13023 :     andq(Imm32(~(ABIStackAlignment - 1)), rsp);
     463       13023 :     push(scratch);
     464       13023 : }
     465             : 
     466             : void
     467       13023 : MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromWasm)
     468             : {
     469       13023 :     MOZ_ASSERT(inCall_);
     470       13023 :     uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
     471             : 
     472       13023 :     if (dynamicAlignment_) {
     473             :         // sizeof(intptr_t) accounts for the saved stack pointer pushed by
     474             :         // setupUnalignedABICall.
     475       13023 :         stackForCall += ComputeByteAlignment(stackForCall + sizeof(intptr_t),
     476             :                                              ABIStackAlignment);
     477             :     } else {
     478           0 :         uint32_t alignmentAtPrologue = callFromWasm ? sizeof(wasm::Frame) : 0;
     479           0 :         stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue,
     480             :                                              ABIStackAlignment);
     481             :     }
     482             : 
     483       13023 :     *stackAdjust = stackForCall;
     484       13023 :     reserveStack(stackForCall);
     485             : 
     486             :     // Position all arguments.
     487             :     {
     488       13023 :         enoughMemory_ &= moveResolver_.resolve();
     489       13023 :         if (!enoughMemory_)
     490           0 :             return;
     491             : 
     492       26046 :         MoveEmitter emitter(*this);
     493       13023 :         emitter.emit(moveResolver_);
     494       13023 :         emitter.finish();
     495             :     }
     496             : 
     497       13023 :     assertStackAlignment(ABIStackAlignment);
     498             : }
     499             : 
     500             : void
     501       13023 : MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result, bool cleanupArg)
     502             : {
     503       13023 :     freeStack(stackAdjust);
     504       13023 :     if (dynamicAlignment_)
     505       13023 :         pop(rsp);
     506             : 
     507             : #ifdef DEBUG
     508       13023 :     MOZ_ASSERT(inCall_);
     509       13023 :     inCall_ = false;
     510             : #endif
     511       13023 : }
     512             : 
     513             : static bool
     514         154 : IsIntArgReg(Register reg)
     515             : {
     516        1066 :     for (uint32_t i = 0; i < NumIntArgRegs; i++) {
     517         914 :         if (IntArgRegs[i] == reg)
     518           2 :             return true;
     519             :     }
     520             : 
     521         152 :     return false;
     522             : }
     523             : 
     524             : void
     525           0 : MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result)
     526             : {
     527           0 :     if (IsIntArgReg(fun)) {
     528             :         // Callee register may be clobbered for an argument. Move the callee to
     529             :         // r10, a volatile, non-argument register.
     530           0 :         propagateOOM(moveResolver_.addMove(MoveOperand(fun), MoveOperand(r10),
     531           0 :                                            MoveOp::GENERAL));
     532           0 :         fun = r10;
     533             :     }
     534             : 
     535           0 :     MOZ_ASSERT(!IsIntArgReg(fun));
     536             : 
     537             :     uint32_t stackAdjust;
     538           0 :     callWithABIPre(&stackAdjust);
     539           0 :     call(fun);
     540           0 :     callWithABIPost(stackAdjust, result);
     541           0 : }
     542             : 
     543             : void
     544          77 : MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
     545             : {
     546          77 :     Address safeFun = fun;
     547          77 :     if (IsIntArgReg(safeFun.base)) {
     548             :         // Callee register may be clobbered for an argument. Move the callee to
     549             :         // r10, a volatile, non-argument register.
     550           4 :         propagateOOM(moveResolver_.addMove(MoveOperand(fun.base), MoveOperand(r10),
     551           2 :                                            MoveOp::GENERAL));
     552           2 :         safeFun.base = r10;
     553             :     }
     554             : 
     555          77 :     MOZ_ASSERT(!IsIntArgReg(safeFun.base));
     556             : 
     557             :     uint32_t stackAdjust;
     558          77 :     callWithABIPre(&stackAdjust);
     559          77 :     call(safeFun);
     560          77 :     callWithABIPost(stackAdjust, result);
     561          77 : }
     562             : 
     563             : // ===============================================================
     564             : // Branch functions
     565             : 
     566             : void
     567         226 : MacroAssembler::branchPtrInNurseryChunk(Condition cond, Register ptr, Register temp, Label* label)
     568             : {
     569         226 :     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     570             : 
     571         452 :     ScratchRegisterScope scratch(*this);
     572         226 :     MOZ_ASSERT(ptr != temp);
     573         226 :     MOZ_ASSERT(ptr != scratch);
     574             : 
     575         226 :     movePtr(ptr, scratch);
     576         226 :     orPtr(Imm32(gc::ChunkMask), scratch);
     577         452 :     branch32(cond, Address(scratch, gc::ChunkLocationOffsetFromLastByte),
     578         226 :              Imm32(int32_t(gc::ChunkLocation::Nursery)), label);
     579         226 : }
     580             : 
     581             : void
     582           0 : MacroAssembler::branchValueIsNurseryObject(Condition cond, const Address& address, Register temp,
     583             :                                            Label* label)
     584             : {
     585           0 :     branchValueIsNurseryObjectImpl(cond, address, temp, label);
     586           0 : }
     587             : 
     588             : void
     589         208 : MacroAssembler::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp,
     590             :                                            Label* label)
     591             : {
     592         208 :     branchValueIsNurseryObjectImpl(cond, value, temp, label);
     593         208 : }
     594             : 
     595             : template <typename T>
     596             : void
     597         208 : MacroAssembler::branchValueIsNurseryObjectImpl(Condition cond, const T& value, Register temp,
     598             :                                                Label* label)
     599             : {
     600         208 :     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     601         208 :     MOZ_ASSERT(temp != InvalidReg);
     602             : 
     603         416 :     Label done;
     604         208 :     branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label);
     605             : 
     606         208 :     extractObject(value, temp);
     607         208 :     orPtr(Imm32(gc::ChunkMask), temp);
     608         208 :     branch32(cond, Address(temp, gc::ChunkLocationOffsetFromLastByte),
     609             :              Imm32(int32_t(gc::ChunkLocation::Nursery)), label);
     610             : 
     611         208 :     bind(&done);
     612         208 : }
     613             : 
     614             : void
     615          89 : MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs,
     616             :                                 const Value& rhs, Label* label)
     617             : {
     618          89 :     MOZ_ASSERT(cond == Equal || cond == NotEqual);
     619         178 :     ScratchRegisterScope scratch(*this);
     620          89 :     MOZ_ASSERT(lhs.valueReg() != scratch);
     621          89 :     moveValue(rhs, scratch);
     622          89 :     cmpPtr(lhs.valueReg(), scratch);
     623          89 :     j(cond, label);
     624          89 : }
     625             : 
     626             : // ========================================================================
     627             : // Memory access primitives.
     628             : template <typename T>
     629             : void
     630           6 : MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
     631             :                                   const T& dest, MIRType slotType)
     632             : {
     633           6 :     if (valueType == MIRType::Double) {
     634           0 :         storeDouble(value.reg().typedReg().fpu(), dest);
     635           0 :         return;
     636             :     }
     637             : 
     638             :     // For known integers and booleans, we can just store the unboxed value if
     639             :     // the slot has the same type.
     640           6 :     if ((valueType == MIRType::Int32 || valueType == MIRType::Boolean) && slotType == valueType) {
     641           0 :         if (value.constant()) {
     642           0 :             Value val = value.value();
     643           0 :             if (valueType == MIRType::Int32)
     644           0 :                 store32(Imm32(val.toInt32()), dest);
     645             :             else
     646           0 :                 store32(Imm32(val.toBoolean() ? 1 : 0), dest);
     647             :         } else {
     648           0 :             store32(value.reg().typedReg().gpr(), dest);
     649             :         }
     650           0 :         return;
     651             :     }
     652             : 
     653           6 :     if (value.constant())
     654           0 :         storeValue(value.value(), dest);
     655             :     else
     656           6 :         storeValue(ValueTypeFromMIRType(valueType), value.reg().typedReg().gpr(), dest);
     657             : }
     658             : 
     659             : template void
     660             : MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
     661             :                                   const Address& dest, MIRType slotType);
     662             : template void
     663             : MacroAssembler::storeUnboxedValue(const ConstantOrRegister& value, MIRType valueType,
     664             :                                   const BaseIndex& dest, MIRType slotType);
     665             : 
     666             : // ========================================================================
     667             : // wasm support
     668             : 
     669             : void
     670           0 : MacroAssembler::wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr, AnyRegister out)
     671             : {
     672           0 :     memoryBarrier(access.barrierBefore());
     673             : 
     674           0 :     size_t loadOffset = size();
     675           0 :     switch (access.type()) {
     676             :       case Scalar::Int8:
     677           0 :         movsbl(srcAddr, out.gpr());
     678           0 :         break;
     679             :       case Scalar::Uint8:
     680           0 :         movzbl(srcAddr, out.gpr());
     681           0 :         break;
     682             :       case Scalar::Int16:
     683           0 :         movswl(srcAddr, out.gpr());
     684           0 :         break;
     685             :       case Scalar::Uint16:
     686           0 :         movzwl(srcAddr, out.gpr());
     687           0 :         break;
     688             :       case Scalar::Int32:
     689             :       case Scalar::Uint32:
     690           0 :         movl(srcAddr, out.gpr());
     691           0 :         break;
     692             :       case Scalar::Float32:
     693           0 :         loadFloat32(srcAddr, out.fpu());
     694           0 :         break;
     695             :       case Scalar::Float64:
     696           0 :         loadDouble(srcAddr, out.fpu());
     697           0 :         break;
     698             :       case Scalar::Float32x4:
     699           0 :         switch (access.numSimdElems()) {
     700             :           // In memory-to-register mode, movss zeroes out the high lanes.
     701           0 :           case 1: loadFloat32(srcAddr, out.fpu()); break;
     702             :           // See comment above, which also applies to movsd.
     703           0 :           case 2: loadDouble(srcAddr, out.fpu()); break;
     704           0 :           case 4: loadUnalignedSimd128Float(srcAddr, out.fpu()); break;
     705           0 :           default: MOZ_CRASH("unexpected size for partial load");
     706             :         }
     707           0 :         break;
     708             :       case Scalar::Int32x4:
     709           0 :         switch (access.numSimdElems()) {
     710             :           // In memory-to-register mode, movd zeroes out the high lanes.
     711           0 :           case 1: vmovd(srcAddr, out.fpu()); break;
     712             :           // See comment above, which also applies to movq.
     713           0 :           case 2: vmovq(srcAddr, out.fpu()); break;
     714           0 :           case 4: loadUnalignedSimd128Int(srcAddr, out.fpu()); break;
     715           0 :           default: MOZ_CRASH("unexpected size for partial load");
     716             :         }
     717           0 :         break;
     718             :       case Scalar::Int8x16:
     719           0 :         MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial load");
     720           0 :         loadUnalignedSimd128Int(srcAddr, out.fpu());
     721           0 :         break;
     722             :       case Scalar::Int16x8:
     723           0 :         MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial load");
     724           0 :         loadUnalignedSimd128Int(srcAddr, out.fpu());
     725           0 :         break;
     726             :       case Scalar::Int64:
     727           0 :         MOZ_CRASH("int64 loads must use load64");
     728             :       case Scalar::Uint8Clamped:
     729             :       case Scalar::MaxTypedArrayViewType:
     730           0 :         MOZ_CRASH("unexpected array type");
     731             :     }
     732           0 :     append(access, loadOffset, framePushed());
     733             : 
     734           0 :     memoryBarrier(access.barrierAfter());
     735           0 : }
     736             : 
     737             : void
     738           0 : MacroAssembler::wasmLoadI64(const wasm::MemoryAccessDesc& access, Operand srcAddr, Register64 out)
     739             : {
     740           0 :     MOZ_ASSERT(!access.isAtomic());
     741           0 :     MOZ_ASSERT(!access.isSimd());
     742             : 
     743           0 :     size_t loadOffset = size();
     744           0 :     switch (access.type()) {
     745             :       case Scalar::Int8:
     746           0 :         movsbq(srcAddr, out.reg);
     747           0 :         break;
     748             :       case Scalar::Uint8:
     749           0 :         movzbq(srcAddr, out.reg);
     750           0 :         break;
     751             :       case Scalar::Int16:
     752           0 :         movswq(srcAddr, out.reg);
     753           0 :         break;
     754             :       case Scalar::Uint16:
     755           0 :         movzwq(srcAddr, out.reg);
     756           0 :         break;
     757             :       case Scalar::Int32:
     758           0 :         movslq(srcAddr, out.reg);
     759           0 :         break;
     760             :       // Int32 to int64 moves zero-extend by default.
     761             :       case Scalar::Uint32:
     762           0 :         movl(srcAddr, out.reg);
     763           0 :         break;
     764             :       case Scalar::Int64:
     765           0 :         movq(srcAddr, out.reg);
     766           0 :         break;
     767             :       case Scalar::Float32:
     768             :       case Scalar::Float64:
     769             :       case Scalar::Float32x4:
     770             :       case Scalar::Int8x16:
     771             :       case Scalar::Int16x8:
     772             :       case Scalar::Int32x4:
     773           0 :         MOZ_CRASH("non-int64 loads should use load()");
     774             :       case Scalar::Uint8Clamped:
     775             :       case Scalar::MaxTypedArrayViewType:
     776           0 :         MOZ_CRASH("unexpected array type");
     777             :     }
     778           0 :     append(access, loadOffset, framePushed());
     779           0 : }
     780             : 
     781             : void
     782           0 : MacroAssembler::wasmStore(const wasm::MemoryAccessDesc& access, AnyRegister value, Operand dstAddr)
     783             : {
     784           0 :     memoryBarrier(access.barrierBefore());
     785             : 
     786           0 :     size_t storeOffset = size();
     787           0 :     switch (access.type()) {
     788             :       case Scalar::Int8:
     789             :       case Scalar::Uint8:
     790           0 :         movb(value.gpr(), dstAddr);
     791           0 :         break;
     792             :       case Scalar::Int16:
     793             :       case Scalar::Uint16:
     794           0 :         movw(value.gpr(), dstAddr);
     795           0 :         break;
     796             :       case Scalar::Int32:
     797             :       case Scalar::Uint32:
     798           0 :         movl(value.gpr(), dstAddr);
     799           0 :         break;
     800             :       case Scalar::Int64:
     801           0 :         movq(value.gpr(), dstAddr);
     802           0 :         break;
     803             :       case Scalar::Float32:
     804           0 :         storeUncanonicalizedFloat32(value.fpu(), dstAddr);
     805           0 :         break;
     806             :       case Scalar::Float64:
     807           0 :         storeUncanonicalizedDouble(value.fpu(), dstAddr);
     808           0 :         break;
     809             :       case Scalar::Float32x4:
     810           0 :         switch (access.numSimdElems()) {
     811             :           // In memory-to-register mode, movss zeroes out the high lanes.
     812           0 :           case 1: storeUncanonicalizedFloat32(value.fpu(), dstAddr); break;
     813             :           // See comment above, which also applies to movsd.
     814           0 :           case 2: storeUncanonicalizedDouble(value.fpu(), dstAddr); break;
     815           0 :           case 4: storeUnalignedSimd128Float(value.fpu(), dstAddr); break;
     816           0 :           default: MOZ_CRASH("unexpected size for partial load");
     817             :         }
     818           0 :         break;
     819             :       case Scalar::Int32x4:
     820           0 :         switch (access.numSimdElems()) {
     821             :           // In memory-to-register mode, movd zeroes out the high lanes.
     822           0 :           case 1: vmovd(value.fpu(), dstAddr); break;
     823             :           // See comment above, which also applies to movq.
     824           0 :           case 2: vmovq(value.fpu(), dstAddr); break;
     825           0 :           case 4: storeUnalignedSimd128Int(value.fpu(), dstAddr); break;
     826           0 :           default: MOZ_CRASH("unexpected size for partial load");
     827             :         }
     828           0 :         break;
     829             :       case Scalar::Int8x16:
     830           0 :         MOZ_ASSERT(access.numSimdElems() == 16, "unexpected partial store");
     831           0 :         storeUnalignedSimd128Int(value.fpu(), dstAddr);
     832           0 :         break;
     833             :       case Scalar::Int16x8:
     834           0 :         MOZ_ASSERT(access.numSimdElems() == 8, "unexpected partial store");
     835           0 :         storeUnalignedSimd128Int(value.fpu(), dstAddr);
     836           0 :         break;
     837             :       case Scalar::Uint8Clamped:
     838             :       case Scalar::MaxTypedArrayViewType:
     839           0 :         MOZ_CRASH("unexpected array type");
     840             :     }
     841           0 :     append(access, storeOffset, framePushed());
     842             : 
     843           0 :     memoryBarrier(access.barrierAfter());
     844           0 : }
     845             : 
     846             : void
     847           0 : MacroAssembler::wasmTruncateDoubleToUInt32(FloatRegister input, Register output, Label* oolEntry)
     848             : {
     849           0 :     vcvttsd2sq(input, output);
     850             : 
     851             :     // Check that the result is in the uint32_t range.
     852           0 :     ScratchRegisterScope scratch(*this);
     853           0 :     move32(Imm32(0xffffffff), scratch);
     854           0 :     cmpq(scratch, output);
     855           0 :     j(Assembler::Above, oolEntry);
     856           0 : }
     857             : 
     858             : void
     859           0 : MacroAssembler::wasmTruncateFloat32ToUInt32(FloatRegister input, Register output, Label* oolEntry)
     860             : {
     861           0 :     vcvttss2sq(input, output);
     862             : 
     863             :     // Check that the result is in the uint32_t range.
     864           0 :     ScratchRegisterScope scratch(*this);
     865           0 :     move32(Imm32(0xffffffff), scratch);
     866           0 :     cmpq(scratch, output);
     867           0 :     j(Assembler::Above, oolEntry);
     868           0 : }
     869             : 
     870             : //}}} check_macroassembler_style

Generated by: LCOV version 1.13