Coverage Report

Created: 2026-11-03 11:39

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
306k
    do {                                              \
45
306k
        if (env->ExceptionCheck()) [[unlikely]]       \
46
4
            return Jni::Env::GetJniExceptionMsg(env); \
47
306k
    } 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
261k
    static Status Get(JNIEnv** env) {
59
261k
        if (tls_env_) {
60
261k
            *env = tls_env_;
61
261k
        } else {
62
163
            Status status = GetJNIEnvSlowPath(env);
63
163
            if (!status.ok()) {
64
0
                return status;
65
0
            }
66
163
        }
67
261k
        if (*env == nullptr) [[unlikely]] {
68
0
            return Status::JniError("Failed to get JNIEnv: it is nullptr.");
69
0
        }
70
261k
        return Status::OK();
71
261k
    }
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
49
    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
847
    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
422
    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
4.19k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewLocalRef(obj); }
177
178
229k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteLocalRef(obj); }
179
180
233k
    static Status get_env(JNIEnv** env) {
181
        // Get the JNIEnv* corresponding to current thread.
182
233k
        return Jni::Env::Get(env);
183
233k
    }
184
};
185
186
template <>
187
struct RefHelper<Global> {
188
11.5k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewGlobalRef(obj); }
189
190
11.5k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteGlobalRef(obj); }
191
192
11.5k
    static Status get_env(JNIEnv** env) { return Jni::Env::Get(env); }
193
};
194
195
template <RefType Ref>
196
class Object;
197
198
template <RefType Ref>
199
class Class;
200
201
class MethodId {
202
public:
203
14.0k
    MethodId() = default;
204
159k
    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
102k
    static jobject call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
257
102k
        return env->CallObjectMethodA(obj, methodID, args);
258
102k
    }
259
    using BASE_TYPE = jobject;
260
    using RETURN_TYPE = jobject;
261
};
262
263
template <>
264
struct CallHelper<IntMethod> {
265
1.25k
    static jint call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
266
1.25k
        return env->CallIntMethodA(obj, methodID, args);
267
1.25k
    }
268
    using BASE_TYPE = jobject;
269
    using RETURN_TYPE = jint;
270
};
271
272
template <>
273
struct CallHelper<LongMethod> {
274
16.6k
    static jlong call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
275
16.6k
        return env->CallLongMethodA(obj, methodID, args);
276
16.6k
    }
277
    using BASE_TYPE = jobject;
278
    using RETURN_TYPE = jlong;
279
};
280
281
template <>
282
struct CallHelper<VoidMethod> {
283
257
    static void call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
284
257
        env->CallVoidMethodA(obj, methodID, args);
285
257
    }
286
    using BASE_TYPE = jobject;
287
    using RETURN_TYPE = void;
288
};
289
290
template <>
291
struct CallHelper<BooleanMethod> {
292
6
    static jboolean call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
293
6
        return env->CallBooleanMethodA(obj, methodID, args);
294
6
    }
295
    using BASE_TYPE = jobject;
296
    using RETURN_TYPE = jboolean;
297
};
298
299
template <>
300
struct CallHelper<StaticObjectMethod> {
301
7.41k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
302
7.41k
        return env->CallStaticObjectMethodA(cls, methodID, args);
303
7.41k
    }
304
    using BASE_TYPE = jclass;
305
    using RETURN_TYPE = jobject;
306
};
307
308
template <>
309
struct CallHelper<StaticIntMethod> {
310
0
    static jint call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
311
0
        return env->CallStaticIntMethodA(cls, methodID, args);
312
0
    }
313
    using BASE_TYPE = jclass;
314
    using RETURN_TYPE = jint;
315
};
316
317
template <>
318
struct CallHelper<StaticLongMethod> {
319
0
    static jlong call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
320
0
        return env->CallStaticLongMethodA(cls, methodID, args);
321
0
    }
322
    using BASE_TYPE = jclass;
323
    using RETURN_TYPE = jlong;
324
};
325
326
template <>
327
struct CallHelper<StaticVoidMethod> {
328
928
    static void call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
329
928
        return env->CallStaticVoidMethodA(cls, methodID, args);
330
928
    }
331
332
    using BASE_TYPE = jclass;
333
    using RETURN_TYPE = void;
334
};
335
336
template <>
337
struct CallHelper<NewObject> {
338
5.57k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
339
5.57k
        return env->NewObjectA(cls, methodID, args);
340
5.57k
    }
341
342
    using BASE_TYPE = jclass;
343
    using RETURN_TYPE = jobject;
344
};
345
346
template <>
347
struct CallHelper<NonvirtualVoidMethod> {
348
    static void call_impl(JNIEnv* env, jobject obj, jclass clazz, jmethodID methodID,
349
6.22k
                          const jvalue* args) {
350
6.22k
        return env->CallNonvirtualVoidMethodA(obj, clazz, methodID, args);
351
6.22k
    }
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
82
                             const jvalue* args) {
361
82
        return env->CallNonvirtualObjectMethodA(obj, clazz, methodID, args);
362
82
    }
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
134k
                                 jmethodID method_id) {
397
134k
        return FunctionCall(env, base, method_id);
398
134k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
7.43k
                                 jmethodID method_id) {
397
7.43k
        return FunctionCall(env, base, method_id);
398
7.43k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
102k
                                 jmethodID method_id) {
397
102k
        return FunctionCall(env, base, method_id);
398
102k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
16.6k
                                 jmethodID method_id) {
397
16.6k
        return FunctionCall(env, base, method_id);
398
16.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
1.25k
                                 jmethodID method_id) {
397
1.25k
        return FunctionCall(env, base, method_id);
398
1.25k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
257
                                 jmethodID method_id) {
397
257
        return FunctionCall(env, base, method_id);
398
257
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
5.56k
                                 jmethodID method_id) {
397
5.56k
        return FunctionCall(env, base, method_id);
398
5.56k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
6
                                 jmethodID method_id) {
397
6
        return FunctionCall(env, base, method_id);
398
6
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
928
                                 jmethodID method_id) {
397
928
        return FunctionCall(env, base, method_id);
398
928
    }
399
400
    /// Pass a primitive arg (eg an integer).
401
    /// Multiple arguments may be passed by repeated calls.
402
    template <class T>
403
        requires std::disjunction_v<std::is_same<T, jboolean>, std::is_same<T, jbyte>,
404
                                    std::is_same<T, jchar>, std::is_same<T, jshort>,
405
                                    std::is_same<T, jint>, std::is_same<T, jlong>,
406
                                    std::is_same<T, jfloat>, std::is_same<T, jdouble>>
