blob: 227dfb4331606fa4ad0d1d2db1563ffc0ab6273a [file] [log] [blame] [edit]
/*
* 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 SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_
#define SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_
#include <jni.h>
#include <atomic>
#include "third_party/jni_zero/jni_zero_internal.h"
#define JNI_REGISTRATION_EXPORT __attribute__((visibility("default")))
#if defined(WEBRTC_ARCH_X86)
// Dalvik JIT generated code doesn't guarantee 16-byte stack alignment on
// x86 - use force_align_arg_pointer to realign the stack at the JNI
// boundary. crbug.com/655248
#define JNI_GENERATOR_EXPORT \
__attribute__((force_align_arg_pointer)) extern "C" JNIEXPORT JNICALL
#else
#define JNI_GENERATOR_EXPORT extern "C" JNIEXPORT JNICALL
#endif
// Re-export helpers in the old jni_generator namespace.
// TODO(b/319078685): Remove once all uses of the jni_generator has been
// updated.
namespace jni_generator {
using jni_zero::internal::kJniStackMarkerValue;
// TODO(b/319078685): Remove JniJavaCallContextUnchecked once all uses of the
// jni_generator has been updated.
struct 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 <jni_zero::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 = jni_zero::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;
};
// TODO(b/319078685): Remove JniJavaCallContextChecked once all uses of the
// jni_generator has been updated.
// Context about the JNI call with exception unchecked to be stored in stack.
struct JniJavaCallContextChecked {
// Force no inline to reduce code size.
template <jni_zero::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_zero::CheckException(base.env1); }
JniJavaCallContextUnchecked base;
};
static_assert(sizeof(JniJavaCallContextChecked) ==
sizeof(JniJavaCallContextUnchecked),
"Stack unwinder cannot work with structs of different sizes.");
} // namespace jni_generator
#endif // SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_