Coverage Report

Created: 2026-11-05 11:32

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
267k
    do {                                              \
45
267k
        if (env->ExceptionCheck()) [[unlikely]]       \
46
4
            return Jni::Env::GetJniExceptionMsg(env); \
47
267k
    } 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
226k
    static Status Get(JNIEnv** env) {
59
226k
        if (tls_env_) {
60
226k
            *env = tls_env_;
61
226k
        } else {
62
180
            Status status = GetJNIEnvSlowPath(env);
63
180
            if (!status.ok()) {
64
0
                return status;
65
0
            }
66
180
        }
67
226k
        if (*env == nullptr) [[unlikely]] {
68
0
            return Status::JniError("Failed to get JNIEnv: it is nullptr.");
69
0
        }
70
226k
        return Status::OK();
71
226k
    }
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
48
    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
729
    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
363
    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
3.60k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewLocalRef(obj); }
177
178
199k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteLocalRef(obj); }
179
180
202k
    static Status get_env(JNIEnv** env) {
181
        // Get the JNIEnv* corresponding to current thread.
182
202k
        return Jni::Env::Get(env);
183
202k
    }
184
};
185
186
template <>
187
struct RefHelper<Global> {
188
9.91k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewGlobalRef(obj); }
189
190
9.89k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteGlobalRef(obj); }
191
192
9.89k
    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
12.3k
    MethodId() = default;
204
139k
    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
89.0k
    static jobject call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
257
89.0k
        return env->CallObjectMethodA(obj, methodID, args);
258
89.0k
    }
259
    using BASE_TYPE = jobject;
260
    using RETURN_TYPE = jobject;
261
};
262
263
template <>
264
struct CallHelper<IntMethod> {
265
1.08k
    static jint call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
266
1.08k
        return env->CallIntMethodA(obj, methodID, args);
267
1.08k
    }
268
    using BASE_TYPE = jobject;
269
    using RETURN_TYPE = jint;
270
};
271
272
template <>
273
struct CallHelper<LongMethod> {
274
14.6k
    static jlong call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
275
14.6k
        return env->CallLongMethodA(obj, methodID, args);
276
14.6k
    }
277
    using BASE_TYPE = jobject;
278
    using RETURN_TYPE = jlong;
279
};
280
281
template <>
282
struct CallHelper<VoidMethod> {
283
233
    static void call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
284
233
        env->CallVoidMethodA(obj, methodID, args);
285
233
    }
286
    using BASE_TYPE = jobject;
287
    using RETURN_TYPE = void;
288
};
289
290
template <>
291
struct CallHelper<BooleanMethod> {
292
0
    static jboolean call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
293
0
        return env->CallBooleanMethodA(obj, methodID, args);
294
0
    }
295
    using BASE_TYPE = jobject;
296
    using RETURN_TYPE = jboolean;
297
};
298
299
template <>
300
struct CallHelper<StaticObjectMethod> {
301
6.35k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
302
6.35k
        return env->CallStaticObjectMethodA(cls, methodID, args);
303
6.35k
    }
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
232
    static void call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
329
232
        return env->CallStaticVoidMethodA(cls, methodID, args);
330
232
    }
331
332
    using BASE_TYPE = jclass;
333
    using RETURN_TYPE = void;
334
};
335
336
template <>
337
struct CallHelper<NewObject> {
338
5.49k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
339
5.49k
        return env->NewObjectA(cls, methodID, args);
340
5.49k
    }
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
5.36k
                          const jvalue* args) {
350
5.36k
        return env->CallNonvirtualVoidMethodA(obj, clazz, methodID, args);
351
5.36k
    }
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
80
                             const jvalue* args) {
361
80
        return env->CallNonvirtualObjectMethodA(obj, clazz, methodID, args);
362
80
    }
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
117k
                                 jmethodID method_id) {
397
117k
        return FunctionCall(env, base, method_id);
398
117k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
6.35k
                                 jmethodID method_id) {
397
6.35k
        return FunctionCall(env, base, method_id);
398
6.35k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
89.0k
                                 jmethodID method_id) {
397
89.0k
        return FunctionCall(env, base, method_id);
398
89.0k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
14.6k
                                 jmethodID method_id) {
397
14.6k
        return FunctionCall(env, base, method_id);
398
14.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
1.08k
                                 jmethodID method_id) {
397
1.08k
        return FunctionCall(env, base, method_id);
398
1.08k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
234
                                 jmethodID method_id) {
397
234
        return FunctionCall(env, base, method_id);
398
234
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
5.49k
                                 jmethodID method_id) {
397
5.49k
        return FunctionCall(env, base, method_id);
398
5.49k
    }
