| /* | 
 |  * Copyright (C) 2015-2017 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 "B3PatchpointSpecial.h" | 
 |  | 
 | #if ENABLE(B3_JIT) | 
 |  | 
 | #include "AirCode.h" | 
 | #include "AirGenerationContext.h" | 
 | #include "B3ProcedureInlines.h" | 
 | #include "B3StackmapGenerationParams.h" | 
 | #include "B3ValueInlines.h" | 
 |  | 
 | namespace JSC { namespace B3 { | 
 |  | 
 | using Arg = Air::Arg; | 
 | using Inst = Air::Inst; | 
 |  | 
 | PatchpointSpecial::PatchpointSpecial() | 
 | { | 
 | } | 
 |  | 
 | PatchpointSpecial::~PatchpointSpecial() | 
 | { | 
 | } | 
 |  | 
 | void PatchpointSpecial::forEachArg(Inst& inst, const ScopedLambda<Inst::EachArgCallback>& callback) | 
 | { | 
 |     const Procedure& procedure = code().proc(); | 
 |     PatchpointValue* patchpoint = inst.origin->as<PatchpointValue>(); | 
 |     unsigned argIndex = 1; | 
 |  | 
 |     Type type = patchpoint->type(); | 
 |     for (; argIndex <= procedure.resultCount(type); ++argIndex) { | 
 |         Arg::Role role; | 
 |         if (patchpoint->resultConstraints[argIndex - 1].kind() == ValueRep::SomeEarlyRegister) | 
 |             role = Arg::EarlyDef; | 
 |         else | 
 |             role = Arg::Def; | 
 |  | 
 |         Type argType = type.isTuple() ? procedure.extractFromTuple(type, argIndex - 1) : type; | 
 |         callback(inst.args[argIndex], role, bankForType(argType), widthForType(argType)); | 
 |     } | 
 |  | 
 |     forEachArgImpl(0, argIndex, inst, SameAsRep, WTF::nullopt, callback, WTF::nullopt); | 
 |     argIndex += inst.origin->numChildren(); | 
 |  | 
 |     for (unsigned i = patchpoint->numGPScratchRegisters; i--;) | 
 |         callback(inst.args[argIndex++], Arg::Scratch, GP, conservativeWidth(GP)); | 
 |     for (unsigned i = patchpoint->numFPScratchRegisters; i--;) | 
 |         callback(inst.args[argIndex++], Arg::Scratch, FP, conservativeWidth(FP)); | 
 | } | 
 |  | 
 | bool PatchpointSpecial::isValid(Inst& inst) | 
 | { | 
 |     const Procedure& procedure = code().proc(); | 
 |     PatchpointValue* patchpoint = inst.origin->as<PatchpointValue>(); | 
 |     unsigned argIndex = 1; | 
 |  | 
 |     Type type = patchpoint->type(); | 
 |     for (; argIndex <= procedure.resultCount(type); ++argIndex) { | 
 |         if (argIndex >= inst.args.size()) | 
 |             return false; | 
 |          | 
 |         if (!isArgValidForType(inst.args[argIndex], type.isTuple() ? procedure.extractFromTuple(type, argIndex - 1) : type)) | 
 |             return false; | 
 |         if (!isArgValidForRep(code(), inst.args[argIndex], patchpoint->resultConstraints[argIndex - 1])) | 
 |             return false; | 
 |     } | 
 |  | 
 |     if (!isValidImpl(0, argIndex, inst)) | 
 |         return false; | 
 |     argIndex += patchpoint->numChildren(); | 
 |  | 
 |     if (argIndex + patchpoint->numGPScratchRegisters + patchpoint->numFPScratchRegisters | 
 |         != inst.args.size()) | 
 |         return false; | 
 |  | 
 |     for (unsigned i = patchpoint->numGPScratchRegisters; i--;) { | 
 |         Arg arg = inst.args[argIndex++]; | 
 |         if (!arg.isGPTmp()) | 
 |             return false; | 
 |     } | 
 |     for (unsigned i = patchpoint->numFPScratchRegisters; i--;) { | 
 |         Arg arg = inst.args[argIndex++]; | 
 |         if (!arg.isFPTmp()) | 
 |             return false; | 
 |     } | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | bool PatchpointSpecial::admitsStack(Inst& inst, unsigned argIndex) | 
 | { | 
 |     ASSERT(argIndex); | 
 |  | 
 |     Type type = inst.origin->type(); | 
 |     unsigned returnCount = code().proc().resultCount(type); | 
 |  | 
 |     if (argIndex <= returnCount) { | 
 |         switch (inst.origin->as<PatchpointValue>()->resultConstraints[argIndex - 1].kind()) { | 
 |         case ValueRep::WarmAny: | 
 |         case ValueRep::StackArgument: | 
 |             return true; | 
 |         case ValueRep::SomeRegister: | 
 |         case ValueRep::SomeRegisterWithClobber: | 
 |         case ValueRep::SomeEarlyRegister: | 
 |         case ValueRep::SomeLateRegister: | 
 |         case ValueRep::Register: | 
 |         case ValueRep::LateRegister: | 
 |             return false; | 
 |         default: | 
 |             RELEASE_ASSERT_NOT_REACHED(); | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     return admitsStackImpl(0, returnCount + 1, inst, argIndex); | 
 | } | 
 |  | 
 | bool PatchpointSpecial::admitsExtendedOffsetAddr(Inst& inst, unsigned argIndex) | 
 | { | 
 |     return admitsStack(inst, argIndex); | 
 | } | 
 |  | 
 | CCallHelpers::Jump PatchpointSpecial::generate(Inst& inst, CCallHelpers& jit, Air::GenerationContext& context) | 
 | { | 
 |     const Procedure& procedure = code().proc(); | 
 |     PatchpointValue* value = inst.origin->as<PatchpointValue>(); | 
 |     ASSERT(value); | 
 |  | 
 |     Vector<ValueRep> reps; | 
 |     unsigned offset = 1; | 
 |  | 
 |     Type type = value->type(); | 
 |     while (offset <= procedure.resultCount(type)) | 
 |         reps.append(repForArg(*context.code, inst.args[offset++])); | 
 |     reps.appendVector(repsImpl(context, 0, offset, inst)); | 
 |     offset += value->numChildren(); | 
 |  | 
 |     StackmapGenerationParams params(value, reps, context); | 
 |  | 
 |     for (unsigned i = value->numGPScratchRegisters; i--;) | 
 |         params.m_gpScratch.append(inst.args[offset++].gpr()); | 
 |     for (unsigned i = value->numFPScratchRegisters; i--;) | 
 |         params.m_fpScratch.append(inst.args[offset++].fpr()); | 
 |      | 
 |     value->m_generator->run(jit, params); | 
 |  | 
 |     return CCallHelpers::Jump(); | 
 | } | 
 |  | 
 | bool PatchpointSpecial::isTerminal(Inst& inst) | 
 | { | 
 |     return inst.origin->as<PatchpointValue>()->effects.terminal; | 
 | } | 
 |  | 
 | void PatchpointSpecial::dumpImpl(PrintStream& out) const | 
 | { | 
 |     out.print("Patchpoint"); | 
 | } | 
 |  | 
 | void PatchpointSpecial::deepDumpImpl(PrintStream& out) const | 
 | { | 
 |     out.print("Lowered B3::PatchpointValue."); | 
 | } | 
 |  | 
 | } } // namespace JSC::B3 | 
 |  | 
 | #endif // ENABLE(B3_JIT) |