407
12.4k
    FunctionCall& with_arg(T arg) {
408
12.4k
        jvalue v;
409
12.4k
        std::memset(&v, 0, sizeof(v));
410
12.4k
        if constexpr (std::is_same_v<T, jboolean>) {
411
234
            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.8k
        } else if constexpr (std::is_same_v<T, jint>) {
419
10.8k
            v.i = arg;
420
10.8k
        } else if constexpr (std::is_same_v<T, jlong>) {
421
1.36k
            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
12.4k
        _args.push_back(v);
430
12.4k
        return *this;
431
12.4k
    }
_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
4.60k
    FunctionCall& with_arg(T arg) {
408
4.60k
        jvalue v;
409
4.60k
        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
4.60k
        } else if constexpr (std::is_same_v<T, jint>) {
419
4.60k
            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
4.60k
        _args.push_back(v);
430
4.60k
        return *this;
431
4.60k
    }
_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.56k
    FunctionCall& with_arg(T arg) {
408
5.56k
        jvalue v;
409
5.56k
        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.56k
        } else if constexpr (std::is_same_v<T, jint>) {
419
5.56k
            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.56k
        _args.push_back(v);
430
5.56k
        return *this;
431
5.56k
    }
_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
234
    FunctionCall& with_arg(T arg) {
408
234
        jvalue v;
409
234
        std::memset(&v, 0, sizeof(v));
410
234
        if constexpr (std::is_same_v<T, jboolean>) {
411
234
            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
234
        _args.push_back(v);
430
234
        return *this;
431
234
    }
_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
708
    FunctionCall& with_arg(T arg) {
408
708
        jvalue v;
409
708
        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
708
        } else if constexpr (std::is_same_v<T, jint>) {
419
708
            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
708
        _args.push_back(v);
430
708
        return *this;
431
708
    }
_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
233
    FunctionCall& with_arg(T arg) {
408
233
        jvalue v;
409
233
        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
233
        } else if constexpr (std::is_same_v<T, jlong>) {
421
233
            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
233
        _args.push_back(v);
430
233
        return *this;
431
233
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
205
    FunctionCall& with_arg(T arg) {
408
205
        jvalue v;
409
205
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
        } else if constexpr (std::is_same_v<T, jint>) {
419
            v.i = arg;
420
205
        } else if constexpr (std::is_same_v<T, jlong>) {
421
205
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
205
        _args.push_back(v);
430
205
        return *this;
431
205
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8with_argIiQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
5
    FunctionCall& with_arg(T arg) {
408
5
        jvalue v;
409
5
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
5
        } else if constexpr (std::is_same_v<T, jint>) {
419
5
            v.i = arg;
420
        } else if constexpr (std::is_same_v<T, jlong>) {
421
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
5
        _args.push_back(v);
430
5
        return *this;
431
5
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8with_argIlQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
928
    FunctionCall& with_arg(T arg) {
408
928
        jvalue v;
409
928
        std::memset(&v, 0, sizeof(v));
410
        if constexpr (std::is_same_v<T, jboolean>) {
411
            v.z = arg;
412
        } else if constexpr (std::is_same_v<T, jbyte>) {
413
            v.b = arg;
414
        } else if constexpr (std::is_same_v<T, jchar>) {
415
            v.c = arg;
416
        } else if constexpr (std::is_same_v<T, jshort>) {
417
            v.s = arg;
418
        } else if constexpr (std::is_same_v<T, jint>) {
419
            v.i = arg;
420
928
        } else if constexpr (std::is_same_v<T, jlong>) {
421
928
            v.j = arg;
422
        } else if constexpr (std::is_same_v<T, jfloat>) {
423
            v.f = arg;
424
        } else if constexpr (std::is_same_v<T, jdouble>) {
425
            v.d = arg;
426
        } else {
427
            static_assert(false);
428
        }
429
928
        _args.push_back(v);
430
928
        return *this;
431
928
    }
432
433
    template <RefType Ref>
434
    FunctionCall& with_arg(const Object<Ref>& obj) WARN_UNUSED_RESULT;
435
436
    template <typename ReturnType>
437
        requires(std::is_same_v<typename CallHelper<tag>::RETURN_TYPE, ReturnType>)
438
17.8k
    Status call(ReturnType* result) {
439
17.8k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
17.8k
        RETURN_ERROR_IF_EXC(_env);
441
17.8k
        return Status::OK();
442
17.8k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE4callIlQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
16.6k
    Status call(ReturnType* result) {
439
16.6k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
16.6k
        RETURN_ERROR_IF_EXC(_env);
441
16.5k
        return Status::OK();
442
16.6k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE4callIiQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
1.25k
    Status call(ReturnType* result) {
439
1.25k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
1.25k
        RETURN_ERROR_IF_EXC(_env);
441
1.25k
        return Status::OK();
442
1.25k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EE4callIhQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
6
    Status call(ReturnType* result) {
439
6
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
6
        RETURN_ERROR_IF_EXC(_env);
441
6
        return Status::OK();
442
6
    }
443
444
    Status call(Object<Local>* result);
445
446
    Status call(Object<Global>* result);
447
448
17.9k
    Status call() {
449
17.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
1.18k
                              std::is_same<return_type, void>>) {
456
1.18k
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
1.18k
            RETURN_ERROR_IF_EXC(_env);
458
16.7k
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
16.7k
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
16.7k
            _env->DeleteLocalRef(tmp);
461
16.7k
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
17.9k
        return Status::OK();
466
17.9k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE4callEv
Line
Count
Source
448
255
    Status call() {
449
255
        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
255
                              std::is_same<return_type, void>>) {
456
255
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
255
            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
255
        return Status::OK();
466
255
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEv
Line
Count
Source
448
16.7k
    Status call() {
449
16.7k
        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.7k
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
16.7k
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
16.7k
            _env->DeleteLocalRef(tmp);
461
16.7k
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
16.7k
        return Status::OK();
466
16.7k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE4callEv
Line
Count
Source
448
928
    Status call() {
449
928
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
450
        if constexpr (std::disjunction_v<
451
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
452
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
453
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
454
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
455
928
                              std::is_same<return_type, void>>) {
456
928
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
928
            RETURN_ERROR_IF_EXC(_env);
458
        } else if constexpr (std::is_same_v<return_type, jobject>) {
459
            jobject tmp = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
460
            _env->DeleteLocalRef(tmp);
461
            RETURN_ERROR_IF_EXC(_env);
462
        } else {
463
            static_assert(false);
464
        }
465
928
        return Status::OK();
466
928
    }
467
468
protected:
469
    explicit FunctionCall(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
470
                          jmethodID method_id)
471
140k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
7.43k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
102k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
16.6k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
1.25k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
257
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
5.56k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
6.22k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
82
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE4EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
6
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
928
            : _env(env), _base(base), _method(method_id) {}
472
473
    JNIEnv* _env = nullptr;
474
    CallHelper<tag>::BASE_TYPE _base; // is jobject/jclass  not need new/delete local/global ref.
475
    const jmethodID _method = nullptr;
476
    std::vector<jvalue> _args;
477
    Status _st = Status::OK();
478
    DISALLOW_COPY_AND_ASSIGN(FunctionCall);
479
};
480
481
template <CallTag tag>
482
class NonvirtualFunctionCall : public FunctionCall<tag> {
483
public:
484
    NonvirtualFunctionCall(NonvirtualFunctionCall&& other) noexcept = default;
485
486
    static NonvirtualFunctionCall instance(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
487
6.30k
                                           jclass cls, jmethodID method_id) {
488
6.30k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
6.30k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
6.22k
                                           jclass cls, jmethodID method_id) {
488
6.22k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
6.22k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
82
                                           jclass cls, jmethodID method_id) {
488
82
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
82
    }
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
200
    NonvirtualFunctionCall& with_arg(T arg) {
498
200
        jvalue v;
499
200
        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
200
        } else if constexpr (std::is_same_v<T, jlong>) {
511
200
            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
200
        this->_args.push_back(v);
520
200
        return *this;
521
200
    }
_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
118
    NonvirtualFunctionCall& with_arg(T arg) {
498
118
        jvalue v;
499
118
        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
118
        } else if constexpr (std::is_same_v<T, jlong>) {
511
118
            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
118
        this->_args.push_back(v);
520
118
        return *this;
521
118
    }
_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
82
    NonvirtualFunctionCall& with_arg(T arg) {
498
82
        jvalue v;
499
82
        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
82
        } else if constexpr (std::is_same_v<T, jlong>) {
511
82
            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
82
        this->_args.push_back(v);
520
82
        return *this;
521
82
    }
522
523
    template <RefType Ref>
524
    NonvirtualFunctionCall& with_arg(const Object<Ref>& obj) WARN_UNUSED_RESULT;
525
526
    // no override
527
6.21k
    Status call() {
528
6.21k
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
529
        if constexpr (std::disjunction_v<
530
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
531
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
532
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
533
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
534
6.21k
                              std::is_same<return_type, void>>) {
535
6.21k
            CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
536
6.21k
                                       this->_args.data());
537
6.21k
            RETURN_ERROR_IF_EXC(this->_env);
538
        } else if constexpr (std::is_same_v<return_type, jobject>) {
539
            jobject tmp = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
540
                                                     this->_args.data());
541
            RETURN_ERROR_IF_EXC(this->_env);
542
            this->_env->DeleteLocalRef(tmp);
543
        } else {
544
            static_assert(false);
545
        }
546
6.21k
        return Status::OK();
547
6.21k
    }
548
549
    Status call(Object<Local>* result);
550
551
    template <typename ReturnType>
552
        requires(std::is_same_v<typename CallHelper<tag>::RETURN_TYPE, ReturnType>)
553
    Status call(ReturnType* result) {
554
        *result = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
555
                                             this->_args.data());
556
        RETURN_ERROR_IF_EXC(this->_env);
557
        return Status::OK();
558
    }
559
560
private:
561
    explicit NonvirtualFunctionCall(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
562
                                    jclass cls, jmethodID method_id)
563
6.30k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
6.22k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
82
            : 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
257k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
599
11.8k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
599
246k
    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
257k
    virtual ~Object() {
623
257k
        if (_obj != nullptr) [[likely]] {
624
240k
            JNIEnv* env = nullptr;
625
240k
            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
240k
            RefHelper<Ref>::destroy(env, _obj);
630
240k
        }
631
257k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EED2Ev
Line
Count
Source
622
245k
    virtual ~Object() {
623
245k
        if (_obj != nullptr) [[likely]] {
624
229k
            JNIEnv* env = nullptr;
625
229k
            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
229k
            RefHelper<Ref>::destroy(env, _obj);
630
229k
        }
631
245k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EED2Ev
Line
Count
Source
622
11.8k
    virtual ~Object() {
623
11.8k
        if (_obj != nullptr) [[likely]] {
624
11.5k
            JNIEnv* env = nullptr;
625
11.5k
            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
11.5k
            RefHelper<Ref>::destroy(env, _obj);
630
11.5k
        }
631
11.8k
    }
632
633
    template <RefType R>
634
15.7k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
15.7k
        DCHECK(!other.uninitialized());
636
15.7k
        DCHECK(result->uninitialized());
637
638
15.7k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
15.7k
        RETURN_ERROR_IF_EXC(env);
640
15.7k
        return Status::OK();
641
15.7k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
11.5k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
11.5k
        DCHECK(!other.uninitialized());
636
11.5k
        DCHECK(result->uninitialized());
637
638
11.5k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
11.5k
        RETURN_ERROR_IF_EXC(env);
640
11.5k
        return Status::OK();
641
11.5k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
4.19k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
4.19k
        DCHECK(!other.uninitialized());
636
4.19k
        DCHECK(result->uninitialized());
637
638
4.19k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
4.19k
        RETURN_ERROR_IF_EXC(env);
640
4.19k
        return Status::OK();
641
4.19k
    }
642
643
902k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE13uninitializedEv
Line
Count
Source
643
684k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE13uninitializedEv
Line
Count
Source
643
218k
    bool uninitialized() const { return _obj == nullptr; }
644
645
    // Access the JNI handle without changing ownership.
646
1
    jobject get() const { return _obj; }
Unexecuted instantiation: _ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE3getEv
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE3getEv
Line
Count
Source
646
1
    jobject get() const { return _obj; }
647
648
2
    void reset(JNIEnv* env) {
649
2
        if (_obj == nullptr) {
650
0
            return;
651
0
        }
652
2
        RefHelper<Ref>::destroy(env, _obj);
653
2
        _obj = nullptr;
654
2
    }
655
656
    template <RefType T>
657
141k
    bool equal(JNIEnv* env, const Object<T>& other) {
658
141k
        DCHECK(!uninitialized());
659
141k
        DCHECK(!other.uninitialized());
660
141k
        return env->IsSameObject(this->_obj, other._obj); //assume not throw exception.
661
141k
    }
662
663
102k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
102k
        DCHECK(!this->uninitialized());
665
102k
        DCHECK(!method_id.uninitialized());
666
102k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
102k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
663
102k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
102k
        DCHECK(!this->uninitialized());
665
        DCHECK(!method_id.uninitialized());
666
102k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
102k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
663
2
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
2
        DCHECK(!this->uninitialized());
665
        DCHECK(!method_id.uninitialized());
666
2
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
2
    }
668
669
1.25k
    FunctionCall<IntMethod> call_int_method(JNIEnv* env, MethodId method_id) const {
670
1.25k
        DCHECK(!this->uninitialized());
671
1.25k
        DCHECK(!method_id.uninitialized());
672
1.25k
        return FunctionCall<IntMethod>::instance(env, _obj, method_id._id);
673
1.25k
    }
674
675
16.6k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
16.6k
        DCHECK(!this->uninitialized());
677
16.6k
        DCHECK(!method_id.uninitialized());
678
16.6k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
16.6k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
13.8k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
13.8k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
13.8k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
13.8k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
2.77k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
2.77k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
2.77k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
2.77k
    }
680
681
257
    FunctionCall<VoidMethod> call_void_method(JNIEnv* env, MethodId method_id) const {
682
257
        DCHECK(!this->uninitialized());
683
257
        DCHECK(!method_id.uninitialized());
684
257
        return FunctionCall<VoidMethod>::instance(env, _obj, method_id._id);
685
257
    }
686
687
6
    FunctionCall<BooleanMethod> call_boolean_method(JNIEnv* env, MethodId method_id) const {
688
6
        DCHECK(!this->uninitialized());
689
6
        DCHECK(!method_id.uninitialized());
690
6
        return FunctionCall<BooleanMethod>::instance(env, _obj, method_id._id);
691
6
    }
692
693
    template <RefType R>
694
    NonvirtualFunctionCall<NonvirtualVoidMethod> call_nonvirtual_void_method(
695
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
696
697
    template <RefType R>
698
    NonvirtualFunctionCall<NonvirtualObjectMethod> call_nonvirtual_object_method(
699
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
700
701
    template <RefType R>
702
    NonvirtualFunctionCall<NonvirtualIntMethod> call_nonvirtual_int_method(
703
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
704
705
    template <RefType R>
706
    NonvirtualFunctionCall<NonvirtualBooleanMethod> call_nonvirtual_boolean_method(
707
            JNIEnv* env, const Class<R>& clazz, MethodId method_id) const;
708
709
protected:
710
    jobject _obj = nullptr;
711
    DISALLOW_COPY_AND_ASSIGN(Object);
712
};
713
714
using LocalObject = Object<Local>;
715
using GlobalObject = Object<Global>;
716
717
static inline Status local_to_global_ref(JNIEnv* env, const LocalObject& local_ref,
718
11.5k
                                         GlobalObject* global_ref) {
719
11.5k
    return Object<Global>::create(env, local_ref, global_ref);
720
11.5k
}
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
11.5k
                                         GlobalObject* global_ref) {
719
11.5k
    return Object<Global>::create(env, local_ref, global_ref);
720
11.5k
}
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
4.19k
    BufferGuard() = default;
727
728
    template <RefType R>
729
    static Status create(JNIEnv* env, const Object<R>& object,
730
4.19k
                         BufferGuard<bufferfType, Ref>* result, jboolean* isCopy) {
731
4.19k
        DCHECK(result->_buffer == nullptr && result->_object.uninitialized());
732
733
4.19k
        RETURN_IF_ERROR(Object<Ref>::create(env, object, &result->_object));
734
735
4.19k
        if constexpr (bufferfType == BufferType::Chars) {
736
4.19k
            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
4.19k
        RETURN_ERROR_IF_EXC(env);
745
4.19k
        if (result->_buffer == nullptr) [[unlikely]] {
746
0
            return Status::JniError("GetStringUTFChars/GetByteArrayElements fail.");
747
0
        }
748
749
4.19k
        return Status::OK();
750
4.19k
    }
751
752
4.19k
    ~BufferGuard() {
753
4.19k
        if (_object.uninitialized() || _buffer == nullptr) [[unlikely]] {
754
0
            return;
755
0
        }
756
4.19k
        JNIEnv* env = nullptr;
757
758
4.19k
        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
4.19k
        if constexpr (bufferfType == BufferType::Chars) {
764
4.19k
            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
4.19k
    }
769
770
8.38k
    const char* get() const { return _buffer; }
771
772
private:
773
    Object<Ref> _object;
774
    const char* _buffer = nullptr;
775
776
    DISALLOW_COPY_AND_ASSIGN(BufferGuard);
777
};
778
779
template <RefType Ref>
780
using StringBufferGuard = BufferGuard<Chars, Ref>;
781
using LocalStringBufferGuard = BufferGuard<Chars, Local>;
782
using GlobalStringBufferGuard = BufferGuard<Chars, Global>;
783
784
template <RefType Ref>
785
using ByteArrayBufferGuard = BufferGuard<ByteArray, Ref>;
786
using LocalByteArrayBufferGuard = BufferGuard<ByteArray, Local>;
787
using GlobalByteArrayBufferGuard = BufferGuard<ByteArray, Global>;
788
789
// Reads a borrowed Java String as standard UTF-8 without taking ownership of the reference.
790
Status get_string_utf8(JNIEnv* env, jstring value, std::string* result);
791
792
template <RefType Ref>
793
class String : public Object<Ref> {
794
public:
795
50.2k
    String() = default;
796
797
    // Accepts JNI modified UTF-8. Use new_string_utf8 for standard UTF-8, e.g. scanner SQL.
798
11.4k
    static Status new_string(JNIEnv* env, const char* utf_chars, String<Ref>* result) {
799
11.4k
        DCHECK(result->uninitialized());
800
801
11.4k
        if constexpr (Ref == Local) {
802
11.4k
            result->_obj = env->NewStringUTF(utf_chars);
803
11.4k
            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
11.4k
        if (result->uninitialized()) {
813
1
            return Status::JniError("Failed to allocate modified UTF-8 Java string reference");
814
1
        }
815
11.4k
        return Status::OK();
816
11.4k
    }
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
4.19k
    Status get_string_chars(JNIEnv* env, StringBufferGuard<Ref>* jni_chars) const {
822
4.19k
        return StringBufferGuard<Ref>::create(env, *this, jni_chars, nullptr);
823
4.19k
    }
824
825
    // Unlike get_string_chars (JNI modified UTF-8), preserves standard UTF-8 and embedded NULs.
826
    // Rejects unpaired UTF-16 surrogates instead of replacing them.
827
8
    Status get_string_utf8(JNIEnv* env, std::string* result) const {
828
8
        DCHECK(!this->uninitialized());
829
8
        return Jni::get_string_utf8(env, static_cast<jstring>(this->_obj), result);
830
8
    }
831
832
private:
833
    DISALLOW_COPY_AND_ASSIGN(String);
834
};
835
836
extern template Status String<Local>::new_string_utf8(JNIEnv*, std::string_view, String<Local>*);
837
extern template Status String<Global>::new_string_utf8(JNIEnv*, std::string_view, String<Global>*);
838
839
template <RefType Ref>
840
class Array : public Object<Ref> {
841
public:
842
6.79k
    Array() = default;
843
844
500
    Status get_length(JNIEnv* env, jsize* result) const {
845
500
        DCHECK(!this->uninitialized());
846
847
500
        *result = env->GetArrayLength((jarray)this->_obj);
848
500
        RETURN_ERROR_IF_EXC(env);
849
500
        return Status::OK();
850
500
    }
851
852
68.7k
    Status get_object_array_element(JNIEnv* env, jsize index, Jni::LocalObject* result) {
853
68.7k
        DCHECK(!this->uninitialized());
854
68.7k
        DCHECK(result->uninitialized());
855
68.7k
        result->_obj = env->GetObjectArrayElement((jobjectArray)this->_obj, index);
856
68.7k
        RETURN_ERROR_IF_EXC(env);
857
68.7k
        return Status::OK();
858
68.7k
    }
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
82
    Status get_byte_elements(JNIEnv* env, jsize start, jsize len, jbyte* buffer) {
866
82
        DCHECK(!this->uninitialized());
867
82
        env->GetByteArrayRegion((jbyteArray)this->_obj, start, len, buffer);
868
82
        RETURN_ERROR_IF_EXC(env);
869
82
        return Status::OK();
870
82
    }
871
872
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
873
5.77k
                                         Array<Local>* serialized_msg) {
874
5.77k
        DCHECK(serialized_msg->uninitialized());
875
        /// create jbyteArray given buffer
876
5.77k
        serialized_msg->_obj = env->NewByteArray(size);
877
5.77k
        RETURN_ERROR_IF_EXC(env);
878
5.77k
        if (serialized_msg->_obj == nullptr) [[unlikely]] {
879
0
            return Status::JniError("couldn't construct jbyteArray");
880
0
        }
881
5.77k
        env->SetByteArrayRegion((jbyteArray)serialized_msg->_obj, 0, size, buffer);
882
5.77k
        RETURN_ERROR_IF_EXC(env);
883
5.77k
        return Status::OK();
884
5.77k
    }
885
886
    template <class T>
887
5.78k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Local>* serialized_msg) {
888
5.78k
        int buffer_size = 100 * 1024; // start out with 100KB
889
5.78k
        ThriftSerializer serializer(false, buffer_size);
890
891
5.78k
        uint8_t* buffer = nullptr;
892
5.78k
        uint32_t size = 0;
893
5.78k
        RETURN_IF_ERROR(serializer.serialize(msg, &size, &buffer));
894
895
        // Make sure that 'size' is within the limit of INT_MAX as the use of
896
        // 'size' below takes int.
897
5.78k
        if (size > INT_MAX) [[unlikely]] {
898
0
            return Status::JniError(
899
0
                    "The length of the serialization buffer ({} bytes) exceeds the limit of {} "
900
0
                    "bytes",
901
0
                    size, INT_MAX);
902
0
        }
903
5.78k
        RETURN_IF_ERROR(WriteBufferToByteArray(env, (jbyte*)buffer, size, serialized_msg));
904
5.78k
        return Status::OK();
905
5.78k
    }
906
907
private:
908
    DISALLOW_COPY_AND_ASSIGN(Array);
909
};
910
911
template <RefType Ref>
912
class Class : public Object<Ref> {
913
public:
914
11.7k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
914
5.90k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
914
5.80k
    Class() = default;
915
916
46
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
917
46
        DCHECK(result->uninitialized());
918
46
        if constexpr (Ref == Local) {
919
2
            result->_obj = env->FindClass(class_str);
920
2
            RETURN_ERROR_IF_EXC(env);
921
2
            return Status::OK();
922
44
        } else if constexpr (Ref == Global) {
923
44
            Class<Local> local_class;
924
44
            local_class._obj = env->FindClass(class_str);
925
44
            RETURN_ERROR_IF_EXC(env);
926
44
            return local_to_global_ref(env, local_class, result);
927
        } else {
928
            static_assert(false);
929
        }
930
46
    }
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EE10find_classEP7JNIEnv_PKcPS3_
Line
Count
Source
916
44
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
917
44
        DCHECK(result->uninitialized());
918
        if constexpr (Ref == Local) {
919
            result->_obj = env->FindClass(class_str);
920
            RETURN_ERROR_IF_EXC(env);
921
            return Status::OK();
922
44
        } else if constexpr (Ref == Global) {
923
44
            Class<Local> local_class;
924
44
            local_class._obj = env->FindClass(class_str);
925
44
            RETURN_ERROR_IF_EXC(env);
926
44
            return local_to_global_ref(env, local_class, result);
927
        } else {
928
            static_assert(false);
929
        }
930
44
    }
_ZN5doris3Jni5ClassILNS0_7RefTypeE0EE10find_classEP7JNIEnv_PKcPS3_
Line
Count
Source
916
2
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
917
2
        DCHECK(result->uninitialized());
918
2
        if constexpr (Ref == Local) {
919
2
            result->_obj = env->FindClass(class_str);
920
2
            RETURN_ERROR_IF_EXC(env);
921
2
            return Status::OK();
922
        } else if constexpr (Ref == Global) {
923
            Class<Local> local_class;
924
            local_class._obj = env->FindClass(class_str);
925
            RETURN_ERROR_IF_EXC(env);
926
            return local_to_global_ref(env, local_class, result);
927
        } else {
928
            static_assert(false);
929
        }
930
2
    }
931
932
    /**
933
     * The class of an object that is already in hand.
934
     *
935
     * Needed where a class cannot be named: an object produced by a plugin is an instance of a
936
     * class inside that plugin's classloader, which FindClass - searching BE's own loader -
937
     * cannot see. Asking the object is the only way to reach it.
938
     */
939
    template <RefType R>
940
5.73k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
5.73k
        DCHECK(!object.uninitialized());
942
5.73k
        DCHECK(result->uninitialized());
943
5.73k
        if constexpr (Ref == Local) {
944
0
            result->_obj = env->GetObjectClass(object._obj);
945
0
            RETURN_ERROR_IF_EXC(env);
946
0
            return Status::OK();
947
5.73k
        } else if constexpr (Ref == Global) {
948
5.73k
            Class<Local> local_class;
949
5.73k
            local_class._obj = env->GetObjectClass(object._obj);
950
5.73k
            RETURN_ERROR_IF_EXC(env);
951
5.73k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
5.73k
    }
Unexecuted instantiation: _ZN5doris3Jni5ClassILNS0_7RefTypeE0EE16get_object_classILS2_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT_EEEPS3_
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EE16get_object_classILS2_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT_EEEPS3_
Line
Count
Source
940
5.73k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
5.73k
        DCHECK(!object.uninitialized());
942
5.73k
        DCHECK(result->uninitialized());
943
        if constexpr (Ref == Local) {
944
            result->_obj = env->GetObjectClass(object._obj);
945
            RETURN_ERROR_IF_EXC(env);
946
            return Status::OK();
947
5.73k
        } else if constexpr (Ref == Global) {
948
5.73k
            Class<Local> local_class;
949
5.73k
            local_class._obj = env->GetObjectClass(object._obj);
950
5.73k
            RETURN_ERROR_IF_EXC(env);
951
5.73k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
5.73k
    }
956
957
    /**
958
     * Whether an object is an instance of this class.
959
     *
960
     * The one way to check the kind of something a plugin handed back: the object's own class is
961
     * private to the plugin's classloader, so the only comparable identity is a shared base class
962
     * BE resolved itself. IsInstanceOf raises no exception, hence the plain bool.
963
     */
964
    template <RefType R>
965
5
    bool is_instance(JNIEnv* env, const Object<R>& object) const {
966
5
        DCHECK(!this->uninitialized());
967
5
        DCHECK(!object.uninitialized());
968
5
        return env->IsInstanceOf(object._obj, (jclass)this->_obj) == JNI_TRUE;
969
5
    }
970
971
    Status get_static_method(JNIEnv* env, const char* method_str, const char* method_signature,
972
17
                             MethodId* method_id) const {
973
17
        DCHECK(!this->uninitialized());
974
17
        DCHECK(method_id->uninitialized());
975
17
        method_id->_id = env->GetStaticMethodID((jclass)this->_obj, method_str, method_signature);
976
17
        RETURN_ERROR_IF_EXC(env);
977
17
        return Status::OK();
978
17
    }
979
980
    Status get_method(JNIEnv* env, const char* method_str, const char* method_signature,
981
13.0k
                      MethodId* method_id) const {
982
13.0k
        DCHECK(!this->uninitialized());
983
13.0k
        DCHECK(method_id->uninitialized());
984
13.0k
        method_id->_id = env->GetMethodID((jclass)this->_obj, method_str, method_signature);
985
13.0k
        RETURN_ERROR_IF_EXC(env);
986
13.0k
        return Status::OK();
987
13.0k
    }
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.56k
    FunctionCall<NewObject> new_object(JNIEnv* env, MethodId method_id) const {
1026
5.56k
        DCHECK(!this->uninitialized());
1027
5.56k
        DCHECK(!method_id.uninitialized());
1028
5.56k
        return FunctionCall<NewObject>::instance(env, (jclass)this->_obj, method_id._id);
1029
5.56k
    }
1030
1031
    FunctionCall<StaticObjectMethod> call_static_object_method(JNIEnv* env,
1032
7.39k
                                                               MethodId method_id) const {
1033
7.39k
        DCHECK(!this->uninitialized());
1034
7.39k
        DCHECK(!method_id.uninitialized());
1035
7.39k
        return FunctionCall<StaticObjectMethod>::instance(env, (jclass)this->_obj, method_id._id);
1036
7.39k
    }
1037
1038
928
    FunctionCall<StaticVoidMethod> call_static_void_method(JNIEnv* env, MethodId method_id) const {
1039
928
        DCHECK(!this->uninitialized());
1040
928
        DCHECK(!method_id.uninitialized());
1041
928
        return FunctionCall<StaticVoidMethod>::instance(env, (jclass)this->_obj, method_id._id);
1042
928
    }
1043
1044
private:
1045
    DISALLOW_COPY_AND_ASSIGN(Class);
1046
};
1047
1048
using LocalClass = Class<Local>;
1049
using GlobalClass = Class<Global>;
1050
1051
using LocalArray = Array<Local>;
1052
using GlobalArray = Array<Global>;
1053
1054
using LocalString = String<Local>;
1055
using GlobalString = String<Global>;
1056
1057
template <CallTag tag>
1058
template <RefType Ref>
1059
57.7k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
57.7k
    jvalue v;
1061
57.7k
    std::memset(&v, 0, sizeof(v));
1062
57.7k
    v.l = obj._obj;
1063
57.7k
    _args.push_back(v);
1064
57.7k
    return *this;
1065
57.7k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
33.9k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
33.9k
    jvalue v;
1061
33.9k
    std::memset(&v, 0, sizeof(v));
1062
33.9k
    v.l = obj._obj;
1063
33.9k
    _args.push_back(v);
1064
33.9k
    return *this;
1065
33.9k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
235
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
235
    jvalue v;
1061
235
    std::memset(&v, 0, sizeof(v));
1062
235
    v.l = obj._obj;
1063
235
    _args.push_back(v);
1064
235
    return *this;
1065
235
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
5.33k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
5.33k
    jvalue v;
1061
5.33k
    std::memset(&v, 0, sizeof(v));
1062
5.33k
    v.l = obj._obj;
1063
5.33k
    _args.push_back(v);
1064
5.33k
    return *this;
1065
5.33k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
17.3k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
17.3k
    jvalue v;
1061
17.3k
    std::memset(&v, 0, sizeof(v));
1062
17.3k
    v.l = obj._obj;
1063
17.3k
    _args.push_back(v);
1064
17.3k
    return *this;
1065
17.3k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
928
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
928
    jvalue v;
1061
928
    std::memset(&v, 0, sizeof(v));
1062
928
    v.l = obj._obj;
1063
928
    _args.push_back(v);
1064
928
    return *this;
1065
928
}
1066
1067
template <CallTag tag>
1068
template <RefType Ref>
1069
82
NonvirtualFunctionCall<tag>& NonvirtualFunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1070
82
    jvalue v;
1071
82
    std::memset(&v, 0, sizeof(v));
1072
82
    v.l = obj._obj;
1073
82
    this->_args.push_back(v);
1074
82
    return *this;
1075
82
}
1076
1077
template <CallTag tag>
1078
92.7k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
92.7k
    DCHECK(result->uninitialized());
1080
92.7k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
92.7k
    RETURN_ERROR_IF_EXC(this->_env);
1082
92.7k
    return Status::OK();
1083
92.7k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
1.67k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
1.67k
    DCHECK(result->uninitialized());
1080
1.67k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
1.67k
    RETURN_ERROR_IF_EXC(this->_env);
1082
1.67k
    return Status::OK();
1083
1.67k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
85.5k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
85.5k
    DCHECK(result->uninitialized());
1080
85.5k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
85.5k
    RETURN_ERROR_IF_EXC(this->_env);
1082
85.5k
    return Status::OK();
1083
85.5k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
5.57k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
5.57k
    DCHECK(result->uninitialized());
1080
5.57k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
5.57k
    RETURN_ERROR_IF_EXC(this->_env);
1082
5.57k
    return Status::OK();
1083
5.57k
}
1084
1085
template <CallTag tag>
1086
5.70k
Status FunctionCall<tag>::call(Object<Global>* result) {
1087
5.70k
    DCHECK(result->uninitialized());
1088
5.70k
    Object<Local> local_result;
1089
5.70k
    local_result._obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1090
5.70k
    RETURN_ERROR_IF_EXC(this->_env);
1091
5.70k
    return local_to_global_ref(_env, local_result, result);
1092
5.70k
}
1093
1094
template <CallTag tag>
1095
82
Status NonvirtualFunctionCall<tag>::call(Object<Local>* result) {
1096
82
    DCHECK(result->uninitialized());
1097
82
    result->_obj = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
1098
82
                                              this->_args.data());
1099
82
    RETURN_ERROR_IF_EXC(this->_env);
1100
82
    return Status::OK();
1101
82
}
1102
1103
template <RefType Ref>
1104
template <RefType R>
1105
NonvirtualFunctionCall<NonvirtualObjectMethod> Object<Ref>::call_nonvirtual_object_method(
1106
82
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1107
82
    DCHECK(!this->uninitialized());
1108
82
    DCHECK(!method_id.uninitialized());
1109
1110
82
    return NonvirtualFunctionCall<NonvirtualObjectMethod>::instance(env, _obj, (jclass)clazz._obj,
1111
82
                                                                    method_id._id);
1112
82
}
1113
1114
template <RefType Ref>
1115
template <RefType R>
1116
NonvirtualFunctionCall<NonvirtualVoidMethod> Object<Ref>::call_nonvirtual_void_method(
1117
6.22k
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1118
6.22k
    DCHECK(!this->uninitialized());
1119
6.22k
    DCHECK(!method_id.uninitialized());
1120
6.22k
    return NonvirtualFunctionCall<NonvirtualVoidMethod>::instance(env, _obj, (jclass)clazz._obj,
1121
6.22k
                                                                  method_id._id);
1122
6.22k
}
1123
1124
template <RefType Ref>
1125
template <RefType R>
1126
NonvirtualFunctionCall<NonvirtualIntMethod> Object<Ref>::call_nonvirtual_int_method(
1127
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1128
    DCHECK(!this->uninitialized());
1129
    DCHECK(!method_id.uninitialized());
1130
    return NonvirtualFunctionCall<NonvirtualIntMethod>::instance(env, _obj, (jclass)clazz._obj,
1131
                                                                 method_id._id);
1132
}
1133
1134
template <RefType Ref>
1135
template <RefType R>
1136
NonvirtualFunctionCall<NonvirtualBooleanMethod> Object<Ref>::call_nonvirtual_boolean_method(
1137
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1138
    DCHECK(!this->uninitialized());
1139
    DCHECK(!method_id.uninitialized());
1140
    return NonvirtualFunctionCall<NonvirtualBooleanMethod>::instance(env, _obj, (jclass)clazz._obj,
1141
                                                                     method_id._id);
1142
}
1143
1144
class Util {
1145
public:
1146
    // Converts standard UTF-8 strings to a Java String[]. On success the caller owns the
1147
    // returned local reference; *result must be null on entry and is unchanged on failure.
1148
    static Status create_string_array_utf8(JNIEnv* env, const std::vector<std::string>& values,
1149
                                           jobjectArray* result);
1150
1151
    // Throws java.io.IOException with a standard UTF-8 message, using an ASCII fallback if
1152
    // message conversion fails. Exceptions from the IOException constructor are preserved.
1153
    static void throw_java_io_exception_utf8(JNIEnv* env, const std::string& message);
1154
1155
    static size_t get_max_jni_heap_memory_size();
1156
1157
    template <RefType Ref>
1158
46
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
1159
46
        return Class<Ref>::find_class(env, class_str, result);
1160
46
    }
_ZN5doris3Jni4Util10find_classILNS0_7RefTypeE1EEENS_6StatusEP7JNIEnv_PKcPNS0_5ClassIXT_EEE
Line
Count
Source
1158
44
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
1159
44
        return Class<Ref>::find_class(env, class_str, result);
1160
44
    }