Unexecuted instantiation: _ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
232
                                 jmethodID method_id) {
397
232
        return FunctionCall(env, base, method_id);
398
232
    }
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
11.0k
    FunctionCall& with_arg(T arg) {
408
11.0k
        jvalue v;
409
11.0k
        std::memset(&v, 0, sizeof(v));
410
11.0k
        if constexpr (std::is_same_v<T, jboolean>) {
411
232
            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
10.1k
        } else if constexpr (std::is_same_v<T, jint>) {
419
10.1k
            v.i = arg;
420
10.1k
        } else if constexpr (std::is_same_v<T, jlong>) {
421
663
            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
11.0k
        _args.push_back(v);
430
11.0k
        return *this;
431
11.0k
    }
_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
3.96k
    FunctionCall& with_arg(T arg) {
408
3.96k
        jvalue v;
409
3.96k
        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
3.96k
        } else if constexpr (std::is_same_v<T, jint>) {
419
3.96k
            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
3.96k
        _args.push_back(v);
430
3.96k
        return *this;
431
3.96k
    }
_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.49k
    FunctionCall& with_arg(T arg) {
408
5.49k
        jvalue v;
409
5.49k
        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.49k
        } else if constexpr (std::is_same_v<T, jint>) {
419
5.49k
            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.49k
        _args.push_back(v);
430
5.49k
        return *this;
431
5.49k
    }
_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
232
    FunctionCall& with_arg(T arg) {
408
232
        jvalue v;
409
232
        std::memset(&v, 0, sizeof(v));
410
232
        if constexpr (std::is_same_v<T, jboolean>) {
411
232
            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
232
        _args.push_back(v);
430
232
        return *this;
431
232
    }
_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
694
    FunctionCall& with_arg(T arg) {
408
694
        jvalue v;
409
694
        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
694
        } else if constexpr (std::is_same_v<T, jint>) {
419
694
            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
694
        _args.push_back(v);
430
694
        return *this;
431
694
    }
_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
230
    FunctionCall& with_arg(T arg) {
408
230
        jvalue v;
409
230
        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
230
        } else if constexpr (std::is_same_v<T, jlong>) {
421
230
            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
230
        _args.push_back(v);
430
230
        return *this;
431
230
    }
_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
201
    FunctionCall& with_arg(T arg) {
408
201
        jvalue v;
409
201
        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
201
        } else if constexpr (std::is_same_v<T, jlong>) {
421
201
            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
201
        _args.push_back(v);
430
201
        return *this;
431
201
    }
_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
1
    FunctionCall& with_arg(T arg) {
408
1
        jvalue v;
409
1
        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
1
        } else if constexpr (std::is_same_v<T, jint>) {
419
1
            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
1
        _args.push_back(v);
430
1
        return *this;
431
1
    }
_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
232
    FunctionCall& with_arg(T arg) {
408
232
        jvalue v;
409
232
        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
232
        } else if constexpr (std::is_same_v<T, jlong>) {
421
232
            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
232
        _args.push_back(v);
430
232
        return *this;
431
232
    }
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
15.6k
    Status call(ReturnType* result) {
439
15.6k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
15.6k
        RETURN_ERROR_IF_EXC(_env);
441
15.6k
        return Status::OK();
442
15.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE4callIlQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
14.6k
    Status call(ReturnType* result) {
439
14.6k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
14.6k
        RETURN_ERROR_IF_EXC(_env);
441
14.6k
        return Status::OK();
442
14.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE4callIiQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
1.08k
    Status call(ReturnType* result) {
439
1.08k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
1.08k
        RETURN_ERROR_IF_EXC(_env);
441
1.08k
        return Status::OK();
442
1.08k
    }
Unexecuted instantiation: _ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EE4callIhQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
443
444
    Status call(Object<Local>* result);
445
446
    Status call(Object<Global>* result);
447
448
16.9k
    Status call() {
449
16.9k
        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
463
                              std::is_same<return_type, void>>) {
456
463
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
463
            RETURN_ERROR_IF_EXC(_env);
458
16.4k
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
16.4k
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
16.4k
            _env->DeleteLocalRef(tmp);
461
16.4k
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
16.9k
        return Status::OK();
466
16.9k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE4callEv
Line
Count
Source
448
231
    Status call() {
449
231
        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
231
                              std::is_same<return_type, void>>) {
456
231
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
231
            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
231
        return Status::OK();
466
231
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEv
Line
Count
Source
448
16.4k
    Status call() {
449
16.4k
        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.4k
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
16.4k
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
16.4k
            _env->DeleteLocalRef(tmp);
461
16.4k
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
16.4k
        return Status::OK();
466
16.4k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE4callEv
Line
Count
Source
448
232
    Status call() {
449
232
        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
232
                              std::is_same<return_type, void>>) {
456
232
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
232
            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
232
        return Status::OK();
466
232
    }
467
468
protected:
469
    explicit FunctionCall(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
470
                          jmethodID method_id)
471
122k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
6.35k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
89.0k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
14.6k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
1.08k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
234
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
5.49k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
5.36k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
80
            : _env(env), _base(base), _method(method_id) {}
Unexecuted instantiation: _ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
232
            : _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
5.44k
                                           jclass cls, jmethodID method_id) {
488
5.44k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
5.44k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
5.36k
                                           jclass cls, jmethodID method_id) {
488
5.36k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
5.36k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
80
                                           jclass cls, jmethodID method_id) {
488
80
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
80
    }
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
195
    NonvirtualFunctionCall& with_arg(T arg) {
498
195
        jvalue v;
499
195
        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
195
        } else if constexpr (std::is_same_v<T, jlong>) {
511
195
            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
195
        this->_args.push_back(v);
520
195
        return *this;
521
195
    }
_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
115
    NonvirtualFunctionCall& with_arg(T arg) {
498
115
        jvalue v;
499
115
        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
115
        } else if constexpr (std::is_same_v<T, jlong>) {
511
115
            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
115
        this->_args.push_back(v);
520
115
        return *this;
521
115
    }
_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
80
    NonvirtualFunctionCall& with_arg(T arg) {
498
80
        jvalue v;
499
80
        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
80
        } else if constexpr (std::is_same_v<T, jlong>) {
511
80
            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
80
        this->_args.push_back(v);
520
80
        return *this;
521
80
    }
522
523
    template <RefType Ref>
524
    NonvirtualFunctionCall& with_arg(const Object<Ref>& obj) WARN_UNUSED_RESULT;
525
526
    // no override
527
5.36k
    Status call() {
528
5.36k
        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
5.36k
                              std::is_same<return_type, void>>) {
535
5.36k
            CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
536
5.36k
                                       this->_args.data());
537
5.36k
            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
5.36k
        return Status::OK();
547
5.36k
    }
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
5.44k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
5.36k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
80
            : 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
225k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
599
10.1k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
599
215k
    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
225k
    virtual ~Object() {
623
225k
        if (_obj != nullptr) [[likely]] {
624
209k
            JNIEnv* env = nullptr;
625
209k
            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
209k
            RefHelper<Ref>::destroy(env, _obj);
630
209k
        }
631
225k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EED2Ev
Line
Count
Source
622
215k
    virtual ~Object() {
623
215k
        if (_obj != nullptr) [[likely]] {
624
199k
            JNIEnv* env = nullptr;
625
199k
            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
199k
            RefHelper<Ref>::destroy(env, _obj);
630
199k
        }
631
215k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EED2Ev
Line
Count
Source
622
10.1k
    virtual ~Object() {
623
10.1k
        if (_obj != nullptr) [[likely]] {
624
9.89k
            JNIEnv* env = nullptr;
625
9.89k
            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
9.89k
            RefHelper<Ref>::destroy(env, _obj);
630
9.89k
        }
631
10.1k
    }
632
633
    template <RefType R>
634
13.5k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
13.5k
        DCHECK(!other.uninitialized());
636
13.5k
        DCHECK(result->uninitialized());
637
638
13.5k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
13.5k
        RETURN_ERROR_IF_EXC(env);
640
13.5k
        return Status::OK();
641
13.5k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
9.90k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
9.90k
        DCHECK(!other.uninitialized());
636
9.90k
        DCHECK(result->uninitialized());
637
638
9.90k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
9.90k
        RETURN_ERROR_IF_EXC(env);
640
9.90k
        return Status::OK();
641
9.90k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
3.60k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
3.60k
        DCHECK(!other.uninitialized());
636
3.60k
        DCHECK(result->uninitialized());
637
638
3.60k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
3.60k
        RETURN_ERROR_IF_EXC(env);
640
3.60k
        return Status::OK();
641
3.60k
    }
642
643
776k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE13uninitializedEv
Line
Count
Source
643
590k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE13uninitializedEv
Line
Count
Source
643
186k
    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
0
    void reset(JNIEnv* env) {
649
0
        if (_obj == nullptr) {
650
0
            return;
651
0
        }
652
0
        RefHelper<Ref>::destroy(env, _obj);
653
0
        _obj = nullptr;
654
0
    }
655
656
    template <RefType T>
657
119k
    bool equal(JNIEnv* env, const Object<T>& other) {
658
119k
        DCHECK(!uninitialized());
659
119k
        DCHECK(!other.uninitialized());
660
119k
        return env->IsSameObject(this->_obj, other._obj); //assume not throw exception.
661
119k
    }
662
663
89.0k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
89.0k
        DCHECK(!this->uninitialized());
665
89.0k
        DCHECK(!method_id.uninitialized());
666
89.0k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
89.0k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
663
89.0k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
89.0k
        DCHECK(!this->uninitialized());
665
        DCHECK(!method_id.uninitialized());
666
89.0k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
89.0k
    }
Unexecuted instantiation: _ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
668
669
1.08k
    FunctionCall<IntMethod> call_int_method(JNIEnv* env, MethodId method_id) const {
670
1.08k
        DCHECK(!this->uninitialized());
671
1.08k
        DCHECK(!method_id.uninitialized());
672
1.08k
        return FunctionCall<IntMethod>::instance(env, _obj, method_id._id);
673
1.08k
    }
674
675
14.6k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
14.6k
        DCHECK(!this->uninitialized());
677
14.6k
        DCHECK(!method_id.uninitialized());
678
14.6k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
14.6k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
11.8k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
11.8k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
11.8k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
11.8k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
2.73k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
2.73k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
2.73k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
2.73k
    }
680
681
234
    FunctionCall<VoidMethod> call_void_method(JNIEnv* env, MethodId method_id) const {
682
234
        DCHECK(!this->uninitialized());
683
234
        DCHECK(!method_id.uninitialized());
684
234
        return FunctionCall<VoidMethod>::instance(env, _obj, method_id._id);
685
234
    }
686
687
0
    FunctionCall<BooleanMethod> call_boolean_method(JNIEnv* env, MethodId method_id) const {
688
0
        DCHECK(!this->uninitialized());
689
0
        DCHECK(!method_id.uninitialized());
690
0
        return FunctionCall<BooleanMethod>::instance(env, _obj, method_id._id);
691
0
    }
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
9.91k
                                         GlobalObject* global_ref) {
719
9.91k
    return Object<Global>::create(env, local_ref, global_ref);
720
9.91k
}
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
9.85k
                                         GlobalObject* global_ref) {
719
9.85k
    return Object<Global>::create(env, local_ref, global_ref);
720
9.85k
}
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
3.60k
    BufferGuard() = default;
727
728
    template <RefType R>
729
    static Status create(JNIEnv* env, const Object<R>& object,
730
3.60k
                         BufferGuard<bufferfType, Ref>* result, jboolean* isCopy) {
731
3.60k
        DCHECK(result->_buffer == nullptr && result->_object.uninitialized());
732
733
3.60k
        RETURN_IF_ERROR(Object<Ref>::create(env, object, &result->_object));
734
735
3.60k
        if constexpr (bufferfType == BufferType::Chars) {
736
3.60k
            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
3.60k
        RETURN_ERROR_IF_EXC(env);
745
3.60k
        if (result->_buffer == nullptr) [[unlikely]] {
746
0
            return Status::JniError("GetStringUTFChars/GetByteArrayElements fail.");
747
0
        }
748
749
3.60k
        return Status::OK();
750
3.60k
    }
751
752
3.60k
    ~BufferGuard() {
753
3.60k
        if (_object.uninitialized() || _buffer == nullptr) [[unlikely]] {
754
0
            return;
755
0
        }
756
3.60k
        JNIEnv* env = nullptr;
757
758
3.60k
        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
3.60k
        if constexpr (bufferfType == BufferType::Chars) {
764
3.60k
            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
3.60k
    }
769
770
7.20k
    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
46.6k
    String() = default;
796
797
    // Accepts JNI modified UTF-8. Use new_string_utf8 for standard UTF-8, e.g. scanner SQL.
798
9.80k
    static Status new_string(JNIEnv* env, const char* utf_chars, String<Ref>* result) {
799
9.80k
        DCHECK(result->uninitialized());
800
801
9.80k
        if constexpr (Ref == Local) {
802
9.80k
            result->_obj = env->NewStringUTF(utf_chars);
803
9.80k
            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
9.80k
        if (result->uninitialized()) {
813
1
            return Status::JniError("Failed to allocate modified UTF-8 Java string reference");
814
1
        }
815
9.80k
        return Status::OK();
816
9.80k
    }
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
3.60k
    Status get_string_chars(JNIEnv* env, StringBufferGuard<Ref>* jni_chars) const {
822
3.60k
        return StringBufferGuard<Ref>::create(env, *this, jni_chars, nullptr);
823
3.60k
    }
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
0
    Status get_string_utf8(JNIEnv* env, std::string* result) const {
828
0
        DCHECK(!this->uninitialized());
829
0
        return Jni::get_string_utf8(env, static_cast<jstring>(this->_obj), result);
830
0
    }
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
5.81k
    Array() = default;
843
844
440
    Status get_length(JNIEnv* env, jsize* result) const {
845
440
        DCHECK(!this->uninitialized());
846
847
440
        *result = env->GetArrayLength((jarray)this->_obj);
848
440
        RETURN_ERROR_IF_EXC(env);
849
440
        return Status::OK();
850
440
    }
851
852
58.1k
    Status get_object_array_element(JNIEnv* env, jsize index, Jni::LocalObject* result) {
853
58.1k
        DCHECK(!this->uninitialized());
854
58.1k
        DCHECK(result->uninitialized());
855
58.1k
        result->_obj = env->GetObjectArrayElement((jobjectArray)this->_obj, index);
856
58.1k
        RETURN_ERROR_IF_EXC(env);
857
58.1k
        return Status::OK();
858
58.1k
    }
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
80
    Status get_byte_elements(JNIEnv* env, jsize start, jsize len, jbyte* buffer) {
866
80
        DCHECK(!this->uninitialized());
867
80
        env->GetByteArrayRegion((jbyteArray)this->_obj, start, len, buffer);
868
80
        RETURN_ERROR_IF_EXC(env);
869
80
        return Status::OK();
870
80
    }
871
872
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
873
4.98k
                                         Array<Local>* serialized_msg) {
874
4.98k
        DCHECK(serialized_msg->uninitialized());
875
        /// create jbyteArray given buffer
876
4.98k
        serialized_msg->_obj = env->NewByteArray(size);
877
4.98k
        RETURN_ERROR_IF_EXC(env);
878
4.98k
        if (serialized_msg->_obj == nullptr) [[unlikely]] {
879
0
            return Status::JniError("couldn't construct jbyteArray");
880
0
        }
881
4.98k
        env->SetByteArrayRegion((jbyteArray)serialized_msg->_obj, 0, size, buffer);
882
4.98k
        RETURN_ERROR_IF_EXC(env);
883
4.98k
        return Status::OK();
884
4.98k
    }
885
886
    template <class T>
887
4.93k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Local>* serialized_msg) {
888
4.93k
        int buffer_size = 100 * 1024; // start out with 100KB
889
4.93k
        ThriftSerializer serializer(false, buffer_size);
890
891
4.93k
        uint8_t* buffer = nullptr;
892
4.93k
        uint32_t size = 0;
893
4.93k
        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
4.93k
        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
4.93k
        RETURN_IF_ERROR(WriteBufferToByteArray(env, (jbyte*)buffer, size, serialized_msg));
904
4.93k
        return Status::OK();
905
4.93k
    }
906
907
private:
908
    DISALLOW_COPY_AND_ASSIGN(Array);
909
};
910
911
template <RefType Ref>
912
class Class : public Object<Ref> {
913
public:
914
10.0k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
914
5.08k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
914
4.98k
    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
4.91k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
4.91k
        DCHECK(!object.uninitialized());
942
4.91k
        DCHECK(result->uninitialized());
943
4.91k
        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
4.91k
        } else if constexpr (Ref == Global) {
948
4.91k
            Class<Local> local_class;
949
4.91k
            local_class._obj = env->GetObjectClass(object._obj);
950
4.91k
            RETURN_ERROR_IF_EXC(env);
951
4.91k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
4.91k
    }
Unexecuted instantiation: _ZN5doris3Jni5ClassILNS0_7RefTypeE0EE16get_object_classILS2_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT_EEEPS3_
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EE16get_object_classILS2_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT_EEEPS3_
Line
Count
Source
940
4.91k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
4.91k
        DCHECK(!object.uninitialized());
942
4.91k
        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
4.91k
        } else if constexpr (Ref == Global) {
948
4.91k
            Class<Local> local_class;
949
4.91k
            local_class._obj = env->GetObjectClass(object._obj);
950
4.91k
            RETURN_ERROR_IF_EXC(env);
951
4.91k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
4.91k
    }
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
1
    bool is_instance(JNIEnv* env, const Object<R>& object) const {
966
1
        DCHECK(!this->uninitialized());
967
1
        DCHECK(!object.uninitialized());
968
1
        return env->IsInstanceOf(object._obj, (jclass)this->_obj) == JNI_TRUE;
969
1
    }
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
11.3k
                      MethodId* method_id) const {
982
11.3k
        DCHECK(!this->uninitialized());
983
11.3k
        DCHECK(method_id->uninitialized());
984
11.3k
        method_id->_id = env->GetMethodID((jclass)this->_obj, method_str, method_signature);
985
11.3k
        RETURN_ERROR_IF_EXC(env);
986
11.3k
        return Status::OK();
987
11.3k
    }
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.49k
    FunctionCall<NewObject> new_object(JNIEnv* env, MethodId method_id) const {
1026
5.49k
        DCHECK(!this->uninitialized());
1027
5.49k
        DCHECK(!method_id.uninitialized());
1028
5.49k
        return FunctionCall<NewObject>::instance(env, (jclass)this->_obj, method_id._id);
1029
5.49k
    }
