Coverage Report

Created: 2026-11-03 10:06

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
326k
    do {                                              \
45
326k
        if (env->ExceptionCheck()) [[unlikely]]       \
46
4
            return Jni::Env::GetJniExceptionMsg(env); \
47
326k
    } 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
280k
    static Status Get(JNIEnv** env) {
59
280k
        if (tls_env_) {
60
280k
            *env = tls_env_;
61
280k
        } else {
62
180
            Status status = GetJNIEnvSlowPath(env);
63
180
            if (!status.ok()) {
64
0
                return status;
65
0
            }
66
180
        }
67
280k
        if (*env == nullptr) [[unlikely]] {
68
0
            return Status::JniError("Failed to get JNIEnv: it is nullptr.");
69
0
        }
70
280k
        return Status::OK();
71
280k
    }
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
53
    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
933
    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
465
    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.62k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewLocalRef(obj); }
177
178
249k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteLocalRef(obj); }
179
180
253k
    static Status get_env(JNIEnv** env) {
181
        // Get the JNIEnv* corresponding to current thread.
182
253k
        return Jni::Env::Get(env);
183
253k
    }
184
};
185
186
template <>
187
struct RefHelper<Global> {
188
10.9k
    static jobject create(JNIEnv* env, jobject obj) { return env->NewGlobalRef(obj); }
189
190
10.9k
    static void destroy(JNIEnv* env, jobject obj) { env->DeleteGlobalRef(obj); }
191
192
10.9k
    static Status get_env(JNIEnv** env) { return Jni::Env::Get(env); }
193
};
194
195
template <RefType Ref>
196
class Object;
197
198
template <RefType Ref>
199
class Class;
200
201
class MethodId {
202
public:
203
13.4k
    MethodId() = default;
204
171k
    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
113k
    static jobject call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
257
113k
        return env->CallObjectMethodA(obj, methodID, args);
258
113k
    }
259
    using BASE_TYPE = jobject;
260
    using RETURN_TYPE = jobject;
261
};
262
263
template <>
264
struct CallHelper<IntMethod> {
265
1.38k
    static jint call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
266
1.38k
        return env->CallIntMethodA(obj, methodID, args);
267
1.38k
    }
268
    using BASE_TYPE = jobject;
269
    using RETURN_TYPE = jint;
270
};
271
272
template <>
273
struct CallHelper<LongMethod> {
274
18.0k
    static jlong call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
275
18.0k
        return env->CallLongMethodA(obj, methodID, args);
276
18.0k
    }
277
    using BASE_TYPE = jobject;
278
    using RETURN_TYPE = jlong;
279
};
280
281
template <>
282
struct CallHelper<VoidMethod> {
283
248
    static void call_impl(JNIEnv* env, jobject obj, jmethodID methodID, const jvalue* args) {
284
248
        env->CallVoidMethodA(obj, methodID, args);
285
248
    }
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.23k
    static jobject call_impl(JNIEnv* env, jclass cls, jmethodID methodID, const jvalue* args) {
302
7.23k
        return env->CallStaticObjectMethodA(cls, methodID, args);
303
7.23k
    }
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
5.91k
                          const jvalue* args) {
350
5.91k
        return env->CallNonvirtualVoidMethodA(obj, clazz, methodID, args);
351
5.91k
    }
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
77
                             const jvalue* args) {
361
77
        return env->CallNonvirtualObjectMethodA(obj, clazz, methodID, args);
362
77
    }
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
147k
                                 jmethodID method_id) {
397
147k
        return FunctionCall(env, base, method_id);
398
147k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
7.26k
                                 jmethodID method_id) {
397
7.26k
        return FunctionCall(env, base, method_id);
398
7.26k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
113k
                                 jmethodID method_id) {
397
113k
        return FunctionCall(env, base, method_id);
398
113k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
18.0k
                                 jmethodID method_id) {
397
18.0k
        return FunctionCall(env, base, method_id);
398
18.0k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
1.38k
                                 jmethodID method_id) {
397
1.38k
        return FunctionCall(env, base, method_id);
398
1.38k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8instanceEP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
396
249
                                 jmethodID method_id) {
397
249
        return FunctionCall(env, base, method_id);
398
249
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE8instanceEP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
396
5.57k
                                 jmethodID method_id) {
397
5.57k
        return FunctionCall(env, base, method_id);
398
5.57k
    }