_ZN5doris3Jni4Util10find_classILNS0_7RefTypeE0EEENS_6StatusEP7JNIEnv_PKcPNS0_5ClassIXT_EEE
Line
Count
Source
1158
2
    static Status find_class(JNIEnv* env, const char* class_str, Class<Ref>* result) {
1159
2
        return Class<Ref>::find_class(env, class_str, result);
1160
2
    }
1161
1162
    template <RefType Ref, RefType R>
1163
5.76k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
5.76k
        return Class<Ref>::get_object_class(env, object, result);
1165
5.76k
    }
Unexecuted instantiation: _ZN5doris3Jni4Util16get_object_classILNS0_7RefTypeE0ELS3_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT0_EEEPNS0_5ClassIXT_EEE
_ZN5doris3Jni4Util16get_object_classILNS0_7RefTypeE1ELS3_1EEENS_6StatusEP7JNIEnv_RKNS0_6ObjectIXT0_EEEPNS0_5ClassIXT_EEE
Line
Count
Source
1163
5.76k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
5.76k
        return Class<Ref>::get_object_class(env, object, result);
1165
5.76k
    }
1166
1167
    template <RefType Ref>
1168
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
1169
82
                                         Array<Ref>* serialized_msg) {
1170
82
        if constexpr (Ref == Local) {
1171
82
            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
82
    }
1180
1181
    template <class T, RefType Ref>
1182
5.79k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Ref>* serialized_msg) {
1183
5.79k
        if constexpr (Ref == Local) {
1184
5.79k
            return Array<Local>::SerializeThriftMsg(env, msg, serialized_msg);
1185
        } else if (Ref == Global) {
1186
            Array<Local> local_obj;
1187
            RETURN_IF_ERROR(Array<Local>::SerializeThriftMsg(env, msg, local_obj));
1188
            return local_to_global_ref(env, local_obj, serialized_msg);
1189
        } else {
1190
            static_assert(false);
1191
        }
1192
5.79k
    }