1030
1031
    FunctionCall<StaticObjectMethod> call_static_object_method(JNIEnv* env,
1032
6.34k
                                                               MethodId method_id) const {
1033
6.34k
        DCHECK(!this->uninitialized());
1034
6.34k
        DCHECK(!method_id.uninitialized());
1035
6.34k
        return FunctionCall<StaticObjectMethod>::instance(env, (jclass)this->_obj, method_id._id);
1036
6.34k
    }
1037
1038
232
    FunctionCall<StaticVoidMethod> call_static_void_method(JNIEnv* env, MethodId method_id) const {
1039
232
        DCHECK(!this->uninitialized());
1040
232
        DCHECK(!method_id.uninitialized());
1041
232
        return FunctionCall<StaticVoidMethod>::instance(env, (jclass)this->_obj, method_id._id);
1042
232
    }
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
53.8k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
53.8k
    jvalue v;
1061
53.8k
    std::memset(&v, 0, sizeof(v));
1062
53.8k
    v.l = obj._obj;
1063
53.8k
    _args.push_back(v);
1064
53.8k
    return *this;
1065
53.8k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
33.3k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
33.3k
    jvalue v;
1061
33.3k
    std::memset(&v, 0, sizeof(v));
1062
33.3k
    v.l = obj._obj;