_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.9k
    FunctionCall& with_arg(T arg) {
408
12.9k
        jvalue v;
409
12.9k
        std::memset(&v, 0, sizeof(v));
410
12.9k
        if constexpr (std::is_same_v<T, jboolean>) {
411
226
            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
11.3k
        } else if constexpr (std::is_same_v<T, jint>) {
419
11.3k
            v.i = arg;
420
11.3k
        } else if constexpr (std::is_same_v<T, jlong>) {
421
1.35k
            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.9k
        _args.push_back(v);
430
12.9k
        return *this;
431
12.9k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8with_argIiQsr3stdE13disjunction_vISt7is_sameITL0__hES5_IS6_aES5_IS6_tES5_IS6_sES5_IS6_iES5_IS6_lES5_IS6_fES5_IS6_dEEEERS3_T_
Line
Count
Source
407
5.08k
    FunctionCall& with_arg(T arg) {
408
5.08k
        jvalue v;
409
5.08k
        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.08k
        } else if constexpr (std::is_same_v<T, jint>) {
419
5.08k
            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.08k
        _args.push_back(v);
430
5.08k
        return *this;
431
5.08k
    }
_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
226
    FunctionCall& with_arg(T arg) {
408
226
        jvalue v;
409
226
        std::memset(&v, 0, sizeof(v));
410
226
        if constexpr (std::is_same_v<T, jboolean>) {
411
226
            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
226
        _args.push_back(v);
430
226
        return *this;
431
226
    }
_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
682
    FunctionCall& with_arg(T arg) {
408
682
        jvalue v;
409
682
        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
682
        } else if constexpr (std::is_same_v<T, jint>) {
419
682
            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
682
        _args.push_back(v);
430
682
        return *this;
431
682
    }
_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
225
    FunctionCall& with_arg(T arg) {
408
225
        jvalue v;
409
225
        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
225
        } else if constexpr (std::is_same_v<T, jlong>) {
421
225
            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
225
        _args.push_back(v);
430
225
        return *this;
431
225
    }
_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
19.4k
    Status call(ReturnType* result) {
439
19.4k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
19.4k
        RETURN_ERROR_IF_EXC(_env);
441
19.4k
        return Status::OK();
442
19.4k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE4callIlQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
18.0k
    Status call(ReturnType* result) {
439
18.0k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
18.0k
        RETURN_ERROR_IF_EXC(_env);
441
18.0k
        return Status::OK();
442
18.0k
    }
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EE4callIiQsr3stdE9is_same_vINS0_10CallHelperIXT_EE11RETURN_TYPEETL0__EEENS_6StatusEPT_
Line
Count
Source
438
1.38k
    Status call(ReturnType* result) {
439
1.38k
        *result = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
440
1.38k
        RETURN_ERROR_IF_EXC(_env);
441
1.38k
        return Status::OK();
442
1.38k
    }
_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.17k
                              std::is_same<return_type, void>>) {
456
1.17k
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
1.17k
            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
247
    Status call() {
449
247
        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
247
                              std::is_same<return_type, void>>) {
456
247
            CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
457
247
            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
247
        return Status::OK();
466
247
    }
_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
153k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
7.26k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
113k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
18.0k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE1EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
1.38k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
249
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EEC2EP7JNIEnv_P7_jclassP10_jmethodID
Line
Count
Source
471
5.57k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
5.91k
            : _env(env), _base(base), _method(method_id) {}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP10_jmethodID
Line
Count
Source
471
77
            : _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
5.99k
                                           jclass cls, jmethodID method_id) {
488
5.99k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
5.99k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
5.91k
                                           jclass cls, jmethodID method_id) {
488
5.91k
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
5.91k
    }
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EE8instanceEP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
487
77
                                           jclass cls, jmethodID method_id) {
488
77
        return NonvirtualFunctionCall(env, base, cls, method_id);
489
77
    }
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
189
    NonvirtualFunctionCall& with_arg(T arg) {
498
189
        jvalue v;
499
189
        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
189
        } else if constexpr (std::is_same_v<T, jlong>) {
511
189
            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
189
        this->_args.push_back(v);
520
189
        return *this;
521
189
    }
_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
113
    NonvirtualFunctionCall& with_arg(T arg) {
498
113
        jvalue v;
499
113
        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
113
        } else if constexpr (std::is_same_v<T, jlong>) {
511
113
            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
113
        this->_args.push_back(v);
520
113
        return *this;
521
113
    }
_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
76
    NonvirtualFunctionCall& with_arg(T arg) {
498
76
        jvalue v;
499
76
        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
76
        } else if constexpr (std::is_same_v<T, jlong>) {
511
76
            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
76
        this->_args.push_back(v);
520
76
        return *this;
521
76
    }
522
523
    template <RefType Ref>
524
    NonvirtualFunctionCall& with_arg(const Object<Ref>& obj) WARN_UNUSED_RESULT;
525
526
    // no override
527
5.91k
    Status call() {
528
5.91k
        using return_type = typename CallHelper<tag>::RETURN_TYPE;
529
        if constexpr (std::disjunction_v<
530
                              std::is_same<return_type, jboolean>, std::is_same<return_type, jbyte>,
531
                              std::is_same<return_type, jchar>, std::is_same<return_type, jshort>,
532
                              std::is_same<return_type, jint>, std::is_same<return_type, jlong>,
533
                              std::is_same<return_type, jfloat>, std::is_same<return_type, jdouble>,
534
5.91k
                              std::is_same<return_type, void>>) {
535
5.91k
            CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
536
5.91k
                                       this->_args.data());
537
5.91k
            RETURN_ERROR_IF_EXC(this->_env);
538
        } else if constexpr (std::is_same_v<return_type, jobject>) {
539
            jobject tmp = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
540
                                                     this->_args.data());
541
            RETURN_ERROR_IF_EXC(this->_env);
542
            this->_env->DeleteLocalRef(tmp);
543
        } else {
544
            static_assert(false);
545
        }
546
5.91k
        return Status::OK();
547
5.91k
    }
