text: /*
   *  Copyright 2017 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  // Do not include this file directly. It's intended to be used only by the JNI
  // generation script. We are exporting types in strange namespaces in order to
  // be compatible with the generated code targeted for Chromium.
  
  #ifndef MEDIASOUP_CLIENT_JNI_GENERATOR_HELPER_H_
  #define MEDIASOUP_CLIENT_JNI_GENERATOR_HELPER_H_
  
  #include <atomic>
  #include <jni.h>
  
  #include "include/scoped_java_ref.h"
  #include "sdk/android/native_api/jni/jni_int_wrapper.h"
  #include "rtc_base/checks.h"
  
  #define CHECK_CLAZZ(env, jcaller, clazz, ...) RTC_DCHECK(clazz);
  #define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...)                               \
  	RTC_DCHECK(native_ptr) << method_name;
  
  #define BASE_EXPORT
  #define JNI_REGISTRATION_EXPORT __attribute__((visibility("default")))
  #define JNI_GENERATOR_EXPORT extern "C" JNIEXPORT JNICALL
  
  #define CHECK_EXCEPTION(jni)                                                                       \
  	RTC_CHECK(!jni->ExceptionCheck()) << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
  
  namespace mediasoupclient
  {
  // This function will initialize |atomic_class_id| to contain a global ref to
  // the given class, and will return that ref on subsequent calls. The caller is
  // responsible to zero-initialize |atomic_class_id|. It's fine to
  // simultaneously call this on multiple threads referencing the same
  // |atomic_method_id|.
  jclass LazyGetClass(JNIEnv* env, const char* class_name, std::atomic<jclass>* atomic_class_id);
  
  // This class is a wrapper for JNIEnv Get(Static)MethodID.
  class MethodID
  {
  public:
  	enum Type
  	{
  		TYPE_STATIC,
  		TYPE_INSTANCE,
  	};
  
  	// This function will initialize |atomic_method_id| to contain a ref to
  	// the given method, and will return that ref on subsequent calls. The caller
  	// is responsible to zero-initialize |atomic_method_id|. It's fine to
  	// simultaneously call this on multiple threads referencing the same
  	// |atomic_method_id|.
  	template<Type type>
  	static jmethodID LazyGet(
  	  JNIEnv* env,
  	  jclass clazz,
  	  const char* method_name,
  	  const char* jni_signature,
  	  std::atomic<jmethodID>* atomic_method_id);
  };
  
  } // namespace mediasoupclient
  
  // Re-export relevant classes into the namespaces the script expects.
  namespace base
  {
  namespace android
  {
  	using mediasoupclient::JavaParamRef;
  	using mediasoupclient::JavaRef;
  	using mediasoupclient::LazyGetClass;
  	using mediasoupclient::MethodID;
  	using mediasoupclient::ScopedJavaLocalRef;
  
  } // namespace android
  } // namespace base
  
  namespace jni_generator
  {
  inline void CheckException(JNIEnv* env)
  {
  	CHECK_EXCEPTION(env);
  }
  
  // A 32 bit number could be an address on stack. Random 64 bit marker on the
  // stack is much less likely to be present on stack.
  constexpr uint64_t kJniStackMarkerValue = 0xbdbdef1bebcade1b;
  
  // Context about the JNI call with exception checked to be stored in stack.
  struct BASE_EXPORT JniJavaCallContextUnchecked
  {
  	inline JniJavaCallContextUnchecked()
  	{
  // TODO(ssid): Implement for other architectures.
  #if defined(__arm__) || defined(__aarch64__)
  		// This assumes that this method does not increment the stack pointer.
  		asm volatile("mov %0, sp" : "=r"(sp));
  #else
  		sp = 0;
  #endif
  	}
  
  	// Force no inline to reduce code size.
  	template<base::android::MethodID::Type type>
  	void Init(
  	  JNIEnv* env,
  	  jclass clazz,
  	  const char* method_name,
  	  const char* jni_signature,
  	  std::atomic<jmethodID>* atomic_method_id)
  	{
  		env1 = env;
  
  		// Make sure compiler doesn't optimize out the assignment.
  		memcpy(&marker, &kJniStackMarkerValue, sizeof(kJniStackMarkerValue));
  		// Gets PC of the calling function.
  		pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
  
  		method_id = base::android::MethodID::LazyGet<type>(
  		  env, clazz, method_name, jni_signature, atomic_method_id);
  	}
  
  	~JniJavaCallContextUnchecked()
  	{
  		// Reset so that spurious marker finds are avoided.
  		memset(&marker, 0, sizeof(marker));
  	}
  
  	uint64_t marker;
  	uintptr_t sp;
  	uintptr_t pc;
  
  	JNIEnv* env1;
  	jmethodID method_id;
  };
  
  // Context about the JNI call with exception unchecked to be stored in stack.
  struct BASE_EXPORT JniJavaCallContextChecked
  {
  	// Force no inline to reduce code size.
  	template<base::android::MethodID::Type type>
  	void Init(
  	  JNIEnv* env,
  	  jclass clazz,
  	  const char* method_name,
  	  const char* jni_signature,
  	  std::atomic<jmethodID>* atomic_method_id)
  	{
  		base.Init<type>(env, clazz, method_name, jni_signature, atomic_method_id);
  		// Reset |pc| to correct caller.
  		base.pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
  	}
  
  	~JniJavaCallContextChecked()
  	{
  		jni_generator::CheckException(base.env1);
  	}
  
  	JniJavaCallContextUnchecked base;
  };
  
  static_assert(
    sizeof(JniJavaCallContextChecked) == sizeof(JniJavaCallContextUnchecked),
    "Stack unwinder cannot work with structs of different sizes.");
  } // namespace jni_generator
  
  #endif // MEDIASOUP_CLIENT_JNI_GENERATOR_HELPER_H_
  