1063
33.3k
    _args.push_back(v);
1064
33.3k
    return *this;
1065
33.3k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
231
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
231
    jvalue v;
1061
231
    std::memset(&v, 0, sizeof(v));
1062
231
    v.l = obj._obj;
1063
231
    _args.push_back(v);
1064
231
    return *this;
1065
231
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
5.27k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
5.27k
    jvalue v;
1061
5.27k
    std::memset(&v, 0, sizeof(v));
1062
5.27k
    v.l = obj._obj;
1063
5.27k
    _args.push_back(v);
1064
5.27k
    return *this;
1065
5.27k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
14.7k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
14.7k
    jvalue v;
1061
14.7k
    std::memset(&v, 0, sizeof(v));
1062
14.7k
    v.l = obj._obj;
1063
14.7k
    _args.push_back(v);
1064
14.7k
    return *this;
1065
14.7k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
232
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
232
    jvalue v;
1061
232
    std::memset(&v, 0, sizeof(v));
1062
232
    v.l = obj._obj;
1063
232
    _args.push_back(v);
1064
232
    return *this;
1065
232
}
1066
1067
template <CallTag tag>
1068
template <RefType Ref>
1069
80
NonvirtualFunctionCall<tag>& NonvirtualFunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1070
80
    jvalue v;