548
549
    Status call(Object<Local>* result);
550
551
    template <typename ReturnType>
552
        requires(std::is_same_v<typename CallHelper<tag>::RETURN_TYPE, ReturnType>)
553
    Status call(ReturnType* result) {
554
        *result = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
555
                                             this->_args.data());
556
        RETURN_ERROR_IF_EXC(this->_env);
557
        return Status::OK();
558
    }
559
560
private:
561
    explicit NonvirtualFunctionCall(JNIEnv* env, typename CallHelper<tag>::BASE_TYPE base,
562
                                    jclass cls, jmethodID method_id)
563
5.99k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE10EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
5.91k
            : FunctionCall<tag>(env, base, method_id), _cls(cls) {}
_ZN5doris3Jni22NonvirtualFunctionCallILNS0_7CallTagE11EEC2EP7JNIEnv_P8_jobjectP7_jclassP10_jmethodID
Line
Count
Source
563
77
            : 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
276k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
599
11.2k
    Object() = default;
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
599
265k
    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
276k
    virtual ~Object() {
623
276k
        if (_obj != nullptr) [[likely]] {
624
260k
            JNIEnv* env = nullptr;
625
260k
            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
260k
            RefHelper<Ref>::destroy(env, _obj);
630
260k
        }
631
276k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EED2Ev
Line
Count
Source
622
265k
    virtual ~Object() {
623
265k
        if (_obj != nullptr) [[likely]] {
624
249k
            JNIEnv* env = nullptr;
625
249k
            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
249k
            RefHelper<Ref>::destroy(env, _obj);
630
249k
        }
631
265k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EED2Ev
Line
Count
Source
622
11.2k
    virtual ~Object() {
623
11.2k
        if (_obj != nullptr) [[likely]] {
624
10.9k
            JNIEnv* env = nullptr;
625
10.9k
            if (Status st = RefHelper<Ref>::get_env(&env); !st.ok()) [[unlikely]] {
626
0
                LOG(WARNING) << "Can't destroy Jni Ref : " << st.msg();
627
0
                return;
628
0
            }
629
10.9k
            RefHelper<Ref>::destroy(env, _obj);
630
10.9k
        }
631
11.2k
    }
632
633
    template <RefType R>
634
15.5k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
15.5k
        DCHECK(!other.uninitialized());
636
15.5k
        DCHECK(result->uninitialized());
637
638
15.5k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
15.5k
        RETURN_ERROR_IF_EXC(env);
640
15.5k
        return Status::OK();
641
15.5k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE1EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
10.9k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
10.9k
        DCHECK(!other.uninitialized());
636
10.9k
        DCHECK(result->uninitialized());
637
638
10.9k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
10.9k
        RETURN_ERROR_IF_EXC(env);
640
10.9k
        return Status::OK();
641
10.9k
    }
_ZN5doris3Jni6ObjectILNS0_7RefTypeE0EE6createILS2_0EEENS_6StatusEP7JNIEnv_RKNS1_IXT_EEEPS3_
Line
Count
Source
634
4.62k
    static Status create(JNIEnv* env, const Object<R>& other, Object<Ref>* result) {
635
4.62k
        DCHECK(!other.uninitialized());
636
4.62k
        DCHECK(result->uninitialized());
637
638
4.62k
        result->_obj = RefHelper<Ref>::create(env, other._obj);
639
4.62k
        RETURN_ERROR_IF_EXC(env);
640
4.62k
        return Status::OK();
641
4.62k
    }
642
643
991k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE13uninitializedEv
Line
Count
Source
643
756k
    bool uninitialized() const { return _obj == nullptr; }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE13uninitializedEv
Line
Count
Source
643
235k
    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
160k
    bool equal(JNIEnv* env, const Object<T>& other) {
658
160k
        DCHECK(!uninitialized());
659
160k
        DCHECK(!other.uninitialized());
660
160k
        return env->IsSameObject(this->_obj, other._obj); //assume not throw exception.
661
160k
    }
662
663
113k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
113k
        DCHECK(!this->uninitialized());
665
113k
        DCHECK(!method_id.uninitialized());
666
113k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
113k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE18call_object_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
663
113k
    FunctionCall<ObjectMethod> call_object_method(JNIEnv* env, MethodId method_id) const {
664
113k
        DCHECK(!this->uninitialized());
665
        DCHECK(!method_id.uninitialized());
666
113k
        return FunctionCall<ObjectMethod>::instance(env, _obj, method_id._id);
667
113k
    }
_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.38k
    FunctionCall<IntMethod> call_int_method(JNIEnv* env, MethodId method_id) const {
670
1.38k
        DCHECK(!this->uninitialized());
671
1.38k
        DCHECK(!method_id.uninitialized());
672
1.38k
        return FunctionCall<IntMethod>::instance(env, _obj, method_id._id);
673
1.38k
    }
674
675
18.0k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
18.0k
        DCHECK(!this->uninitialized());
677
18.0k
        DCHECK(!method_id.uninitialized());
678
18.0k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
18.0k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE0EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
15.2k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
15.2k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
15.2k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
15.2k
    }
