Coverage Report

Created: 2026-11-06 06:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/jni-util.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <butil/macros.h>
21
#include <jni.h>
22
#include <limits.h>
23
#include <stddef.h>
24
#include <stdint.h>
25
26
#include <atomic>
27
#include <cstdlib>
28
#include <optional>
29
#include <string>
30
#include <string_view>
31
#include <vector>
32
33
#include "common/status.h"
34
#include "jni_md.h"
35
#include "util/defer_op.h"
36
#include "util/thrift_util.h"
37
38
// defined in hadoop/hadoop-hdfs-project/hadoop-hdfs/src/main/native/libhdfs/jni_helper.c
39
extern "C" JNIEnv* getJNIEnv(void);
40
41
namespace doris {
42
43
#define RETURN_ERROR_IF_EXC(env)                      \
44
364k
    do {                                              \
45
364k
        if (env->ExceptionCheck()) [[unlikely]]       \
46
4
            return Jni::Env::GetJniExceptionMsg(env); \
47
364k
    } while (false)
48
49
//In order to reduce the potential risks caused by not handling exceptions,
50
// you need to refer to  https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html
51
// to confirm whether the jni method will throw an exception.
52
53
namespace Jni {
54
class JvmLauncher;
55
56
class Env {
57
public:
58
315k
    static Status Get(JNIEnv** env) {
59
315k
        if (tls_env_) {
60
315k
            *env = tls_env_;
61
315k
        } else {
62
172
            Status status = GetJNIEnvSlowPath(env);
63
172
            if (!status.ok()) {
64
0
                return status;
65
0
            }
66
172
        }
67
315k
        if (*env == nullptr) [[unlikely]] {
68
0
            return Status::JniError("Failed to get JNIEnv: it is nullptr.");
69
0
        }
70
315k
        return Status::OK();
71
315k
    }
72
73
3
    static Status Init() { return init_throw_exception(); }
74
75
    static Status GetJniExceptionMsg(JNIEnv* env, bool log_stack = true,
76
                                     const std::string& prefix = "") WARN_UNUSED_RESULT;
77
78
private:
79
    static Status GetJNIEnvSlowPath(JNIEnv** env);
80
    // What the JVM of this process was created from, for the one error message that has to
81
    // report a deployment problem rather than a programming one. Says so explicitly when the
82
    // variable is unset, which is what a BE not started by bin/start_be.sh looks like.
83
0
    static std::string class_path_of_this_process() {
84
0
        const char* class_path = getenv("CLASSPATH");
85
0
        return class_path == nullptr ? std::string("<CLASSPATH unset>") : std::string(class_path);
86
0
    }
87
3
    static Status init_throw_exception() {
88
3
        JNIEnv* env = nullptr;
89
3
        RETURN_IF_ERROR(Jni::Env::Get(&env));
90
91
        // Find JniUtil class and create a global ref.
92
3
        jclass local_jni_util_cl = env->FindClass("org/apache/doris/jni/spi/utils/JniUtil");
93
3
        if (local_jni_util_cl == nullptr) {
94
0
            if (env->ExceptionOccurred()) {
95
0
                env->ExceptionDescribe();
96
0
            }
97
            // Named rather than left as a bare FindClass failure: this is the first class BE
98
            // resolves out of the shared layer, so a deployment whose lib/jni/spi is missing or
99
            // was not put on the class path fails exactly here, and the answer is a directory
100
            // name and a jar name. The failure is then cached for the life of the process, so
101
            // this is also the only chance to say it.
102
0
            return Status::JniError(
103
0
                    "Failed to find the JniUtil class of the Java plugin SPI. It ships in "
104
0
                    "doris-jni-spi.jar under DORIS_HOME/lib/jni/spi, which bin/start_be.sh puts "
105
0
                    "on the class path; check that the directory exists and holds "
106
0
                    "doris-jni-spi.jar and doris-jni-bootstrap.jar. Class path: {}",
107
0
                    class_path_of_this_process());
108
0
        }
109
3
        jni_util_cl_ = reinterpret_cast<jclass>(env->NewGlobalRef(local_jni_util_cl));
110
3
        env->DeleteLocalRef(local_jni_util_cl);
111
3
        if (jni_util_cl_ == nullptr) {
112
0
            if (env->ExceptionOccurred()) {
113
0
                env->ExceptionDescribe();
114
0
            }
115
0
            return Status::JniError("Failed to create global reference to JniUtil class.");
116
0
        }
117
3
        if (env->ExceptionOccurred()) {
118
0
            return Status::JniError("Failed to delete local reference to JniUtil class.");
119
0
        }
120
121
        // Throwable toString()
122
3
        throwable_to_string_id_ = env->GetStaticMethodID(
123
3
                jni_util_cl_, "throwableToString", "(Ljava/lang/Throwable;)Ljava/lang/String;");
124
3
        if (throwable_to_string_id_ == nullptr) {
125
0
            if (env->ExceptionOccurred()) {
126
0
                env->ExceptionDescribe();
127
0
            }
128
0
            return Status::JniError("Failed to find JniUtil.throwableToString method.");
129
0
        }
130
131
        // throwableToStackTrace()
132
3
        throwable_to_stack_trace_id_ = env->GetStaticMethodID(
133
3
                jni_util_cl_, "throwableToStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;");
134
3
        if (throwable_to_stack_trace_id_ == nullptr) {
135
0
            if (env->ExceptionOccurred()) {
136
0
                env->ExceptionDescribe();
137
0
            }
138
0
            return Status::JniError("Failed to find JniUtil.throwableToFullStackTrace method.");
139
0
        }
140
3
        return Status::OK();
141
3
    }
142
143
    // Drops the cached JNIEnv of the calling thread. Only the thread exit hook and the JVM
144
    // bootstrap may call this: the env it caches is gone the moment the thread is detached,
145
    // and anything reading it afterwards - another thread exit hook, say - would read freed
146
    // memory.
147
52
    static void reset_tls_env() { tls_env_ = nullptr; }
148
    // Caches an env the bootstrap attached by itself, so that resolving the JNI base right
149
    // after the JVM comes up stays on Get()'s fast path instead of re-entering ensure_jvm().
150
1.09k
    static void set_tls_env(JNIEnv* env) { tls_env_ = env; }
151
    // What Get() would hand out on this thread without asking anyone, nullptr when nothing is
152
    // cached. For JvmLauncher::ScopedVmEnv, which primes the cache for one scope and has to put
153
    // back what it found rather than assume there was nothing: on the bootstrap thread there is.
154
545
    static JNIEnv* tls_env() { return tls_env_; }
155
    friend class JvmLauncher;
156
157
private:
158
    // Thread-local cache of the JNIEnv for this thread.
159
    static __thread JNIEnv* tls_env_;
160
161
    //for exception
162
    static jclass jni_util_cl_;
163
    static jmethodID throwable_to_string_id_;
164
    static jmethodID throwable_to_stack_trace_id_;
165
};
166
167
enum RefType { Local, Global };
168
169
enum BufferType { Chars, ByteArray };
170
171
template <RefType Ref>
172
struct RefHelper {};
173
174
template <>
175
struct RefHelper<Local> {
176
5.41k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewLocalRef(obj); }
177
178
282k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteLocalRef(obj); }
179
180
288k
    static Status get_env(JNIEnv** env) {
181
        // Get the JNIEnv* corresponding to current thread.
182
288k
        return Jni::Env::Get(env);
183
288k
    }
184
};
185
186
template <>
187
struct RefHelper<Global> {
188
10.9k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewGlobalRef(obj); }
189
190
10.9k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteGlobalRef(obj); }
191
192
10.9k
    static Status get_env(JNIEnv** env) { return Jni::Env::Get(env); }
193
};
194
195
template <RefType Ref>
196
class Object;
197
198
template <RefType Ref>
199
class Class;
200
201
class MethodId {
202
public:
203
14.2k
    MethodId() = default;
204
193k
    bool uninitialized() const { return _id == nullptr; }
205
206
    template <RefType U>
207
    friend class Object;
208
209
    template <RefType U>
210
    friend class Class;
211
212
private:
213
    jmethodID _id = nullptr;
214
};
215
216
class FieldId {
217
public:
218
18
    FieldId() = default;
219
36
    bool uninitialized() const { return _id == nullptr; }
220
221
    template <RefType U>
222
    friend class Object;
223
224
    template <RefType U>
225
    friend class Class;
226
227
private:
228
    jfieldID _id = nullptr;
229
};
230
231
enum CallTag {
232
    ObjectMethod,
233
    IntMethod,
234
    LongMethod,
235
    VoidMethod,
236
    BooleanMethod,
237
238
    StaticObjectMethod,
239
    StaticIntMethod,
240
    StaticLongMethod,
241
    StaticVoidMethod,
242
243
    NewObject,
244
245
    NonvirtualVoidMethod,
246
    NonvirtualObjectMethod,
247
    NonvirtualIntMethod,
248
    NonvirtualBooleanMethod,
249
};
250
251
template <CallTag Tag>
252
struct CallHelper {};
253
254
template <>
255
struct CallHelper<ObjectMethod> {
256
131k
    static jobject call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
257
131k
        return env->CallObjectMethodA(obj, methodID, args);
258
131k
    }
