• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef JNI_ZERO_JNI_ZERO_HELPER_H_
6 #define JNI_ZERO_JNI_ZERO_HELPER_H_
7 
8 #include <jni.h>
9 
10 #include "base/android/jni_android.h"
11 #include "base/android/scoped_java_ref.h"
12 #include "base/compiler_specific.h"
13 #include "base/memory/raw_ptr.h"
14 #if defined(USE_CHROMIUM_BASE)
15 // Used for ARCH_CPU_X86 - embedder must define this correctly if they want
16 // 16-byte stack alignment on x86.
17 #include "build/build_config.h"
18 #endif                     // defined(USE_CHROMIUM_BASE)
19 #include "third_party/jni_zero/jni_export.h"
20 #include "third_party/jni_zero/jni_int_wrapper.h"
21 #include "third_party/jni_zero/logging.h"
22 
23 // Project-specific macros used by the header files generated by
24 // jni_generator.py. Different projects can then specify their own
25 // implementation for this file.
26 #define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
27   JNI_ZERO_DCHECK(native_ptr);
28 
29 #define CHECK_CLAZZ(env, jcaller, clazz, ...) JNI_ZERO_DCHECK(clazz);
30 
31 namespace jni_generator {
32 
HandleRegistrationError(JNIEnv * env,jclass clazz,const char * filename)33 inline void HandleRegistrationError(JNIEnv* env,
34                                     jclass clazz,
35                                     const char* filename) {
36   JNI_ZERO_ELOG("RegisterNatives failed in %s", filename);
37 }
38 
CheckException(JNIEnv * env)39 inline void CheckException(JNIEnv* env) {
40   base::android::CheckException(env);
41 }
42 
43 // A 32 bit number could be an address on stack. Random 64 bit marker on the
44 // stack is much less likely to be present on stack.
45 constexpr uint64_t kJniStackMarkerValue = 0xbdbdef1bebcade1b;
46 
47 // Context about the JNI call with exception checked to be stored in stack.
48 struct JNI_ZERO_COMPONENT_BUILD_EXPORT JniJavaCallContextUnchecked {
JniJavaCallContextUncheckedJniJavaCallContextUnchecked49   ALWAYS_INLINE JniJavaCallContextUnchecked() {
50 // TODO(ssid): Implement for other architectures.
51 #if defined(__arm__) || defined(__aarch64__)
52     // This assumes that this method does not increment the stack pointer.
53     asm volatile("mov %0, sp" : "=r"(sp));
54 #else
55     sp = 0;
56 #endif
57   }
58 
59   // Force no inline to reduce code size.
60   template <base::android::MethodID::Type type>
InitJniJavaCallContextUnchecked61   NOINLINE void Init(JNIEnv* env,
62                      jclass clazz,
63                      const char* method_name,
64                      const char* jni_signature,
65                      std::atomic<jmethodID>* atomic_method_id) {
66     env1 = env;
67 
68     // Make sure compiler doesn't optimize out the assignment.
69     memcpy(&marker, &kJniStackMarkerValue, sizeof(kJniStackMarkerValue));
70     // Gets PC of the calling function.
71     pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
72 
73     method_id = base::android::MethodID::LazyGet<type>(
74         env, clazz, method_name, jni_signature, atomic_method_id);
75   }
76 
~JniJavaCallContextUncheckedJniJavaCallContextUnchecked77   NOINLINE ~JniJavaCallContextUnchecked() {
78     // Reset so that spurious marker finds are avoided.
79     memset(&marker, 0, sizeof(marker));
80   }
81 
82   uint64_t marker;
83   uintptr_t sp;
84   uintptr_t pc;
85 
86   raw_ptr<JNIEnv> env1;
87   jmethodID method_id;
88 };
89 
90 // Context about the JNI call with exception unchecked to be stored in stack.
91 struct JNI_ZERO_COMPONENT_BUILD_EXPORT JniJavaCallContextChecked {
92   // Force no inline to reduce code size.
93   template <base::android::MethodID::Type type>
InitJniJavaCallContextChecked94   NOINLINE void Init(JNIEnv* env,
95                      jclass clazz,
96                      const char* method_name,
97                      const char* jni_signature,
98                      std::atomic<jmethodID>* atomic_method_id) {
99     base.Init<type>(env, clazz, method_name, jni_signature, atomic_method_id);
100     // Reset |pc| to correct caller.
101     base.pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
102   }
103 
~JniJavaCallContextCheckedJniJavaCallContextChecked104   NOINLINE ~JniJavaCallContextChecked() {
105     jni_generator::CheckException(base.env1);
106   }
107 
108   JniJavaCallContextUnchecked base;
109 };
110 
111 static_assert(sizeof(JniJavaCallContextChecked) ==
112                   sizeof(JniJavaCallContextUnchecked),
113               "Stack unwinder cannot work with structs of different sizes.");
114 
115 }  // namespace jni_generator
116 
117 #endif  // JNI_ZERO_JNI_ZERO_HELPER_H_
118