1193
1194
    template <RefType Ref>
1195
    static Status convert_to_java_map(JNIEnv* env, const std::map<std::string, std::string>& map,
1196
5.57k
                                      Object<Ref>* hashmap_object) {
1197
5.57k
        RETURN_IF_ERROR(hashmap_class.new_object(env, hashmap_constructor)
1198
5.57k
                                .with_arg((jint)map.size())
1199
5.57k
                                .call(hashmap_object));
1200
1201
16.8k
        for (const auto& it : map) {
1202
16.8k
            LocalString key;
1203
16.8k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.first, &key));
1204
1205
16.8k
            LocalString value;
1206
16.8k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.second, &value));
1207
1208
16.8k
            LocalObject result;
1209
16.8k
            RETURN_IF_ERROR(hashmap_object->call_object_method(env, hashmap_put)
1210
16.8k
                                    .with_arg(key)
1211
16.8k
                                    .with_arg(value)
1212
16.8k
                                    .call());
1213
16.8k
        }
1214
5.57k
        return Status::OK();
1215
5.57k
    }
1216
1217
    template <RefType Ref>
1218
    static Status convert_to_cpp_map(JNIEnv* env, const Object<Ref>& map,
1219
2
                                     std::map<std::string, std::string>* resultMap) {
1220
2
        LocalObject entrySet;
1221
2
        RETURN_IF_ERROR(map.call_object_method(env, mapEntrySetMethod).call(&entrySet));
1222
1223
        // Call the iterator method on the set to iterate over the key-value pairs
1224
2
        LocalObject iteratorSet;
1225
2
        RETURN_IF_ERROR(entrySet.call_object_method(env, iteratorSetMethod).call(&iteratorSet));
1226
1227
6
        while (true) {
1228
6
            jboolean hasNext = false;
1229
6
            RETURN_IF_ERROR(
1230
6
                    iteratorSet.call_boolean_method(env, iteratorHasNextMethod).call(&hasNext));
1231
6
            if (!hasNext) {
1232
2
                break;
1233
2
            }
1234
1235
4
            LocalObject entry;
1236
4
            RETURN_IF_ERROR(iteratorSet.call_object_method(env, iteratorNextMethod).call(&entry));
1237
1238
4
            LocalString javaKey;
1239
4
            RETURN_IF_ERROR(entry.call_object_method(env, getEntryKeyMethod).call(&javaKey));
1240
1241
4
            LocalString javaValue;
1242
4
            RETURN_IF_ERROR(entry.call_object_method(env, getEntryValueMethod).call(&javaValue));
1243
1244
4
            std::string key;
1245
4
            RETURN_IF_ERROR(javaKey.get_string_utf8(env, &key));
1246
1247
4
            std::string value;
1248
4
            RETURN_IF_ERROR(javaValue.get_string_utf8(env, &value));
1249
1250
            // Store the key-value pair in the map
1251
4
            (*resultMap)[std::move(key)] = std::move(value);
1252
4
        }
1253
2
        return Status::OK();
1254
2
    }
