| /* | 
 |  * Copyright (C) 2013-2019 Apple Inc. All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
 |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
 |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
 |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
 |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
 |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
 |  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
 |  */ | 
 |  | 
 | #include "config.h" | 
 | #include "FTLSlowPathCall.h" | 
 |  | 
 | #if ENABLE(FTL_JIT) | 
 |  | 
 | #include "CCallHelpers.h" | 
 | #include "FTLState.h" | 
 | #include "FTLThunks.h" | 
 | #include "GPRInfo.h" | 
 | #include "JSCInlines.h" | 
 |  | 
 | namespace JSC { namespace FTL { | 
 |  | 
 | // This code relies on us being 64-bit. FTL is currently always 64-bit. | 
 | static constexpr size_t wordSize = 8; | 
 |  | 
 | SlowPathCallContext::SlowPathCallContext( | 
 |     RegisterSet usedRegisters, CCallHelpers& jit, unsigned numArgs, GPRReg returnRegister) | 
 |     : m_jit(jit) | 
 |     , m_numArgs(numArgs) | 
 |     , m_returnRegister(returnRegister) | 
 | { | 
 |     // We don't care that you're using callee-save, stack, or hardware registers. | 
 |     usedRegisters.exclude(RegisterSet::stackRegisters()); | 
 |     usedRegisters.exclude(RegisterSet::reservedHardwareRegisters()); | 
 |     usedRegisters.exclude(RegisterSet::calleeSaveRegisters()); | 
 |          | 
 |     // The return register doesn't need to be saved. | 
 |     if (m_returnRegister != InvalidGPRReg) | 
 |         usedRegisters.clear(m_returnRegister); | 
 |          | 
 |     size_t stackBytesNeededForReturnAddress = wordSize; | 
 |          | 
 |     m_offsetToSavingArea = | 
 |         (std::max(m_numArgs, NUMBER_OF_ARGUMENT_REGISTERS) - NUMBER_OF_ARGUMENT_REGISTERS) * wordSize; | 
 |          | 
 |     for (unsigned i = std::min(NUMBER_OF_ARGUMENT_REGISTERS, numArgs); i--;) | 
 |         m_argumentRegisters.set(GPRInfo::toArgumentRegister(i)); | 
 |     m_callingConventionRegisters.merge(m_argumentRegisters); | 
 |     if (returnRegister != InvalidGPRReg) | 
 |         m_callingConventionRegisters.set(GPRInfo::returnValueGPR); | 
 |     m_callingConventionRegisters.filter(usedRegisters); | 
 |          | 
 |     unsigned numberOfCallingConventionRegisters = | 
 |         m_callingConventionRegisters.numberOfSetRegisters(); | 
 |          | 
 |     size_t offsetToThunkSavingArea = | 
 |         m_offsetToSavingArea + | 
 |         numberOfCallingConventionRegisters * wordSize; | 
 |          | 
 |     m_stackBytesNeeded = | 
 |         offsetToThunkSavingArea + | 
 |         stackBytesNeededForReturnAddress + | 
 |         (usedRegisters.numberOfSetRegisters() - numberOfCallingConventionRegisters) * wordSize; | 
 |          | 
 |     m_stackBytesNeeded = (m_stackBytesNeeded + stackAlignmentBytes() - 1) & ~(stackAlignmentBytes() - 1); | 
 |          | 
 |     m_jit.subPtr(CCallHelpers::TrustedImm32(m_stackBytesNeeded), CCallHelpers::stackPointerRegister); | 
 |  | 
 |     m_thunkSaveSet = usedRegisters; | 
 |          | 
 |     // This relies on all calling convention registers also being temp registers. | 
 |     unsigned stackIndex = 0; | 
 |     for (unsigned i = GPRInfo::numberOfRegisters; i--;) { | 
 |         GPRReg reg = GPRInfo::toRegister(i); | 
 |         if (!m_callingConventionRegisters.get(reg)) | 
 |             continue; | 
 |         m_jit.storePtr(reg, CCallHelpers::Address(CCallHelpers::stackPointerRegister, m_offsetToSavingArea + (stackIndex++) * wordSize)); | 
 |         m_thunkSaveSet.clear(reg); | 
 |     } | 
 |          | 
 |     m_offset = offsetToThunkSavingArea; | 
 | } | 
 |      | 
 | SlowPathCallContext::~SlowPathCallContext() | 
 | { | 
 |     if (m_returnRegister != InvalidGPRReg) | 
 |         m_jit.move(GPRInfo::returnValueGPR, m_returnRegister); | 
 |      | 
 |     unsigned stackIndex = 0; | 
 |     for (unsigned i = GPRInfo::numberOfRegisters; i--;) { | 
 |         GPRReg reg = GPRInfo::toRegister(i); | 
 |         if (!m_callingConventionRegisters.get(reg)) | 
 |             continue; | 
 |         m_jit.loadPtr(CCallHelpers::Address(CCallHelpers::stackPointerRegister, m_offsetToSavingArea + (stackIndex++) * wordSize), reg); | 
 |     } | 
 |      | 
 |     m_jit.addPtr(CCallHelpers::TrustedImm32(m_stackBytesNeeded), CCallHelpers::stackPointerRegister); | 
 | } | 
 |  | 
 | SlowPathCallKey SlowPathCallContext::keyWithTarget(FunctionPtr<CFunctionPtrTag> callTarget) const | 
 | { | 
 |     return SlowPathCallKey(m_thunkSaveSet, callTarget, m_argumentRegisters, m_offset); | 
 | } | 
 |  | 
 | SlowPathCall SlowPathCallContext::makeCall(VM& vm, FunctionPtr<CFunctionPtrTag> callTarget) | 
 | { | 
 |     SlowPathCallKey key = keyWithTarget(callTarget); | 
 |     SlowPathCall result = SlowPathCall(m_jit.call(OperationPtrTag), key); | 
 |  | 
 |     m_jit.addLinkTask( | 
 |         [result, &vm] (LinkBuffer& linkBuffer) { | 
 |             MacroAssemblerCodeRef<JITThunkPtrTag> thunk = | 
 |                 vm.ftlThunks->getSlowPathCallThunk(vm, result.key()); | 
 |  | 
 |             linkBuffer.link(result.call(), CodeLocationLabel<OperationPtrTag>(thunk.retaggedCode<OperationPtrTag>())); | 
 |         }); | 
 |      | 
 |     return result; | 
 | } | 
 |  | 
 | CallSiteIndex callSiteIndexForCodeOrigin(State& state, CodeOrigin codeOrigin) | 
 | { | 
 |     if (codeOrigin) | 
 |         return state.jitCode->common.addCodeOrigin(codeOrigin); | 
 |     return CallSiteIndex(); | 
 | } | 
 |  | 
 | } } // namespace JSC::FTL | 
 |  | 
 | #endif // ENABLE(FTL_JIT) | 
 |  |