1071
80
    std::memset(&v, 0, sizeof(v));
1072
80
    v.l = obj._obj;
1073
80
    this->_args.push_back(v);
1074
80
    return *this;
1075
80
}
1076
1077
template <CallTag tag>
1078
79.4k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
79.4k
    DCHECK(result->uninitialized());
1080
79.4k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
79.4k
    RETURN_ERROR_IF_EXC(this->_env);
1082
79.4k
    return Status::OK();
1083
79.4k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
1.44k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
1.44k
    DCHECK(result->uninitialized());
1080
1.44k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
1.44k
    RETURN_ERROR_IF_EXC(this->_env);
1082
1.44k
    return Status::OK();
1083
1.44k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
72.5k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
72.5k
    DCHECK(result->uninitialized());
1080
72.5k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
72.5k
    RETURN_ERROR_IF_EXC(this->_env);
1082
72.5k
    return Status::OK();
1083
72.5k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
5.49k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
5.49k
    DCHECK(result->uninitialized());
1080
5.49k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
5.49k
    RETURN_ERROR_IF_EXC(this->_env);
1082
5.49k
    return Status::OK();
1083
5.49k
}
1084
1085
template <CallTag tag>
1086
4.91k
Status FunctionCall<tag>::call(Object<Global>* result) {
1087
4.91k
    DCHECK(result->uninitialized());
1088
4.91k
    Object<Local> local_result;
1089
4.91k
    local_result._obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1090
4.91k
    RETURN_ERROR_IF_EXC(this->_env);
1091
4.91k
    return local_to_global_ref(_env, local_result, result);
1092
4.91k
}
1093
1094
template <CallTag tag>
1095
80
Status NonvirtualFunctionCall<tag>::call(Object<Local>* result) {
1096
80
    DCHECK(result->uninitialized());
1097
80
    result->_obj = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
1098
80
                                              this->_args.data());