1255
1256
    // The outcome of the one attempt to resolve the JNI base, or nullopt when nothing has
1257
    // attempted it yet. Public, unlike ensure_jni_base() below, precisely because it never
1258
    // triggers the attempt: this is what a reader that must not create a JVM asks - the
1259
    // /api/jni_plugin_status endpoint, which exists to answer "why is Java not working here"
1260
    // and would otherwise have to start a JVM to find out.
1261
    static std::optional<Status> jni_base_outcome();
1262
1263
private:
1264
    // Resolves everything the BE needs from the JVM before it can call any Java code: the
1265
    // exception helpers, the native methods the Java side links against, and the
1266
    // collection classes cached below. Runs once, right after the JVM appears; every
1267
    // caller that follows gets the outcome of that one attempt.
1268
    //
1269
    // Deliberately NOT part of "does this process have a JVM": all of it comes out of
1270
    // doris-jni-spi.jar, and a BE whose Java deployment is incomplete still serves HDFS through
1271
    // libhdfs. JvmLauncher runs it once at the end of its bootstrap and logs a failure; Env, the
1272
    // door every Java caller comes through, refuses to hand out a JNIEnv while it is failing.
1273
    //
1274
    // Only those two may call it. JvmLauncher calls it from inside its bootstrap, with the