259
    using BASE_TYPE = jobject;
260
    using RETURN_TYPE = jobject;
261
};
262
263
template <>
264
struct CallHelper<IntMethod> {
265
1.62k
    static jint call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
266
1.62k
        return env->CallIntMethodA(obj, methodID, args);
267
1.62k
    }
268
    using BASE_TYPE = jobject;
269
    using RETURN_TYPE = jint;
270
};
271
272
template <>
273
struct CallHelper<LongMethod> {
274
20.6k
    static jlong call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
275
20.6k
        return env->CallLongMethodA(obj, methodID, args);
276
20.6k
    }
277
    using BASE_TYPE = jobject;
278
    using RETURN_TYPE = jlong;
279
};
280
281
template <>
282
struct CallHelper<VoidMethod> {
283
269
    static void call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
284
269
        env->CallVoidMethodA(obj, methodID, args);
285
269
    }
286
    using BASE_TYPE = jobject;
287
    using RETURN_TYPE = void;
288
};
289
290
template <>
291
struct CallHelper<BooleanMethod> {
292
6
    static jboolean call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
293
6
        return env->CallBooleanMethodA(obj, methodID, args);
294
6
    }
295
    using BASE_TYPE = jobject;
296
    using RETURN_TYPE = jboolean;
297
};
298
299
template <>
300
struct CallHelper<StaticObjectMethod> {
301
7.58k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
302
7.58k
        return env->CallStaticObjectMethodA(cls, methodID, args);
303
7.58k
    }
304
    using BASE_TYPE = jclass;
305
    using RETURN_TYPE = jobject;
306
};
307
308
template <>
309
struct CallHelper<StaticIntMethod> {
310
0
    static jint call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
311
0
        return env->CallStaticIntMethodA(cls, methodID, args);
312
0
    }
313
    using BASE_TYPE = jclass;
314
    using RETURN_TYPE = jint;
315
};
316
317
template <>
318
struct CallHelper<StaticLongMethod> {
319
0
    static jlong call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
320
0
        return env->CallStaticLongMethodA(cls, methodID, args);
321
0
    }
322
    using BASE_TYPE = jclass;
323
    using RETURN_TYPE = jlong;
324
};
325
326
template <>
327
struct CallHelper<StaticVoidMethod> {
328
928
    static void call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
329
928
        return env->CallStaticVoidMethodA(cls, methodID, args);
330
928
    }
331
332
    using BASE_TYPE = jclass;
333
    using RETURN_TYPE = void;
334
};
335
336
template <>
337
struct CallHelper<NewObject> {
338
5.59k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
339
5.59k
        return env->NewObjectA(cls, methodID, args);
340
5.59k
    }
341
342
    using BASE_TYPE = jclass;
343
    using RETURN_TYPE = jobject;