1099
80
    RETURN_ERROR_IF_EXC(this->_env);
1100
80
    return Status::OK();
1101
80
}
1102
1103
template <RefType Ref>
1104
template <RefType R>
1105
NonvirtualFunctionCall<NonvirtualObjectMethod> Object<Ref>::call_nonvirtual_object_method(
1106
80
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1107
80
    DCHECK(!this->uninitialized());
1108
80
    DCHECK(!method_id.uninitialized());
1109
1110
80
    return NonvirtualFunctionCall<NonvirtualObjectMethod>::instance(env, _obj, (jclass)clazz._obj,
1111
80
                                                                    method_id._id);
1112
80
}
1113
1114
template <RefType Ref>
1115
template <RefType R>
1116
NonvirtualFunctionCall<NonvirtualVoidMethod> Object<Ref>::call_nonvirtual_void_method(
1117
5.36k
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1118
5.36k
    DCHECK(!this->uninitialized());
1119
5.36k
    DCHECK(!method_id.uninitialized());
1120
5.36k
    return NonvirtualFunctionCall<NonvirtualVoidMethod>::instance(env, _obj, (jclass)clazz._obj,
1121
5.36k
                                                                  method_id._id);
1122
5.36k
}
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
4.92k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
4.92k
        return Class<Ref>::get_object_class(env, object, result);