_ZNK5doris3Jni6ObjectILNS0_7RefTypeE1EE16call_long_methodEP7JNIEnv_NS0_8MethodIdE
Line
Count
Source
675
2.78k
    FunctionCall<LongMethod> call_long_method(JNIEnv* env, MethodId method_id) const {
676
2.78k
        DCHECK(!this->uninitialized());
677
        DCHECK(!method_id.uninitialized());
678
2.78k
        return FunctionCall<LongMethod>::instance(env, _obj, method_id._id);
679
2.78k
    }
680
681
249
    FunctionCall<VoidMethod> call_void_method(JNIEnv* env, MethodId method_id) const {
682
249
        DCHECK(!this->uninitialized());
683
249
        DCHECK(!method_id.uninitialized());
684
249
        return FunctionCall<VoidMethod>::instance(env, _obj, method_id._id);
685
249
    }
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.0k
                                         GlobalObject* global_ref) {
719
11.0k
    return Object<Global>::create(env, local_ref, global_ref);
720
11.0k
}
Unexecuted instantiation: doris_main.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_0_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: config.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: doris_metrics.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
jvm_metrics.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Line
Count
Source
718
62
                                         GlobalObject* global_ref) {
719
62
    return Object<Global>::create(env, local_ref, global_ref);
720
62
}
Unexecuted instantiation: unity_14_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_2_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_3_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_5_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_15_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
unity_1_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Line
Count
Source
718
10.9k
                                         GlobalObject* global_ref) {
719
10.9k
    return Object<Global>::create(env, local_ref, global_ref);
720
10.9k
}
Unexecuted instantiation: unity_8_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_9_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_10_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_4_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_13_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_12_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_11_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_7_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_6_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: hashjoin_build_sink.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: join_build_sink_operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: partitioned_aggregation_sink_operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: scan_operator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vfile_result_writer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_32_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_31_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_30_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_29_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_28_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_27_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_26_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_25_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_24_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_22_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_21_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_20_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_19_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_18_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_17_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_16_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: ai_functions.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: function_array_aggregation.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: function_date_or_datetime_computation.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: function_datetime_floor_ceil.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: in.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: uuid.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: arrow_row_batch.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: jni_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: iceberg_delete_file_reader_helper.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_disk_usage_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: jdbc_jni_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: parquet_metadata_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: schema_desc.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: parquet_utils.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: parquet_column_convert.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: column_type_convert.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: iceberg_partition_function.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: merge_partitioner.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vcsv_transformer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vfile_format_transformer_factory.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: viceberg_parquet_writer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vjni_format_transformer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vorc_transformer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vparquet_writer.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: adbc_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: hdfs_file_system.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: unity_23_cxx.cxx:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_compound_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_disk_usage.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: index_fs_directory.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: zone_map_index.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: vcollect_iterator.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: predicate_creator_comparison.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: predicate_creator_in_list_in.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: predicate_creator_in_list_not_in.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: tablet.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: engine_clone_task.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: descriptors.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: backend_service.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: point_query_executor.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: be_server_starter_factory.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: http_service.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: internal_service.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: arrow_flight_batch_reader.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: thrift_util.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: load_stream.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: routine_load_task_executor.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
Unexecuted instantiation: cloud_compaction_action.cpp:_ZN5doris3JniL19local_to_global_refEP7JNIEnv_RKNS0_6ObjectILNS0_7RefTypeE0EEEPNS3_ILS4_1EEE
721
722
// auto ReleaseStringUTFChars ReleaseByteArrayElements ...
723
template <BufferType bufferfType, RefType Ref>
724
class BufferGuard {
725
public:
726
4.62k
    BufferGuard() = default;
727
728
    template <RefType R>
729
    static Status create(JNIEnv* env, const Object<R>& object,
730
4.62k
                         BufferGuard<bufferfType, Ref>* result, jboolean* isCopy) {
731
4.62k
        DCHECK(result->_buffer == nullptr && result->_object.uninitialized());
732
733
4.62k
        RETURN_IF_ERROR(Object<Ref>::create(env, object, &result->_object));
734
735
4.62k
        if constexpr (bufferfType == BufferType::Chars) {
736
4.62k
            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.62k
        RETURN_ERROR_IF_EXC(env);
745
4.62k
        if (result->_buffer == nullptr) [[unlikely]] {
746
0
            return Status::JniError("GetStringUTFChars/GetByteArrayElements fail.");
747
0
        }
748
749
4.62k
        return Status::OK();
750
4.62k
    }
751
752
4.62k
    ~BufferGuard() {
753
4.62k
        if (_object.uninitialized() || _buffer == nullptr) [[unlikely]] {
754
0
            return;
755
0
        }
756
4.62k
        JNIEnv* env = nullptr;
757
758
4.62k
        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.62k
        if constexpr (bufferfType == BufferType::Chars) {
764
4.62k
            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.62k
    }
769
770
9.24k
    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
49.9k
    String() = default;
796
797
    // Accepts JNI modified UTF-8. Use new_string_utf8 for standard UTF-8, e.g. scanner SQL.
798
10.7k
    static Status new_string(JNIEnv* env, const char* utf_chars, String<Ref>* result) {
799
10.7k
        DCHECK(result->uninitialized());
800
801
10.7k
        if constexpr (Ref == Local) {
802
10.7k
            result->_obj = env->NewStringUTF(utf_chars);
803
10.7k
            RETURN_ERROR_IF_EXC(env);
804
        } else if constexpr (Ref == Global) {
805
            String<Local> local_result;
806
            RETURN_IF_ERROR(String<Local>::new_string(env, utf_chars, &local_result));
807
            RETURN_IF_ERROR(local_to_global_ref(env, local_result, result));
808
        } else {
809
            static_assert(false);
810
        }
811
        // JNI allocation may return null without a pending exception.
812
10.7k
        if (result->uninitialized()) {
813
1
            return Status::JniError("Failed to allocate modified UTF-8 Java string reference");
814
1
        }
815
10.7k
        return Status::OK();
816
10.7k
    }
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.62k
    Status get_string_chars(JNIEnv* env, StringBufferGuard<Ref>* jni_chars) const {
822
4.62k
        return StringBufferGuard<Ref>::create(env, *this, jni_chars, nullptr);
823
4.62k
    }
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.55k
    Array() = default;
843
844
539
    Status get_length(JNIEnv* env, jsize* result) const {
845
539
        DCHECK(!this->uninitialized());
846
847
539
        *result = env->GetArrayLength((jarray)this->_obj);
848
539
        RETURN_ERROR_IF_EXC(env);
849
539
        return Status::OK();
850
539
    }
851
852
78.3k
    Status get_object_array_element(JNIEnv* env, jsize index, Jni::LocalObject* result) {
853
78.3k
        DCHECK(!this->uninitialized());
854
78.3k
        DCHECK(result->uninitialized());
855
78.3k
        result->_obj = env->GetObjectArrayElement((jobjectArray)this->_obj, index);
856
78.3k
        RETURN_ERROR_IF_EXC(env);
857
78.3k
        return Status::OK();
858
78.3k
    }
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
77
    Status get_byte_elements(JNIEnv* env, jsize start, jsize len, jbyte* buffer) {
866
77
        DCHECK(!this->uninitialized());
867
77
        env->GetByteArrayRegion((jbyteArray)this->_obj, start, len, buffer);
868
77
        RETURN_ERROR_IF_EXC(env);
869
77
        return Status::OK();
870
77
    }
871
872
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
873
5.42k
                                         Array<Local>* serialized_msg) {
874
5.42k
        DCHECK(serialized_msg->uninitialized());
875
        /// create jbyteArray given buffer
876
5.42k
        serialized_msg->_obj = env->NewByteArray(size);
877
5.42k
        RETURN_ERROR_IF_EXC(env);
878
5.42k
        if (serialized_msg->_obj == nullptr) [[unlikely]] {
879
0
            return Status::JniError("couldn't construct jbyteArray");
880
0
        }
881
5.42k
        env->SetByteArrayRegion((jbyteArray)serialized_msg->_obj, 0, size, buffer);
882
5.42k
        RETURN_ERROR_IF_EXC(env);
883
5.42k
        return Status::OK();
884
5.42k
    }
885
886
    template <class T>
887
5.45k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Local>* serialized_msg) {
888
5.45k
        int buffer_size = 100 * 1024; // start out with 100KB
889
5.45k
        ThriftSerializer serializer(false, buffer_size);
890
891
5.45k
        uint8_t* buffer = nullptr;
892
5.45k
        uint32_t size = 0;
893
5.45k
        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.45k
        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.45k
        RETURN_IF_ERROR(WriteBufferToByteArray(env, (jbyte*)buffer, size, serialized_msg));
904
5.45k
        return Status::OK();
905
5.45k
    }
906
907
private:
908
    DISALLOW_COPY_AND_ASSIGN(Array);
909
};
910
911
template <RefType Ref>
912
class Class : public Object<Ref> {
913
public:
914
11.1k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE1EEC2Ev
Line
Count
Source
914
5.60k
    Class() = default;
_ZN5doris3Jni5ClassILNS0_7RefTypeE0EEC2Ev
Line
Count
Source
914
5.51k
    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.44k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
5.44k
        DCHECK(!object.uninitialized());
942
5.44k
        DCHECK(result->uninitialized());
943
5.44k
        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.44k
        } else if constexpr (Ref == Global) {
948
5.44k
            Class<Local> local_class;
949
5.44k
            local_class._obj = env->GetObjectClass(object._obj);
950
5.44k
            RETURN_ERROR_IF_EXC(env);
951
5.44k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
5.44k
    }
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.44k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
941
5.44k
        DCHECK(!object.uninitialized());