1275
    // calling thread already attached and its env cached, because the resolution asks Env::Get()
1276
    // for a JNIEnv and an unattached thread there would go back through ensure_jvm() and deadlock
1277
    // on the once flag the bootstrap is already holding.
1278
    //
1279
    // Env::GetJNIEnvSlowPath() calls it from an unattached thread on purpose, and the invariant
1280
    // that makes THAT safe is a different one, worth stating because nothing enforces it: by the
1281
    // time the slow path gets here, ensure_jvm()'s call_once has already run to completion on
1282
    // some thread, so the resolution below is never the one that runs - it is always the cached
1283
    // answer of the attempt the bootstrap made. Every early exit of _bootstrap() leaves
1284
    // jvm_status non-OK, and the slow path returns on that before reaching this line.
1285
    //
1286
    // Making the base lazy (that is, resolving it here for real rather than reading a cached
1287
    // answer) would put the deadlock straight back, so GetJNIEnvSlowPath() holds it down with a
1288
    // DCHECK: on that path an outcome must already exist before this is called.
1289
    static Status ensure_jni_base();
1290
    friend class JvmLauncher;
1291
    friend class Env;
1292
1293
    static void _parse_max_heap_memory_size_from_jvm();
1294
1295
    // Bytes named by the last -Xmx in `options`, or 0 when none of them says. Split out from the