1165
4.92k
    }
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
4.92k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
4.92k
        return Class<Ref>::get_object_class(env, object, result);
1165
4.92k
    }
1166
1167
    template <RefType Ref>
1168
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
1169
80
                                         Array<Ref>* serialized_msg) {
1170
80
        if constexpr (Ref == Local) {
1171
80
            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
80
    }
1180
1181
    template <class T, RefType Ref>
1182
4.93k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Ref>* serialized_msg) {
1183
4.93k
        if constexpr (Ref == Local) {
1184
4.93k
            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
4.93k
    }
1193
1194
    template <RefType Ref>
1195
    static Status convert_to_java_map(JNIEnv* env, const std::map<std::string, std::string>& map,
1196
5.49k
                                      Object<Ref>* hashmap_object) {
1197
5.49k
        RETURN_IF_ERROR(hashmap_class.new_object(env, hashmap_constructor)
1198
5.49k
                                .with_arg((jint)map.size())
1199
5.49k
                                .call(hashmap_object));
1200
1201
16.5k
        for (const auto& it : map) {
1202
16.5k
            LocalString key;
1203
16.5k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.first, &key));
1204
1205
16.5k
            LocalString value;
1206
16.5k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.second, &value));
1207
1208
16.5k
            LocalObject result;
1209
16.5k
            RETURN_IF_ERROR(hashmap_object->call_object_method(env, hashmap_put)
1210
16.5k
                                    .with_arg(key)
1211
16.5k
                                    .with_arg(value)
1212
16.5k
                                    .call());