942
5.44k
        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.44k
        } else if constexpr (Ref == Global) {
948
5.44k
            Class<Local> local_class;
949
5.44k
            local_class._obj = env->GetObjectClass(object._obj);
950
5.44k
            RETURN_ERROR_IF_EXC(env);
951
5.44k
            return local_to_global_ref(env, local_class, result);
952
        } else {
953
            static_assert(false);
954
        }
955
5.44k
    }
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
12.4k
                      MethodId* method_id) const {
982
12.4k
        DCHECK(!this->uninitialized());
983
12.4k
        DCHECK(method_id->uninitialized());
984
12.4k
        method_id->_id = env->GetMethodID((jclass)this->_obj, method_str, method_signature);
985
12.4k
        RETURN_ERROR_IF_EXC(env);
986
12.4k
        return Status::OK();
987
12.4k
    }
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.57k
    FunctionCall<NewObject> new_object(JNIEnv* env, MethodId method_id) const {
1026
5.57k
        DCHECK(!this->uninitialized());
1027
5.57k
        DCHECK(!method_id.uninitialized());
1028
5.57k
        return FunctionCall<NewObject>::instance(env, (jclass)this->_obj, method_id._id);
1029
5.57k
    }
1030
1031
    FunctionCall<StaticObjectMethod> call_static_object_method(JNIEnv* env,
1032
7.21k
                                                               MethodId method_id) const {
1033
7.21k
        DCHECK(!this->uninitialized());
1034
7.21k
        DCHECK(!method_id.uninitialized());
1035
7.21k
        return FunctionCall<StaticObjectMethod>::instance(env, (jclass)this->_obj, method_id._id);
1036
7.21k
    }
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
56.8k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
56.8k
    jvalue v;
