text: #pragma once
  
  #include "IAsmHelper.h"
  #include "../Include/Macro.h"
  
  namespace blackbone
  {
  
  class AsmHelper64 : public IAsmHelper
  {
  public:
      BLACKBONE_API AsmHelper64();
      BLACKBONE_API ~AsmHelper64( void );
  
      /// <summary>
      /// Generate function prologue code
      /// </summary>
      /// <param name="switchMode">true if execution must be swithed to x64 mode</param>
      virtual void GenPrologue( bool switchMode = false );
  
      /// <summary>
      /// Generate function epilogue code
      /// </summary>
      /// <param name="switchMode">true if execution must be swithed to x86 mode</param>
      /// <param name="retSize">Stack change value</param>
      virtual void GenEpilogue( bool switchMode = false, int retSize = -1 );
  
      /// <summary>
      /// Generate function call
      /// </summary>
      /// <param name="pFN">Function pointer</param>
      /// <param name="args">Function arguments</param>
      /// <param name="cc">Ignored</param>
      virtual void GenCall( const AsmFunctionPtr& pFN, const std::vector<AsmVariant>& args, eCalligConvention cc = cc_stdcall );
  
      /// <summary>
      /// Save rax value and terminate current thread
      /// </summary>
      /// <param name="pExitThread">NtTerminateThread address</param>
      /// <param name="resultPtr">Memory where rax value will be saved</param>
      virtual void ExitThreadWithStatus( uint64_t pExitThread, uint64_t resultPtr );
  
      /// <summary>
      /// Save return value and signal thread return event
      /// </summary>
      /// <param name="pSetEvent">NtSetEvent address</param>
      /// <param name="ResultPtr">Result value memory location</param>
      /// <param name="EventPtr">Event memory location</param>
      /// <param name="errPtr">Error code memory location</param>
      /// <param name="rtype">Return type</param>
      virtual void SaveRetValAndSignalEvent( 
          uint64_t pSetEvent,
          uint64_t ResultPtr,
          uint64_t EventPtr,
          uint64_t lastStatusPtr,
          eReturnType rtype = rt_int32
          );
  
      /// <summary>
      /// Set stack reservation policy on call generation
      /// </summary>
      /// <param name="state">
      /// If true - stack space will be reserved during each call generation
      /// If false - no automatic stack reservation, user must allocate stack by hand
      /// </param>
      virtual void EnableX64CallStack( bool state );
  
  private:
      AsmHelper64( const AsmHelper64& ) = delete;
      AsmHelper64& operator = (const AsmHelper64&) = delete;
  
      /// <summary>
      /// Push function argument
      /// </summary>
      /// <param name="arg">Argument.</param>
      /// <param name="regidx">Push type(register or stack)</param>
      void PushArg( const AsmVariant& arg, int32_t index );
  
      /// <summary>
      /// Push function argument
      /// </summary>
      /// <param name="arg">Argument</param>
      /// <param name="index">Argument index</param>
      /// <param name="fpu">true if argument is a floating point value</param>
      template<typename _Type>
      void PushArgp( const _Type& arg, int32_t index, bool fpu = false );
  
  private:
      bool _stackEnabled;     // if true - GenCall will allocate shadow stack space
  };
  
  }
  