344
};
345
346
template <>
347
struct CallHelper<NonvirtualVoidMethod> {
348
    static void call_impl(JNIEnv* env, jobject obj, jclass clazz, jmethodID methodID,
349
6.05k
                          const jvalue* args) {
350
6.05k
        return env->CallNonvirtualVoidMethodA(obj, clazz, methodID, args);
351
6.05k
    }
352
353
    using BASE_TYPE = jobject;
354
    using RETURN_TYPE = void;
355
};
356
357
template <>
358
struct CallHelper<NonvirtualObjectMethod> {
359
    static jobject call_impl(JNIEnv* env, jobject obj, jclass clazz, jmethodID methodID,
360
99
                             const jvalue* args) {
361
99
        return env->CallNonvirtualObjectMethodA(obj, clazz, methodID, args);
362
99
    }
363
364
    using BASE_TYPE = jobject;
365
    using RETURN_TYPE = jobject;
366
};
367
368
template <>
369
struct CallHelper<NonvirtualIntMethod> {
370
    static jint call_impl(JNIEnv* env, jobject obj, jclass clazz, jmethodID methodID,
371
0
                          const jvalue* args) {
372
0
        return env->CallNonvirtualIntMethodA(obj, clazz, methodID, args);
373
0
    }
374
375
    using BASE_TYPE = jobject;
376
    using RETURN_TYPE = jint;
377
};
378
379
template <>
380
struct CallHelper<NonvirtualBooleanMethod> {
381
    static jboolean call_impl(JNIEnv* env, jobject obj, jclass clazz, jmethodID methodID,
382
0
                              const jvalue* args) {
383
0
        return env->CallNonvirtualBooleanMethodA(obj, clazz, methodID, args);
384
0
    }
385
386
    using BASE_TYPE = jobject;
387
    using RETURN_TYPE = jboolean;
388
};
389
390
template <CallTag tag>
391
class FunctionCall {
392
public:
393
    FunctionCall(FunctionCall&& other) noexcept = default;
394
395
    static FunctionCall instance(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
396
168k
                                 jmethodID method_id) {
397
168k
        return FunctionCall(env, base, method_id);
398
168k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
7.58k
                                 jmethodID method_id) {
397
7.58k
        return FunctionCall(env, base, method_id);
398
7.58k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
131k
                                 jmethodID method_id) {
397
131k
        return FunctionCall(env, base, method_id);
398
131k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
20.6k
                                 jmethodID method_id) {
397
20.6k
        return FunctionCall(env, base, method_id);
398
20.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
1.62k
                                 jmethodID method_id) {
397
1.62k
        return FunctionCall(env, base, method_id);
398
1.62k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
269
                                 jmethodID method_id) {
397
269
        return FunctionCall(env, base, method_id);
398
269
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
5.60k
                                 jmethodID method_id) {
397
5.60k
        return FunctionCall(env, base, method_id);
398
5.60k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
6
                                 jmethodID method_id) {
397
6
        return FunctionCall(env, base, method_id);
398
6
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
928
                                 jmethodID method_id) {
397
928
        return FunctionCall(env, base, method_id);
398
928
    }
399
400
    /// Pass a primitive arg (eg an integer).
401
    /// Multiple arguments may be passed by repeated calls.
402
    template <class T>
403
        requires std::disjunction_v<std::is_same<T, jboolean>, std::is_same<T, jbyte>,
404
                                    std::is_same<T, jchar>, std::is_same<T, jshort>,
405
                                    std::is_same<T, jint>, std::is_same<T, jlong>,
406
                                    std::is_same<T, jfloat>, std::is_same<T, jdouble>>
407
13.9k
    FunctionCall& with_arg(T arg) {
408
13.9k
        jvalue v;
409
13.9k
        std::memset(&v, 0, sizeof(v));
410
13.9k
        if constexpr (std::is_same_v<T, jboolean>) {
411
246
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
12.2k
        } else if constexpr (std::is_same_v<T, jint>) {
419
12.2k
            v.i = arg;
420
12.2k
        } else if constexpr (std::is_same_v<T, jlong>) {
421
1.37k
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
13.9k
        _args.push_back(v);
430
13.9k
        return *this;
431
13.9k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8with_argIiQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
5.95k
    FunctionCall& with_arg(T arg) {
408
5.95k
        jvalue v;
409
5.95k
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
5.95k
        } else if constexpr (std::is_same_v<T, jint>) {
419
5.95k
            v.i = arg;
420
        } else if constexpr (std::is_same_v<T, jlong>) {
421
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
5.95k
        _args.push_back(v);
430
5.95k
        return *this;
431
5.95k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE8with_argIiQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
5.59k
    FunctionCall& with_arg(T arg) {
408
5.59k
        jvalue v;
409
5.59k
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
5.59k
        } else if constexpr (std::is_same_v<T, jint>) {
419
5.59k
            v.i = arg;
420
        } else if constexpr (std::is_same_v<T, jlong>) {
421
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
5.59k
        _args.push_back(v);
430
5.59k
        return *this;
431
5.59k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argIhQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
246
    FunctionCall& with_arg(T arg) {
408
246
        jvalue v;
409
246
        std::memset(&v, 0, sizeof(v));
410
246
        if constexpr (std::is_same_v<T, jboolean>) {
411
246
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
        } else if constexpr (std::is_same_v<T, jint>) {
419
            v.i = arg;
420
        } else if constexpr (std::is_same_v<T, jlong>) {
421
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
246
        _args.push_back(v);
430
246
        return *this;
431
246
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argIiQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
744
    FunctionCall& with_arg(T arg) {
408
744
        jvalue v;
409
744
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
744
        } else if constexpr (std::is_same_v<T, jint>) {
419
744
            v.i = arg;
420
        } else if constexpr (std::is_same_v<T, jlong>) {
421
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
744
        _args.push_back(v);
430
744
        return *this;
431
744
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
246
    FunctionCall& with_arg(T arg) {
408
246
        jvalue v;
409
246
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
        } else if constexpr (std::is_same_v<T, jint>) {
419
            v.i = arg;
420
246
        } else if constexpr (std::is_same_v<T, jlong>) {
421
246
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
246
        _args.push_back(v);
430
246
        return *this;
431
246
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
205
    FunctionCall& with_arg(T arg) {
408
205
        jvalue v;
409
205
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
        } else if constexpr (std::is_same_v<T, jint>) {
419
            v.i = arg;
420
205
        } else if constexpr (std::is_same_v<T, jlong>) {
421
205
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
205
        _args.push_back(v);
430
205
        return *this;
431
205
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8with_argIiQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
5
    FunctionCall& with_arg(T arg) {
408
5
        jvalue v;
409
5
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
5
        } else if constexpr (std::is_same_v<T, jint>) {
419
5
            v.i = arg;
420
        } else if constexpr (std::is_same_v<T, jlong>) {
421
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
5
        _args.push_back(v);
430
5
        return *this;
431
5
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
928
    FunctionCall& with_arg(T arg) {
408
928
        jvalue v;
409
928
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
        } else if constexpr (std::is_same_v<T, jint>) {
419
            v.i = arg;
420
928
        } else if constexpr (std::is_same_v<T, jlong>) {
421
928
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
928
        _args.push_back(v);
430
928
        return *this;
431
928
    }
432
433
    template <RefType Ref>
434
    FunctionCall& with_arg(const Object<Ref>& obj) WARN_UNUSED_RESULT;
435
436
    template <typename ReturnType>
437
        requires(std::is_same_v<typename CallHelper<tag>::RETURN_TYPE, ReturnType>)
438
22.2k
    Status call(ReturnType* result) {
439
22.2k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
22.2k
        RETURN_ERROR_IF_EXC(_env);
441
22.2k
        return Status::OK();
442
22.2k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE4callIlQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
20.6k
    Status call(ReturnType* result) {
439
20.6k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
20.6k
        RETURN_ERROR_IF_EXC(_env);
441
20.6k
        return Status::OK();
442
20.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE4callIiQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
1.62k
    Status call(ReturnType* result) {
439
1.62k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
1.62k
        RETURN_ERROR_IF_EXC(_env);
441
1.62k
        return Status::OK();
442
1.62k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EE4callIhQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
6
    Status call(ReturnType* result) {
439
6
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
6
        RETURN_ERROR_IF_EXC(_env);
441
6
        return Status::OK();
442
6
    }
443
444
    Status call(Object<Local>* result);
445
446
    Status call(Object<Global>* result);
447
448
18.0k
    Status call() {
449
18.0k
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
450
        if constexpr (std::disjunction_v<
451
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
452
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
453
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
454
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
455
1.19k
                              std::is_same<return_type, void>>) {
456
1.19k
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
1.19k
            RETURN_ERROR_IF_EXC(_env);
458
16.8k
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
16.8k
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
16.8k
            _env->DeleteLocalRef(tmp);
461
16.8k
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
18.0k
        return Status::OK();
466
18.0k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE4callEv
Line
Count
Source
448
266
    Status call() {
449
266
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
450
        if constexpr (std::disjunction_v<
451
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
452
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
453
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
454
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
455
266
                              std::is_same<return_type, void>>) {
456
266
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
266
            RETURN_ERROR_IF_EXC(_env);
458
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
            _env->DeleteLocalRef(tmp);
461
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
266
        return Status::OK();
466
266
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEv
Line
Count
Source
448
16.8k
    Status call() {
449
16.8k
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
450
        if constexpr (std::disjunction_v<
451
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
452
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
453
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
454
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
455
                              std::is_same<return_type, void>>) {
456
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
            RETURN_ERROR_IF_EXC(_env);
458
16.8k
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
16.8k
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
16.8k
            _env->DeleteLocalRef(tmp);
461
16.8k
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
16.8k
        return Status::OK();
466
16.8k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE4callEv
Line
Count
Source
448
928
    Status call() {
449
928
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
450
        if constexpr (std::disjunction_v<
451
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
452
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
453
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
454
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
455
928
                              std::is_same<return_type, void>>) {
456
928
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
928
            RETURN_ERROR_IF_EXC(_env);
458
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
            _env->DeleteLocalRef(tmp);
461
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
928
        return Status::OK();
466
928
    }
467
468
protected:
469
    explicit FunctionCall(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
470
                          jmethodID method_id)
471
174k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
7.58k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
131k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
20.6k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
1.62k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
269
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
5.60k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
6.05k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
99
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
6
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
928
            : _env(env), _base(base), _method(method_id) {}
472
473
    JNIEnv* _env = nullptr;
474
    CallHelper<tag>::BASE_TYPE _base; // is jobject/jclass  not need new/delete local/global ref.
475
    const jmethodID _method = nullptr;
476
    std::vector<jvalue> _args;
477
    Status _st = Status::OK();
478
    DISALLOW_COPY_AND_ASSIGN(FunctionCall);
479
};
480
481
template <CallTag tag>
482
class NonvirtualFunctionCall : public FunctionCall<tag> {
483
public:
484
    NonvirtualFunctionCall(NonvirtualFunctionCall&& other) noexcept = default;
485
486
    static NonvirtualFunctionCall instance(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
487
6.15k
                                           jclass cls, jmethodID method_id) {
488
6.15k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
6.15k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
6.05k
                                           jclass cls, jmethodID method_id) {
488
6.05k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
6.05k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
99
                                           jclass cls, jmethodID method_id) {
488
99
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
99
    }
490
491
    // no override
492
    template <class T>
493
        requires std::disjunction_v<std::is_same<T, jboolean>, std::is_same<T, jbyte>,
494
                                    std::is_same<T, jchar>, std::is_same<T, jshort>,
495
                                    std::is_same<T, jint>, std::is_same<T, jlong>,
496
                                    std::is_same<T, jfloat>, std::is_same<T, jdouble>>
497
234
    NonvirtualFunctionCall& with_arg(T arg) {
498
234
        jvalue v;
499
234
        std::memset(&v, 0, sizeof(v));
500
        if constexpr (std::is_same_v<T, jboolean>) {
501
            v.z = arg;
502
        } else if constexpr (std::is_same_v<T, jbyte>) {
503
            v.b = arg;
504
        } else if constexpr (std::is_same_v<T, jchar>) {
505
            v.c = arg;
506
        } else if constexpr (std::is_same_v<T, jshort>) {
507
            v.s = arg;
508
        } else if constexpr (std::is_same_v<T, jint>) {
509
            v.i = arg;
510
234
        } else if constexpr (std::is_same_v<T, jlong>) {
511
234
            v.j = arg;
512
        } else if constexpr (std::is_same_v<T, jfloat>) {
513
            v.f = arg;
514
        } else if constexpr (std::is_same_v<T, jdouble>) {
515
            v.d = arg;
516
        } else {
517
            static_assert(false);
518
        }
519
234
        this->_args.push_back(v);
520
234
        return *this;
521
234
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
497
135
    NonvirtualFunctionCall& with_arg(T arg) {
498
135
        jvalue v;
499
135
        std::memset(&v, 0, sizeof(v));
500
        if constexpr (std::is_same_v<T, jboolean>) {
501
            v.z = arg;
502
        } else if constexpr (std::is_same_v<T, jbyte>) {
503
            v.b = arg;
504
        } else if constexpr (std::is_same_v<T, jchar>) {
505
            v.c = arg;
506
        } else if constexpr (std::is_same_v<T, jshort>) {
507
            v.s = arg;
508
        } else if constexpr (std::is_same_v<T, jint>) {
509
            v.i = arg;
510
135
        } else if constexpr (std::is_same_v<T, jlong>) {
511
135
            v.j = arg;
512
        } else if constexpr (std::is_same_v<T, jfloat>) {
513
            v.f = arg;
514
        } else if constexpr (std::is_same_v<T, jdouble>) {
515
            v.d = arg;
516
        } else {
517
            static_assert(false);
518
        }
519
135
        this->_args.push_back(v);
520
135
        return *this;
521
135
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
497
99
    NonvirtualFunctionCall& with_arg(T arg) {
498
99
        jvalue v;
499
99
        std::memset(&v, 0, sizeof(v));
500
        if constexpr (std::is_same_v<T, jboolean>) {
501
            v.z = arg;
502
        } else if constexpr (std::is_same_v<T, jbyte>) {
503
            v.b = arg;
504
        } else if constexpr (std::is_same_v<T, jchar>) {
505
            v.c = arg;
506
        } else if constexpr (std::is_same_v<T, jshort>) {
507
            v.s = arg;
508
        } else if constexpr (std::is_same_v<T, jint>) {
509
            v.i = arg;
510
99
        } else if constexpr (std::is_same_v<T, jlong>) {
511
99
            v.j = arg;
512
        } else if constexpr (std::is_same_v<T, jfloat>) {
513
            v.f = arg;
514
        } else if constexpr (std::is_same_v<T, jdouble>) {
515
            v.d = arg;
516
        } else {
517
            static_assert(false);
518
        }
519
99
        this->_args.push_back(v);
520
99
        return *this;
521
99
    }
522
523
    template <RefType Ref>
524
    NonvirtualFunctionCall& with_arg(const Object<Ref>& obj) WARN_UNUSED_RESULT;
525
526
    // no override
527
6.04k
    Status call() {
528
6.04k
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
529
        if constexpr (std::disjunction_v<
530
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
531
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
532
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
533
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
534
6.04k
                              std::is_same<return_type, void>>) {
535
6.04k
            CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
536
6.04k
                                       this->_args.data());
537
6.04k
            RETURN_ERROR_IF_EXC(this->_env);
538
        } else if constexpr (std::is_same_v<return_type, jobject>) {
539
            jobject tmp = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
540
                                                     this->_args.data());
541
            RETURN_ERROR_IF_EXC(this->_env);
542
            this->_env->DeleteLocalRef(tmp);
543
        } else {
544
            static_assert(false);
545
        }
546
6.04k
        return Status::OK();
547
6.04k
    }
548
549
    Status call(Object<Local>* result);
550
551
    template <typename ReturnType>
552
        requires(std::is_same_v<typename CallHelper<tag>::RETURN_TYPE, ReturnType>)
553
    Status call(ReturnType* result) {
554
        *result = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
555
                                             this->_args.data());
556
        RETURN_ERROR_IF_EXC(this->_env);
557
        return Status::OK();
558
    }
559
560
private:
561
    explicit NonvirtualFunctionCall(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
562
                                    jclass cls, jmethodID method_id)
563
6.15k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
6.05k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
99
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
564
    jclass _cls;
565
    DISALLOW_COPY_AND_ASSIGN(NonvirtualFunctionCall);
566
};
567
568
/**
569
 * When writing JNI code, developers usually need to pay extra attention to several error-prone aspects, including:
570
 * 1. The reference type of jobject (local vs. global)
571
 * 2. The lifetime and scope of JNI references
572
 * 3. Proper release of references after use
573
 * 4. Explicit exception checking after JNI calls
574
 * Because these concerns are verbose and easy to overlook, they often lead to bugs or inconsistent code. To simplify this, 
575
 * we provide a wrapper framework around raw JNI APIs. The following describes how to use it (assuming the user already 
576
 * understands the basic JNI programming model).
577
 *
578
 * 0. Get JNIEnv* env: `Status st = Jni::Env::Get(&env)`
579
 * 1. Choose the reference type
580
 *   First, determine whether the JNI object should be a local or global reference. Based on this, create the corresponding C++ wrapper object:
581
 *   LocalObject / GlobalObject. If the exact JNI type is known, use specialized wrappers such as <Local/Global><Array/String/Class>. 
582
 * 2. Initialize the object
583
 *   For `jclass`, typically use: `Status st = Jni::Util::find_class(xxx);`
584
 *   For other object types, they are usually initialized via: `Status st = clazz.new_object(xxx).with_arg(xxx).call(&object) or by calling methods on existing objects.
585
 * 3. Call methods and retrieve results
586
 *   To invoke a method and obtain a return value, use: `Status st = object.call_<return_type>_method(xxx).call(&result);` 
587
 * 
588
 * Notes
589
 * 1. All JNI references are automatically released in the wrapper’s destructor, ensuring safe and deterministic cleanup.
590
 * 2. All framework method invocations return a Status.
591
 * The actual JNI return value is written to the address passed to call().
592
 * 
593
 * Example: be/test/util/jni_util_test.cpp
594
*/
595
template <RefType Ref>
596
class Object {
597
    // env->GetObjectRefType
598
public:
599
311k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
599
11.2k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
599
299k
    Object() = default;
600
601
    template <RefType U>
602
    friend class Object;
603
604
    template <RefType U>
605
    friend class Class;
606
607
    template <RefType U>
608
    friend class String;
609
610
    template <RefType U>
611
    friend class Array;
612
613
    template <BufferType bufferfType, RefType U>
614
    friend class BufferGuard;
615
616
    template <CallTag tag>
617
    friend class FunctionCall;
618
619
    template <CallTag tag>
620
    friend class NonvirtualFunctionCall;
621
622
310k
    virtual ~Object() {
623
310k
        if (_obj != nullptr) [[likely]] {
624
293k
            JNIEnv* env = nullptr;
625
293k
            if (Status st = RefHelper<Ref>::get_env(&env); !st.ok()) [[unlikely]] {
626
0
                LOG(WARNING) << "Can't destroy Jni Ref : " << st.msg();
627
0
                return;
628
0
            }
629
293k
            RefHelper<Ref>::destroy(env, _obj);
630
293k
        }
631
310k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EED2Ev
Line
Count
Source
622
299k
    virtual ~Object() {
623
299k
        if (_obj != nullptr) [[likely]] {
624
282k
            JNIEnv* env = nullptr;
625
282k
            if (Status st = RefHelper<Ref>::get_env(&env); !st.ok()) [[unlikely]] {
626
0
                LOG(WARNING) << "Can't destroy Jni Ref : " << st.msg();
627
0
                return;
628
0
            }
629
282k
            RefHelper<Ref>::destroy(env, _obj);
630
282k
        }
631
299k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EED2Ev
Line
Count
Source
622
11.2k
    virtual ~Object() {
623
11.2k
        if (_obj != nullptr) [[likely]] {
624
10.9k
            JNIEnv* env = nullptr;
625
10.9k
            if (Status st = RefHelper<Ref>::get_env(&env); !st.ok()) [[unlikely]] {
626
0
                LOG(WARNING) << "Can't destroy Jni Ref : " << st.msg();
627
0
                return;
628
0
            }
629
10.9k
            RefHelper<Ref>::destroy(env, _obj);
630
10.9k
        }
631
11.2k
    }
632
633
    template <RefType R>
634
16.3k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
16.3k
        DCHECK(!other.uninitialized());
636
16.3k
        DCHECK(result->uninitialized());
637
638
16.3k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
16.3k
        RETURN_ERROR_IF_EXC(env);
640
16.3k
        return Status::OK();
641
16.3k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
10.9k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
10.9k
        DCHECK(!other.uninitialized());
636
10.9k
        DCHECK(result->uninitialized());
637
638
10.9k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
10.9k
        RETURN_ERROR_IF_EXC(env);
640
10.9k
        return Status::OK();
641
10.9k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
5.41k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
5.41k
        DCHECK(!other.uninitialized());
636
5.41k
        DCHECK(result->uninitialized());
637
638
5.41k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
5.41k
        RETURN_ERROR_IF_EXC(env);
640
5.41k
        return Status::OK();
641
5.41k
    }
642
643
1.14M
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE13uninitializedEv
Line
Count
Source
643
873k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE13uninitializedEv
Line
Count
Source
643
266k
    bool uninitialized() const { return _obj == nullptr; }
644
645
    // Access the JNI handle without changing ownership.
646
1
    jobject get() const { return _obj; }
Unexecuted instantiation: _ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE3getEv
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE3getEv
Line
Count
Source
646
1
    jobject get() const { return _obj; }
647
648
2
    void reset(JNIEnv* env) {
649
2
        if (_obj == nullptr) {
650
0
            return;
651
0
        }
652
2
        RefHelper<Ref>::destroy(env, _obj);
653
2
        _obj = nullptr;
654
2
    }
655
656
    template <RefType T>
657
191k
    bool equal(JNIEnv* env, const Object<T>& other) {
658
191k
        DCHECK(!uninitialized());
659
191k
        DCHECK(!other.uninitialized());
660
191k
        return env->IsSameObject(this->_obj, other._obj); //assume not throw exception.
661
191k
    }
662
663
131k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
131k
        DCHECK(!this->uninitialized());
665
131k
        DCHECK(!method_id.uninitialized());
666
131k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
131k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
663
131k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
131k
        DCHECK(!this->uninitialized());
665
        DCHECK(!method_id.uninitialized());
666
131k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
131k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
663
2
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
2
        DCHECK(!this->uninitialized());
665
        DCHECK(!method_id.uninitialized());
666
2
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
2
    }
668
669
1.62k
    FunctionCall<IntMethod> call_int_method(JNIEnv* env, MethodId method_id) const {
670
1.62k
        DCHECK(!this->uninitialized());
671
1.62k
        DCHECK(!method_id.uninitialized());
672
1.62k
        return FunctionCall<IntMethod>::instance(env, _obj, method_id._id);
673
1.62k
    }
674
675
20.6k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
20.6k
        DCHECK(!this->uninitialized());
677
20.6k
        DCHECK(!method_id.uninitialized());
678
20.6k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
20.6k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
17.8k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
17.8k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
17.8k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
17.8k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
2.78k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
2.78k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
2.78k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
2.78k
    }
680
681
268
    FunctionCall<VoidMethod> call_void_method(JNIEnv* env, MethodId method_id) const {
682
268
        DCHECK(!this->uninitialized());
683
268
        DCHECK(!method_id.uninitialized());
684
268
        return FunctionCall<VoidMethod>::instance(env, _obj, method_id._id);
685
268
    }
686
687
6
    FunctionCall<BooleanMethod> call_boolean_method(JNIEnv* env, MethodId method_id) const {
688
6
        DCHECK(!this->uninitialized());
689
6
        DCHECK(!method_id.uninitialized());
690
6
        return FunctionCall<BooleanMethod>::instance(env, _obj, method_id._id);
691
6
    }
692
693
    template <RefType R>
694
    NonvirtualFunctionCall<NonvirtualVoidMethod> call_nonvirtual_void_method(
695
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
696
697
    template <RefType R>
698
    NonvirtualFunctionCall<NonvirtualObjectMethod> call_nonvirtual_object_method(
699
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
700
701
    template <RefType R>
702
    NonvirtualFunctionCall<NonvirtualIntMethod> call_nonvirtual_int_method(
703
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
704
705
    template <RefType R>
706
    NonvirtualFunctionCall<NonvirtualBooleanMethod> call_nonvirtual_boolean_method(
707
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
708
709
protected:
710
    jobject _obj = nullptr;
711
    DISALLOW_COPY_AND_ASSIGN(Object);
712
};
713
714
using LocalObject = Object<Local>;
715
using GlobalObject = Object<Global>;
716
717
static inline Status local_to_global_ref(JNIEnv* env, const LocalObject& local_ref,
718
10.9k
                                         GlobalObject* global_ref) {
719
10.9k
    return Object<Global>::create(env, local_ref, global_ref);
720
10.9k
}
Unexecuted instantiation: doris_main.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_0_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: config.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: doris_metrics.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
jvm_metrics.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Line
Count
Source
718
62
                                         GlobalObject* global_ref) {
719
62
    return Object<Global>::create(env, local_ref, global_ref);
720
62
}
Unexecuted instantiation: unity_14_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_2_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_3_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_5_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_15_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
unity_1_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Line
Count
Source
718
10.9k
                                         GlobalObject* global_ref) {
719
10.9k
    return Object<Global>::create(env, local_ref, global_ref);
720
10.9k
}
Unexecuted instantiation: unity_8_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_9_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_10_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_4_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_13_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_12_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_11_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_7_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_6_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: hashjoin_build_sink.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: join_build_sink_operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: partitioned_aggregation_sink_operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: scan_operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vfile_result_writer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_32_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_31_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_30_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_29_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_28_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_27_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_26_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_25_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_24_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_22_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_21_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_20_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_19_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_18_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_17_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_16_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: ai_functions.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: function_array_aggregation.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: function_date_or_datetime_computation.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: function_datetime_floor_ceil.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: in.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: uuid.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: arrow_row_batch.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: jni_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: iceberg_delete_file_reader_helper.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_disk_usage_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: jdbc_jni_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: parquet_metadata_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: schema_desc.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: parquet_utils.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: parquet_column_convert.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: column_type_convert.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: iceberg_partition_function.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: merge_partitioner.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vcsv_transformer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vfile_format_transformer_factory.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: viceberg_parquet_writer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vjni_format_transformer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vorc_transformer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vparquet_writer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: adbc_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: hdfs_file_system.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_23_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_compound_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_disk_usage.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_fs_directory.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: zone_map_index.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vcollect_iterator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: predicate_creator_comparison.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: predicate_creator_in_list_in.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: predicate_creator_in_list_not_in.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: tablet.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: engine_clone_task.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: descriptors.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: backend_service.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: point_query_executor.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: be_server_starter_factory.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: http_service.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: internal_service.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: arrow_flight_batch_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: thrift_util.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: load_stream.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: routine_load_task_executor.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: cloud_compaction_action.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
721
722
// auto ReleaseStringUTFChars ReleaseByteArrayElements ...
723
template <BufferType bufferfType, RefType Ref>
724
class BufferGuard {
725
public:
726
5.41k
    BufferGuard() = default;
727
728
    template <RefType R>
729
    static Status create(JNIEnv* env, const Object<R>& object,
730
5.41k
                         BufferGuard<bufferfType, Ref>* result, jboolean* isCopy) {
731
5.41k
        DCHECK(result->_buffer == nullptr && result->_object.uninitialized());
732
733
5.41k
        RETURN_IF_ERROR(Object<Ref>::create(env, object, &result->_object));
734
735
5.41k
        if constexpr (bufferfType == BufferType::Chars) {
736
5.41k
            result->_buffer = env->GetStringUTFChars((jstring)result->_object._obj, isCopy);
737
        } else if constexpr (bufferfType == BufferType::ByteArray) {
738
            result->_buffer =
739
                    (char*)env->GetByteArrayElements((jbyteArray)result->_object._obj, isCopy);
740
        } else {
741
            static_assert(false);
742
        }
743
744
5.41k
        RETURN_ERROR_IF_EXC(env);
745
5.41k
        if (result->_buffer == nullptr) [[unlikely]] {
746
0
            return Status::JniError("GetStringUTFChars/GetByteArrayElements fail.");
747
0
        }
748
749
5.41k
        return Status::OK();
750
5.41k
    }
751
752
5.41k
    ~BufferGuard() {
753
5.41k
        if (_object.uninitialized() || _buffer == nullptr) [[unlikely]] {
754
0
            return;
755
0
        }
756
5.41k
        JNIEnv* env = nullptr;
757
758
5.41k
        if (auto st = RefHelper<Ref>::get_env(&env); !st.ok()) [[unlikely]] {
759
0
            LOG(WARNING) << "BufferGuard release fail: " << st;
760
0
            return;
761
0
        }
762
763
5.41k
        if constexpr (bufferfType == BufferType::Chars) {
764
5.41k
            env->ReleaseStringUTFChars((jstring)_object._obj, _buffer);
765
        } else if constexpr (bufferfType == BufferType::ByteArray) {
766
            env->ReleaseByteArrayElements((jbyteArray)_object._obj, (jbyte*)_buffer, JNI_ABORT);
767
        }
768
5.41k
    }
769
770
10.8k
    const char* get() const { return _buffer; }
771
772
private:
773
    Object<Ref> _object;
774
    const char* _buffer = nullptr;
775
776
    DISALLOW_COPY_AND_ASSIGN(BufferGuard);
777
};
778
779
template <RefType Ref>
780
using StringBufferGuard = BufferGuard<Chars, Ref>;
781
using LocalStringBufferGuard = BufferGuard<Chars, Local>;
782
using GlobalStringBufferGuard = BufferGuard<Chars, Global>;
783
784
template <RefType Ref>
785
using ByteArrayBufferGuard = BufferGuard<ByteArray, Ref>;
786
using LocalByteArrayBufferGuard = BufferGuard<ByteArray, Local>;
787
using GlobalByteArrayBufferGuard = BufferGuard<ByteArray, Global>;
788
789
// Reads a borrowed Java String as standard UTF-8 without taking ownership of the reference.
790
Status get_string_utf8(JNIEnv* env, jstring value, std::string* result);
791
792
template <RefType Ref>
793
class String : public Object<Ref> {
794
public:
795
50.9k
    String() = default;
796
797
    // Accepts JNI modified UTF-8. Use new_string_utf8 for standard UTF-8, e.g. scanner SQL.
798
10.8k
    static Status new_string(JNIEnv* env, const char* utf_chars, String<Ref>* result) {
799
10.8k
        DCHECK(result->uninitialized());
800
801
10.8k
        if constexpr (Ref == Local) {
802
10.8k
            result->_obj = env->NewStringUTF(utf_chars);
803
10.8k
            RETURN_ERROR_IF_EXC(env);
804
        } else if constexpr (Ref == Global) {
805
            String<Local> local_result;
806
            RETURN_IF_ERROR(String<Local>::new_string(env, utf_chars, &local_result));
807
            RETURN_IF_ERROR(local_to_global_ref(env, local_result, result));
808
        } else {
809
            static_assert(false);
810
        }
811
        // JNI allocation may return null without a pending exception.
812
10.8k
        if (result->uninitialized()) {
813
1
            return Status::JniError("Failed to allocate modified UTF-8 Java string reference");
814
1
        }
815
10.8k
        return Status::OK();
816
10.8k
    }
817
818
    // Decodes standard UTF-8, including supplementary characters and embedded NULs.
819
    static Status new_string_utf8(JNIEnv* env, std::string_view utf_chars, String<Ref>* result);
820
821
5.41k
    Status get_string_chars(JNIEnv* env, StringBufferGuard<Ref>* jni_chars) const {
822
5.41k
        return StringBufferGuard<Ref>::create(env, *this, jni_chars, nullptr);
823
5.41k
    }
824
825
    // Unlike get_string_chars (JNI modified UTF-8), preserves standard UTF-8 and embedded NULs.
826
    // Rejects unpaired UTF-16 surrogates instead of replacing them.
827
8
    Status get_string_utf8(JNIEnv* env, std::string* result) const {
828
8
        DCHECK(!this->uninitialized());
829
8
        return Jni::get_string_utf8(env, static_cast<jstring>(this->_obj), result);
830
8
    }
831
832
private:
833
    DISALLOW_COPY_AND_ASSIGN(String);
834
};
835
836
extern template Status String<Local>::new_string_utf8(JNIEnv*, std::string_view, String<Local>*);
837
extern template Status String<Global>::new_string_utf8(JNIEnv*, std::string_view, String<Global>*);
838
839
template <RefType Ref>
840
class Array : public Object<Ref> {
841
public:
842
6.74k
    Array() = default;
843
844
639
    Status get_length(JNIEnv* env, jsize* result) const {
845
639
        DCHECK(!this->uninitialized());
846
847
639
        *result = env->GetArrayLength((jarray)this->_obj);
848
639
        RETURN_ERROR_IF_EXC(env);
849
639
        return Status::OK();
850
639
    }
851
852
93.0k
    Status get_object_array_element(JNIEnv* env, jsize index, Jni::LocalObject* result) {
853
93.0k
        DCHECK(!this->uninitialized());
854
93.0k
        DCHECK(result->uninitialized());
855
93.0k
        result->_obj = env->GetObjectArrayElement((jobjectArray)this->_obj, index);
856
93.0k
        RETURN_ERROR_IF_EXC(env);
857
93.0k
        return Status::OK();
858
93.0k
    }
859
860
    Status get_byte_elements(JNIEnv* env, ByteArrayBufferGuard<Ref>* jni_bytes) const {
861
        DCHECK(!this->uninitialized());
862
        return ByteArrayBufferGuard<Ref>::create(env, *this, jni_bytes, nullptr);
863
    }
864
865
99
    Status get_byte_elements(JNIEnv* env, jsize start, jsize len, jbyte* buffer) {
866
99
        DCHECK(!this->uninitialized());
867
99
        env->GetByteArrayRegion((jbyteArray)this->_obj, start, len, buffer);
868
99
        RETURN_ERROR_IF_EXC(env);
869
99
        return Status::OK();
870
99
    }
871
872
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
873
5.49k
                                         Array<Local>* serialized_msg) {
874
5.49k
        DCHECK(serialized_msg->uninitialized());
875
        /// create jbyteArray given buffer
876
5.49k
        serialized_msg->_obj = env->NewByteArray(size);
877
5.49k
        RETURN_ERROR_IF_EXC(env);
878
5.49k
        if (serialized_msg->_obj == nullptr) [[unlikely]] {
879
0
            return Status::JniError("couldn't construct jbyteArray");
880
0
        }
881
5.49k
        env->SetByteArrayRegion((jbyteArray)serialized_msg->_obj, 0, size, buffer);
882
5.49k
        RETURN_ERROR_IF_EXC(env);
883
5.49k
        return Status::OK();
884
5.49k
    }
885
886
    template <class T>
887
5.44k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Local>* serialized_msg) {
888
5.44k
        int buffer_size = 100 * 1024; // start out with 100KB
889
5.44k
        ThriftSerializer serializer(false, buffer_size);
890
891
5.44k
        uint8_t* buffer = nullptr;
892
5.44k
        uint32_t size = 0;
893
5.44k
        RETURN_IF_ERROR(serializer.serialize(msg, &size, &buffer));
894
895
        // Make sure that 'size' is within the limit of INT_MAX as the use of
896
        // 'size' below takes int.
897
5.44k
        if (size > INT_MAX) [[unlikely]] {
898
0
            return Status::JniError(
899
0
                    "The length of the serialization buffer ({} bytes) exceeds the limit of {} "
900
0
                    "bytes",
901
0
                    size, INT_MAX);
902
0
        }
903
5.44k
        RETURN_IF_ERROR(WriteBufferToByteArray(env, (jbyte*)buffer, size, serialized_msg));
904
5.44k
        return Status::OK();
905
5.44k
    }
906
907
private:
908
    DISALLOW_COPY_AND_ASSIGN(Array);
909
};
910
911
template <RefType Ref>
912
class Class : public Object<Ref> {
913
public:
914
11.1k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
914
5.61k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
914
5.48k
    Class() = default;
915
916
46
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
917
46
        DCHECK(result->uninitialized());
918
46
        if constexpr (Ref == Local) {
919
2
            result->_obj = env->FindClass(class_str);
920
2
            RETURN_ERROR_IF_EXC(env);
921
2
            return Status::OK();
922
44
        } else if constexpr (Ref == Global) {
923
44
            Class<Local> local_class;
924
44
            local_class._obj = env->FindClass(class_str);
925
44
            RETURN_ERROR_IF_EXC(env);
926
44
            return local_to_global_ref(env, local_class, result);
927
        } else {
928
            static_assert(false);
929
        }
930
46
    }
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EE10find_classEP7JNIEnv_PKcPS3_
Line
Count
Source
916
44
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
917
44
        DCHECK(result->uninitialized());
918
        if constexpr (Ref == Local) {
919
            result->_obj = env->FindClass(class_str);
920
            RETURN_ERROR_IF_EXC(env);
921
            return Status::OK();
922
44
        } else if constexpr (Ref == Global) {
923
44
            Class<Local> local_class;
924
44
            local_class._obj = env->FindClass(class_str);
925
44
            RETURN_ERROR_IF_EXC(env);
926
44
            return local_to_global_ref(env, local_class, result);
927
        } else {
928
            static_assert(false);
929
        }
930
44
    }
_ZN5doris3Jni5ClassILNS0_7RefTypeE0EE10find_classEP7JNIEnv_PKcPS3_
Line
Count
Source
916
2
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
917
2
        DCHECK(result->uninitialized());
918
2
        if constexpr (Ref == Local) {
919
2
            result->_obj = env->FindClass(class_str);
920
2
            RETURN_ERROR_IF_EXC(env);
921
2
            return Status::OK();
922
        } else if constexpr (Ref == Global) {
923
            Class<Local> local_class;
924
            local_class._obj = env->FindClass(class_str);
925
            RETURN_ERROR_IF_EXC(env);
926
            return local_to_global_ref(env, local_class, result);
927
        } else {
928
            static_assert(false);
929
        }
930
2
    }
931
932
    /**
933
     * The class of an object that is already in hand.
934
     *
935
     * Needed where a class cannot be named: an object produced by a plugin is an instance of a
936
     * class inside that plugin's classloader, which FindClass - searching BE's own loader -
937
     * cannot see. Asking the object is the only way to reach it.
938
     */
939
    template <RefType R>
940
5.42k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
5.42k
        DCHECK(!object.uninitialized());
942
5.42k
        DCHECK(result->uninitialized());
943
5.42k
        if constexpr (Ref == Local) {
944
0
            result->_obj = env->GetObjectClass(object._obj);
945
0
            RETURN_ERROR_IF_EXC(env);
946
0
            return Status::OK();
947
5.42k
        } else if constexpr (Ref == Global) {
948
5.42k
            Class<Local> local_class;
949
5.42k
            local_class._obj = env->GetObjectClass(object._obj);
950
5.42k
            RETURN_ERROR_IF_EXC(env);
951
5.42k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
5.42k
    }
Unexecuted instantiation: _ZN5doris3Jni5ClassILNS0_7RefTypeE0EE16get_object_classILS2_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT_EEEPS3_
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EE16get_object_classILS2_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT_EEEPS3_
Line
Count
Source
940
5.42k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
5.42k
        DCHECK(!object.uninitialized());
942
5.42k
        DCHECK(result->uninitialized());
943
        if constexpr (Ref == Local) {
944
            result->_obj = env->GetObjectClass(object._obj);
945
            RETURN_ERROR_IF_EXC(env);
946
            return Status::OK();
947
5.42k
        } else if constexpr (Ref == Global) {
948
5.42k
            Class<Local> local_class;
949
5.42k
            local_class._obj = env->GetObjectClass(object._obj);
950
5.42k
            RETURN_ERROR_IF_EXC(env);
951
5.42k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
5.42k
    }
956
957
    /**
958
     * Whether an object is an instance of this class.
959
     *
960
     * The one way to check the kind of something a plugin handed back: the object's own class is
961
     * private to the plugin's classloader, so the only comparable identity is a shared base class
962
     * BE resolved itself. IsInstanceOf raises no exception, hence the plain bool.
963
     */
964
    template <RefType R>
965
5
    bool is_instance(JNIEnv* env, const Object<R>& object) const {
966
5
        DCHECK(!this->uninitialized());
967
5
        DCHECK(!object.uninitialized());
968
5
        return env->IsInstanceOf(object._obj, (jclass)this->_obj) == JNI_TRUE;
969
5
    }
970
971
    Status get_static_method(JNIEnv* env, const char* method_str, const char* method_signature,
972
17
                             MethodId* method_id) const {
973
17
        DCHECK(!this->uninitialized());
974
17
        DCHECK(method_id->uninitialized());
975
17
        method_id->_id = env->GetStaticMethodID((jclass)this->_obj, method_str, method_signature);
976
17
        RETURN_ERROR_IF_EXC(env);
977
17
        return Status::OK();
978
17
    }
979
980
    Status get_method(JNIEnv* env, const char* method_str, const char* method_signature,
981
13.1k
                      MethodId* method_id) const {
982
13.1k
        DCHECK(!this->uninitialized());
983
13.1k
        DCHECK(method_id->uninitialized());
984
13.1k
        method_id->_id = env->GetMethodID((jclass)this->_obj, method_str, method_signature);
985
13.1k
        RETURN_ERROR_IF_EXC(env);
986
13.1k
        return Status::OK();
987
13.1k
    }
988
989
    Status get_static_fieldId(JNIEnv* env, const char* name, const char* signature,
990
18
                              FieldId* field_id) const {
991
18
        DCHECK(!this->uninitialized());
992
18
        DCHECK(field_id->uninitialized());
993
18
        field_id->_id = env->GetStaticFieldID((jclass)this->_obj, name, signature);
994
18
        RETURN_ERROR_IF_EXC(env);
995
18
        return Status::OK();
996
18
    }
997
998
    Status get_static_object_field(JNIEnv* env, const FieldId& field_id,
999
                                   Object<Local>* result) const {
1000
        DCHECK(!this->uninitialized());
1001
        DCHECK(!field_id.uninitialized());
1002
        result->_obj = env->GetStaticObjectField((jclass)this->_obj, field_id._id);
1003
        RETURN_ERROR_IF_EXC(env);
1004
        return Status::OK();
1005
    }
1006
1007
    Status get_static_object_field(JNIEnv* env, const FieldId& field_id,
1008
18
                                   Object<Global>* global_result) const {
1009
18
        DCHECK(!this->uninitialized());
1010
18
        DCHECK(!field_id.uninitialized());
1011
18
        Object<Local> local_result;
1012
18
        local_result._obj = env->GetStaticObjectField((jclass)this->_obj, field_id._id);
1013
18
        RETURN_ERROR_IF_EXC(env);
1014
18
        return local_to_global_ref(env, local_result, global_result);
1015
18
    }
1016
1017
    Status get_static_object_field(JNIEnv* env, const char* name, const char* signature,
1018
18
                                   Object<Global>* global_result) const {
1019
18
        Jni::FieldId tmpFieldID;
1020
18
        RETURN_IF_ERROR(get_static_fieldId(env, name, signature, &tmpFieldID));
1021
18
        RETURN_IF_ERROR(get_static_object_field(env, tmpFieldID, global_result));
1022
18
        return Status::OK();
1023
18
    }
1024
1025
5.59k
    FunctionCall<NewObject> new_object(JNIEnv* env, MethodId method_id) const {
1026
5.59k
        DCHECK(!this->uninitialized());
1027
5.59k
        DCHECK(!method_id.uninitialized());
1028
5.59k
        return FunctionCall<NewObject>::instance(env, (jclass)this->_obj, method_id._id);
1029
5.59k
    }
1030
1031
    FunctionCall<StaticObjectMethod> call_static_object_method(JNIEnv* env,
1032
7.56k
                                                               MethodId method_id) const {
1033
7.56k
        DCHECK(!this->uninitialized());
1034
7.56k
        DCHECK(!method_id.uninitialized());
1035
7.56k
        return FunctionCall<StaticObjectMethod>::instance(env, (jclass)this->_obj, method_id._id);
1036
7.56k
    }
1037
1038
928
    FunctionCall<StaticVoidMethod> call_static_void_method(JNIEnv* env, MethodId method_id) const {
1039
928
        DCHECK(!this->uninitialized());
1040
928
        DCHECK(!method_id.uninitialized());
1041
928
        return FunctionCall<StaticVoidMethod>::instance(env, (jclass)this->_obj, method_id._id);
1042
928
    }
1043
1044
private:
1045
    DISALLOW_COPY_AND_ASSIGN(Class);
1046
};
1047
1048
using LocalClass = Class<Local>;
1049
using GlobalClass = Class<Global>;
1050
1051
using LocalArray = Array<Local>;
1052
using GlobalArray = Array<Global>;
1053
1054
using LocalString = String<Local>;
1055
using GlobalString = String<Global>;
1056
1057
template <CallTag tag>
1058
template <RefType Ref>
1059
57.1k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
57.1k
    jvalue v;
1061
57.1k
    std::memset(&v, 0, sizeof(v));
1062
57.1k
    v.l = obj._obj;
1063
57.1k
    _args.push_back(v);
1064
57.1k
    return *this;
1065
57.1k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
34.2k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
34.2k
    jvalue v;
1061
34.2k
    std::memset(&v, 0, sizeof(v));
1062
34.2k
    v.l = obj._obj;
1063
34.2k
    _args.push_back(v);
1064
34.2k
    return *this;
1065
34.2k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
245
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
245
    jvalue v;
1061
245
    std::memset(&v, 0, sizeof(v));
1062
245
    v.l = obj._obj;
1063
245
    _args.push_back(v);
1064
245
    return *this;
1065
245
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
5.35k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
5.35k
    jvalue v;
1061
5.35k
    std::memset(&v, 0, sizeof(v));
1062
5.35k
    v.l = obj._obj;
1063
5.35k
    _args.push_back(v);
1064
5.35k
    return *this;
1065
5.35k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
16.3k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
16.3k
    jvalue v;
1061
16.3k
    std::memset(&v, 0, sizeof(v));
1062
16.3k
    v.l = obj._obj;
1063
16.3k
    _args.push_back(v);
1064
16.3k
    return *this;
1065
16.3k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
928
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
928
    jvalue v;
1061
928
    std::memset(&v, 0, sizeof(v));
1062
928
    v.l = obj._obj;
1063
928
    _args.push_back(v);
1064
928
    return *this;
1065
928
}
1066
1067
template <CallTag tag>
1068
template <RefType Ref>
1069
99
NonvirtualFunctionCall<tag>& NonvirtualFunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1070
99
    jvalue v;
1071
99
    std::memset(&v, 0, sizeof(v));
1072
99
    v.l = obj._obj;
1073
99
    this->_args.push_back(v);
1074
99
    return *this;
1075
99
}
1076
1077
template <CallTag tag>
1078
122k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
122k
    DCHECK(result->uninitialized());
1080
122k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
122k
    RETURN_ERROR_IF_EXC(this->_env);
1082
122k
    return Status::OK();
1083
122k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
2.16k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
2.16k
    DCHECK(result->uninitialized());
1080
2.16k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
2.16k
    RETURN_ERROR_IF_EXC(this->_env);
1082
2.16k
    return Status::OK();
1083
2.16k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
114k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
114k
    DCHECK(result->uninitialized());
1080
114k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
114k
    RETURN_ERROR_IF_EXC(this->_env);
1082
114k
    return Status::OK();
1083
114k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
5.59k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
5.59k
    DCHECK(result->uninitialized());
1080
5.59k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
5.59k
    RETURN_ERROR_IF_EXC(this->_env);
1082
5.59k
    return Status::OK();
1083
5.59k
}
1084
1085
template <CallTag tag>
1086
5.39k
Status FunctionCall<tag>::call(Object<Global>* result) {
1087
5.39k
    DCHECK(result->uninitialized());
1088
5.39k
    Object<Local> local_result;
1089
5.39k
    local_result._obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1090
5.39k
    RETURN_ERROR_IF_EXC(this->_env);
1091
5.39k
    return local_to_global_ref(_env, local_result, result);
1092
5.39k
}
1093
1094
template <CallTag tag>
1095
99
Status NonvirtualFunctionCall<tag>::call(Object<Local>* result) {
1096
99
    DCHECK(result->uninitialized());
1097
99
    result->_obj = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
1098
99
                                              this->_args.data());
1099
99
    RETURN_ERROR_IF_EXC(this->_env);
1100
99
    return Status::OK();
1101
99
}
1102
1103
template <RefType Ref>
1104
template <RefType R>
1105
NonvirtualFunctionCall<NonvirtualObjectMethod> Object<Ref>::call_nonvirtual_object_method(
1106
99
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1107
99
    DCHECK(!this->uninitialized());
1108
99
    DCHECK(!method_id.uninitialized());
1109
1110
99
    return NonvirtualFunctionCall<NonvirtualObjectMethod>::instance(env, _obj, (jclass)clazz._obj,
1111
99
                                                                    method_id._id);
1112
99
}
1113
1114
template <RefType Ref>
1115
template <RefType R>
1116
NonvirtualFunctionCall<NonvirtualVoidMethod> Object<Ref>::call_nonvirtual_void_method(
1117
6.05k
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1118
6.05k
    DCHECK(!this->uninitialized());
1119
6.05k
    DCHECK(!method_id.uninitialized());
1120
6.05k
    return NonvirtualFunctionCall<NonvirtualVoidMethod>::instance(env, _obj, (jclass)clazz._obj,
1121
6.05k
                                                                  method_id._id);
1122
6.05k
}
1123
1124
template <RefType Ref>
1125
template <RefType R>
1126
NonvirtualFunctionCall<NonvirtualIntMethod> Object<Ref>::call_nonvirtual_int_method(
1127
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1128
    DCHECK(!this->uninitialized());
1129
    DCHECK(!method_id.uninitialized());
1130
    return NonvirtualFunctionCall<NonvirtualIntMethod>::instance(env, _obj, (jclass)clazz._obj,
1131
                                                                 method_id._id);
1132
}
1133
1134
template <RefType Ref>
1135
template <RefType R>
1136
NonvirtualFunctionCall<NonvirtualBooleanMethod> Object<Ref>::call_nonvirtual_boolean_method(
1137
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1138
    DCHECK(!this->uninitialized());
1139
    DCHECK(!method_id.uninitialized());
1140
    return NonvirtualFunctionCall<NonvirtualBooleanMethod>::instance(env, _obj, (jclass)clazz._obj,
1141
                                                                     method_id._id);
1142
}
1143
1144
class Util {
1145
public:
1146
    // Converts standard UTF-8 strings to a Java String[]. On success the caller owns the
1147
    // returned local reference; *result must be null on entry and is unchanged on failure.
1148
    static Status create_string_array_utf8(JNIEnv* env, const std::vector<std::string>& values,
1149
                                           jobjectArray* result);
1150
1151
    // Throws java.io.IOException with a standard UTF-8 message, using an ASCII fallback if
1152
    // message conversion fails. Exceptions from the IOException constructor are preserved.
1153
    static void throw_java_io_exception_utf8(JNIEnv* env, const std::string& message);
1154
1155
    static size_t get_max_jni_heap_memory_size();
1156
1157
    template <RefType Ref>
1158
46
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
1159
46
        return Class<Ref>::find_class(env, class_str, result);
1160
46
    }
_ZN5doris3Jni4Util10find_classILNS0_7RefTypeE1EEENS_6StatusEP7JNIEnv_PKcPNS0_5ClassIXT_EEE
Line
Count
Source
1158
44
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
1159
44
        return Class<Ref>::find_class(env, class_str, result);
1160
44
    }
_ZN5doris3Jni4Util10find_classILNS0_7RefTypeE0EEENS_6StatusEP7JNIEnv_PKcPNS0_5ClassIXT_EEE
Line
Count
Source
1158
2
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
1159
2
        return Class<Ref>::find_class(env, class_str, result);
1160
2
    }
1161
1162
    template <RefType Ref, RefType R>
1163
5.43k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
5.43k
        return Class<Ref>::get_object_class(env, object, result);
1165
5.43k
    }
Unexecuted instantiation: _ZN5doris3Jni4Util16get_object_classILNS0_7RefTypeE0ELS3_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT0_EEEPNS0_5ClassIXT_EEE
_ZN5doris3Jni4Util16get_object_classILNS0_7RefTypeE1ELS3_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT0_EEEPNS0_5ClassIXT_EEE
Line
Count
Source
1163
5.43k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
5.43k
        return Class<Ref>::get_object_class(env, object, result);
1165
5.43k
    }
1166
1167
    template <RefType Ref>
1168
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
1169
99
                                         Array<Ref>* serialized_msg) {
1170
99
        if constexpr (Ref == Local) {
1171
99
            return Array<Local>::WriteBufferToByteArray(env, buffer, size, serialized_msg);
1172
        } else if constexpr (Ref == Global) {
1173
            Array<Local> local_obj;
1174
            RETURN_IF_ERROR(Array<Local>::WriteBufferToByteArray(env, buffer, size, &local_obj));
1175
            return local_to_global_ref(env, local_obj, serialized_msg);
1176
        } else {
1177
            static_assert(false);
1178
        }
1179
99
    }
1180
1181
    template <class T, RefType Ref>
1182
5.46k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Ref>* serialized_msg) {
1183
5.46k
        if constexpr (Ref == Local) {
1184
5.46k
            return Array<Local>::SerializeThriftMsg(env, msg, serialized_msg);
1185
        } else if (Ref == Global) {
1186
            Array<Local> local_obj;
1187
            RETURN_IF_ERROR(Array<Local>::SerializeThriftMsg(env, msg, local_obj));
1188
            return local_to_global_ref(env, local_obj, serialized_msg);
1189
        } else {
1190
            static_assert(false);
1191
        }
1192
5.46k
    }
1193
1194
    template <RefType Ref>
1195
    static Status convert_to_java_map(JNIEnv* env, const std::map<std::string, std::string>& map,
1196
5.59k
                                      Object<Ref>* hashmap_object) {
1197
5.59k
        RETURN_IF_ERROR(hashmap_class.new_object(env, hashmap_constructor)
1198
5.59k
                                .with_arg((jint)map.size())
1199
5.59k
                                .call(hashmap_object));
1200
1201
16.8k
        for (const auto& it : map) {
1202
16.8k
            LocalString key;
1203
16.8k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.first, &key));
1204
1205
16.8k
            LocalString value;
1206
16.8k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.second, &value));
1207
1208
16.8k
            LocalObject result;
1209
16.8k
            RETURN_IF_ERROR(hashmap_object->call_object_method(env, hashmap_put)
1210
16.8k
                                    .with_arg(key)
1211
16.8k
                                    .with_arg(value)
1212
16.8k
                                    .call());
1213
16.8k
        }
1214
5.59k
        return Status::OK();
1215
5.59k
    }
1216
1217
    template <RefType Ref>
1218
    static Status convert_to_cpp_map(JNIEnv* env, const Object<Ref>& map,
1219
2
                                     std::map<std::string, std::string>* resultMap) {
1220
2
        LocalObject entrySet;
1221
2
        RETURN_IF_ERROR(map.call_object_method(env, mapEntrySetMethod).call(&entrySet));
1222
1223
        // Call the iterator method on the set to iterate over the key-value pairs
1224
2
        LocalObject iteratorSet;
1225
2
        RETURN_IF_ERROR(entrySet.call_object_method(env, iteratorSetMethod).call(&iteratorSet));
1226
1227
6
        while (true) {
1228
6
            jboolean hasNext = false;
1229
6
            RETURN_IF_ERROR(
1230
6
                    iteratorSet.call_boolean_method(env, iteratorHasNextMethod).call(&hasNext));
1231
6
            if (!hasNext) {
1232
2
                break;
1233
2
            }
1234
1235
4
            LocalObject entry;
1236
4
            RETURN_IF_ERROR(iteratorSet.call_object_method(env, iteratorNextMethod).call(&entry));
1237
1238
4
            LocalString javaKey;
1239
4
            RETURN_IF_ERROR(entry.call_object_method(env, getEntryKeyMethod).call(&javaKey));
1240
1241
4
            LocalString javaValue;
1242
4
            RETURN_IF_ERROR(entry.call_object_method(env, getEntryValueMethod).call(&javaValue));
1243
1244
4
            std::string key;
1245
4
            RETURN_IF_ERROR(javaKey.get_string_utf8(env, &key));
1246
1247
4
            std::string value;
1248
4
            RETURN_IF_ERROR(javaValue.get_string_utf8(env, &value));
1249
1250
            // Store the key-value pair in the map
1251
4
            (*resultMap)[std::move(key)] = std::move(value);
1252
4
        }
1253
2
        return Status::OK();
1254
2
    }
1255
1256
    // The outcome of the one attempt to resolve the JNI base, or nullopt when nothing has
1257
    // attempted it yet. Public, unlike ensure_jni_base() below, precisely because it never
1258
    // triggers the attempt: this is what a reader that must not create a JVM asks - the
1259
    // /api/jni_plugin_status endpoint, which exists to answer "why is Java not working here"
1260
    // and would otherwise have to start a JVM to find out.
1261
    static std::optional<Status> jni_base_outcome();
1262
1263
private:
1264
    // Resolves everything the BE needs from the JVM before it can call any Java code: the
1265
    // exception helpers, the native methods the Java side links against, and the
1266
    // collection classes cached below. Runs once, right after the JVM appears; every
1267
    // caller that follows gets the outcome of that one attempt.
1268
    //
1269
    // Deliberately NOT part of "does this process have a JVM": all of it comes out of
1270
    // doris-jni-spi.jar, and a BE whose Java deployment is incomplete still serves HDFS through
1271
    // libhdfs. JvmLauncher runs it once at the end of its bootstrap and logs a failure; Env, the
1272
    // door every Java caller comes through, refuses to hand out a JNIEnv while it is failing.
1273
    //
1274
    // Only those two may call it. JvmLauncher calls it from inside its bootstrap, with the
1275
    // calling thread already attached and its env cached, because the resolution asks Env::Get()
1276
    // for a JNIEnv and an unattached thread there would go back through ensure_jvm() and deadlock
1277
    // on the once flag the bootstrap is already holding.
1278
    //
1279
    // Env::GetJNIEnvSlowPath() calls it from an unattached thread on purpose, and the invariant
1280
    // that makes THAT safe is a different one, worth stating because nothing enforces it: by the
1281
    // time the slow path gets here, ensure_jvm()'s call_once has already run to completion on
1282
    // some thread, so the resolution below is never the one that runs - it is always the cached
1283
    // answer of the attempt the bootstrap made. Every early exit of _bootstrap() leaves
1284
    // jvm_status non-OK, and the slow path returns on that before reaching this line.
1285
    //
1286
    // Making the base lazy (that is, resolving it here for real rather than reading a cached
1287
    // answer) would put the deadlock straight back, so GetJNIEnvSlowPath() holds it down with a
1288
    // DCHECK: on that path an outcome must already exist before this is called.
1289
    static Status ensure_jni_base();
1290
    friend class JvmLauncher;
1291
    friend class Env;
1292
1293
    static void _parse_max_heap_memory_size_from_jvm();
1294
1295
    // Bytes named by the last -Xmx in `options`, or 0 when none of them says. Split out from the
1296
    // above so that the parsing can be tested without a JVM; see jni_util_test.cpp.
1297
    static jlong _parse_xmx(const std::string& options);
1298
1299
    static Status _init_jni_base() WARN_UNUSED_RESULT;
1300
    static Status _init_collect_class() WARN_UNUSED_RESULT;
1301
    static Status _init_register_natives() WARN_UNUSED_RESULT;
1302
1303
    // for jvm heap
1304
    static jlong max_jvm_heap_memory_size_;
1305
1306
    //for hashmap
1307
    static GlobalClass hashmap_class;
1308
    static MethodId hashmap_constructor;
1309
    static MethodId hashmap_put;
1310
1311
    //for map
1312
    static GlobalClass mapClass;
1313
    static MethodId mapEntrySetMethod;
1314
1315
    // for map entry
1316
    static GlobalClass mapEntryClass;
1317
    static MethodId getEntryKeyMethod;
1318
    static MethodId getEntryValueMethod;
1319
1320
    //for set
1321
    static GlobalClass setClass;
1322
    static MethodId iteratorSetMethod;
1323
1324
    // for iterator
1325
    static GlobalClass iteratorClass;
1326
    static MethodId iteratorHasNextMethod;
1327
    static MethodId iteratorNextMethod;
1328
};
1329
}; // namespace Jni
1330
1331
} // namespace doris