1061
56.8k
    std::memset(&v, 0, sizeof(v));
1062
56.8k
    v.l = obj._obj;
1063
56.8k
    _args.push_back(v);
1064
56.8k
    return *this;
1065
56.8k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
34.0k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
34.0k
    jvalue v;
1061
34.0k
    std::memset(&v, 0, sizeof(v));
1062
34.0k
    v.l = obj._obj;
1063
34.0k
    _args.push_back(v);
1064
34.0k
    return *this;
1065
34.0k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE3EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
226
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
226
    jvalue v;
1061
226
    std::memset(&v, 0, sizeof(v));
1062
226
    v.l = obj._obj;
1063
226
    _args.push_back(v);
1064
226
    return *this;
1065
226
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE2EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
5.34k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
5.34k
    jvalue v;
1061
5.34k
    std::memset(&v, 0, sizeof(v));
1062
5.34k
    v.l = obj._obj;
1063
5.34k
    _args.push_back(v);
1064
5.34k
    return *this;
1065
5.34k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
16.3k
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
16.3k
    jvalue v;
1061
16.3k
    std::memset(&v, 0, sizeof(v));
1062
16.3k
    v.l = obj._obj;
1063
16.3k
    _args.push_back(v);
1064
16.3k
    return *this;
1065
16.3k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE8EE8with_argILNS0_7RefTypeE0EEERS3_RKNS0_6ObjectIXT_EEE
Line
Count
Source
1059
928
FunctionCall<tag>& FunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1060
928
    jvalue v;