1213
16.5k
        }
1214
5.49k
        return Status::OK();
1215
5.49k
    }
1216
1217
    template <RefType Ref>
1218
    static Status convert_to_cpp_map(JNIEnv* env, const Object<Ref>& map,
1219
0
                                     std::map<std::string, std::string>* resultMap) {
1220
0
        LocalObject entrySet;
1221
0
        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
0
        LocalObject iteratorSet;
1225
0
        RETURN_IF_ERROR(entrySet.call_object_method(env, iteratorSetMethod).call(&iteratorSet));
1226
1227
0
        while (true) {
1228
0
            jboolean hasNext = false;
1229
0
            RETURN_IF_ERROR(
1230
0
                    iteratorSet.call_boolean_method(env, iteratorHasNextMethod).call(&hasNext));
1231
0
            if (!hasNext) {
1232
0
                break;
1233
0
            }
1234
1235
0
            LocalObject entry;
1236
0
            RETURN_IF_ERROR(iteratorSet.call_object_method(env, iteratorNextMethod).call(&entry));
1237
1238
0
            LocalString javaKey;
1239
0
            RETURN_IF_ERROR(entry.call_object_method(env, getEntryKeyMethod).call(&javaKey));
1240
1241
0
            LocalString javaValue;
1242
0
            RETURN_IF_ERROR(entry.call_object_method(env, getEntryValueMethod).call(&javaValue));
1243
1244
0
            std::string key;
1245
0
            RETURN_IF_ERROR(javaKey.get_string_utf8(env, &key));
1246
1247
0
            std::string value;
1248
0
            RETURN_IF_ERROR(javaValue.get_string_utf8(env, &value));
1249
1250
            // Store the key-value pair in the map
1251
0
            (*resultMap)[std::move(key)] = std::move(value);
1252
0
        }
1253
0
        return Status::OK();
1254
0
    }
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