Coverage Report

Created: 2026-09-17 10:05

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