1061
928
    std::memset(&v, 0, sizeof(v));
1062
928
    v.l = obj._obj;
1063
928
    _args.push_back(v);
1064
928
    return *this;
1065
928
}
1066
1067
template <CallTag tag>
1068
template <RefType Ref>
1069
77
NonvirtualFunctionCall<tag>& NonvirtualFunctionCall<tag>::with_arg(const Object<Ref>& obj) {
1070
77
    jvalue v;
1071
77
    std::memset(&v, 0, sizeof(v));
1072
77
    v.l = obj._obj;
1073
77
    this->_args.push_back(v);
1074
77
    return *this;
1075
77
}
1076
1077
template <CallTag tag>
1078
104k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
104k
    DCHECK(result->uninitialized());
1080
104k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
104k
    RETURN_ERROR_IF_EXC(this->_env);
1082
104k
    return Status::OK();
1083
104k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE5EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
1.84k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
1.84k
    DCHECK(result->uninitialized());
1080
1.84k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
1.84k
    RETURN_ERROR_IF_EXC(this->_env);
1082
1.84k
    return Status::OK();
1083
1.84k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE0EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
96.8k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
96.8k
    DCHECK(result->uninitialized());
1080
96.8k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
96.8k
    RETURN_ERROR_IF_EXC(this->_env);
1082
96.8k
    return Status::OK();