1296
    // above so that the parsing can be tested without a JVM; see jni_util_test.cpp.
1297
    static jlong _parse_xmx(const std::string& options);
1298
1299
    static Status _init_jni_base() WARN_UNUSED_RESULT;
1300
    static Status _init_collect_class() WARN_UNUSED_RESULT;
1301
    static Status _init_register_natives() WARN_UNUSED_RESULT;
1302
1303
    // for jvm heap
1304
    static jlong max_jvm_heap_memory_size_;
1305
1306
    //for hashmap
1307
    static GlobalClass hashmap_class;
1308
    static MethodId hashmap_constructor;
1309
    static MethodId hashmap_put;
1310
1311
    //for map
1312
    static GlobalClass mapClass;
1313
    static MethodId mapEntrySetMethod;
1314
1315
    // for map entry
1316
    static GlobalClass mapEntryClass;
1317
    static MethodId getEntryKeyMethod;
1318
    static MethodId getEntryValueMethod;
1319
1320
    //for set
1321
    static GlobalClass setClass;
1322
    static MethodId iteratorSetMethod;
1323
1324
    // for iterator
1325
    static GlobalClass iteratorClass;
1326
    static MethodId iteratorHasNextMethod;
1327
    static MethodId iteratorNextMethod;
1328
};
1329
}; // namespace Jni
1330
1331
} // namespace doris