1083
96.8k
}
_ZN5doris3Jni12FunctionCallILNS0_7CallTagE9EE4callEPNS0_6ObjectILNS0_7RefTypeE0EEE
Line
Count
Source
1078
5.56k
Status FunctionCall<tag>::call(Object<Local>* result) {
1079
5.56k
    DCHECK(result->uninitialized());
1080
5.56k
    result->_obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1081
5.56k
    RETURN_ERROR_IF_EXC(this->_env);
1082
5.56k
    return Status::OK();
1083
5.56k
}
1084
1085
template <CallTag tag>
1086
5.35k
Status FunctionCall<tag>::call(Object<Global>* result) {
1087
5.35k
    DCHECK(result->uninitialized());
1088
5.35k
    Object<Local> local_result;
1089
5.35k
    local_result._obj = CallHelper<tag>::call_impl(_env, _base, _method, _args.data());
1090
5.35k
    RETURN_ERROR_IF_EXC(this->_env);
1091
5.35k
    return local_to_global_ref(_env, local_result, result);
1092
5.35k
}
1093
1094
template <CallTag tag>
1095
77
Status NonvirtualFunctionCall<tag>::call(Object<Local>* result) {
1096
77
    DCHECK(result->uninitialized());
1097
77
    result->_obj = CallHelper<tag>::call_impl(this->_env, this->_base, _cls, this->_method,
1098
77
                                              this->_args.data());
1099
77
    RETURN_ERROR_IF_EXC(this->_env);
1100
77
    return Status::OK();
1101
77
}
1102
1103
template <RefType Ref>
1104
template <RefType R>
1105
NonvirtualFunctionCall<NonvirtualObjectMethod> Object<Ref>::call_nonvirtual_object_method(
1106
76
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1107
76
    DCHECK(!this->uninitialized());
1108
76
    DCHECK(!method_id.uninitialized());
1109
1110
76
    return NonvirtualFunctionCall<NonvirtualObjectMethod>::instance(env, _obj, (jclass)clazz._obj,
1111
76
                                                                    method_id._id);
1112
76
}
1113
1114
template <RefType Ref>
1115
template <RefType R>
1116
NonvirtualFunctionCall<NonvirtualVoidMethod> Object<Ref>::call_nonvirtual_void_method(
1117
5.91k
        JNIEnv* env, const Class<R>& clazz, MethodId method_id) const {
1118
5.91k
    DCHECK(!this->uninitialized());
1119
5.91k
    DCHECK(!method_id.uninitialized());
1120
5.91k
    return NonvirtualFunctionCall<NonvirtualVoidMethod>::instance(env, _obj, (jclass)clazz._obj,
1121
5.91k
                                                                  method_id._id);
1122
5.91k
}
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.45k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
5.45k
        return Class<Ref>::get_object_class(env, object, result);
1165
5.45k
    }
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.45k
    static Status get_object_class(JNIEnv* env, const Object<R>& object, Class<Ref>* result) {
1164
5.45k
        return Class<Ref>::get_object_class(env, object, result);
1165
5.45k
    }
1166
1167
    template <RefType Ref>
1168
    static Status WriteBufferToByteArray(JNIEnv* env, const jbyte* buffer, jint size,
1169
77
                                         Array<Ref>* serialized_msg) {
1170
77
        if constexpr (Ref == Local) {
1171
77
            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
77
    }
1180
1181
    template <class T, RefType Ref>
1182
5.47k
    static Status SerializeThriftMsg(JNIEnv* env, T* msg, Array<Ref>* serialized_msg) {
1183
5.47k
        if constexpr (Ref == Local) {
1184
5.47k
            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.47k
    }
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.7k
        for (const auto& it : map) {
1202
16.7k
            LocalString key;
1203
16.7k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.first, &key));
1204
1205
16.7k
            LocalString value;
1206
16.7k
            RETURN_IF_ERROR(String<Local>::new_string_utf8(env, it.second, &value));
1207
1208
16.7k
            LocalObject result;
1209
16.7k
            RETURN_IF_ERROR(hashmap_object->call_object_method(env, hashmap_put)
1210
16.7k
                                    .with_arg(key)
1211
16.7k
                                    .with_arg(value)
1212
16.7k
                                    .call());
1213
16.7k
        }
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