jdk

Форк
0
/
jniHandles.cpp 
527 строк · 17.9 Кб
1
/*
2
 * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
 *
5
 * This code is free software; you can redistribute it and/or modify it
6
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.
8
 *
9
 * This code is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 * version 2 for more details (a copy is included in the LICENSE file that
13
 * accompanied this code).
14
 *
15
 * You should have received a copy of the GNU General Public License version
16
 * 2 along with this work; if not, write to the Free Software Foundation,
17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
 * or visit www.oracle.com if you need additional information or have any
21
 * questions.
22
 *
23
 */
24

25
#include "precompiled.hpp"
26
#include "gc/shared/collectedHeap.hpp"
27
#include "gc/shared/oopStorage.inline.hpp"
28
#include "gc/shared/oopStorageSet.hpp"
29
#include "logging/log.hpp"
30
#include "memory/iterator.hpp"
31
#include "memory/universe.hpp"
32
#include "oops/access.inline.hpp"
33
#include "oops/oop.inline.hpp"
34
#include "runtime/handles.inline.hpp"
35
#include "runtime/javaThread.inline.hpp"
36
#include "runtime/jniHandles.inline.hpp"
37
#include "runtime/mutexLocker.hpp"
38
#include "utilities/align.hpp"
39
#include "utilities/debug.hpp"
40

41
OopStorage* JNIHandles::global_handles() {
42
  return _global_handles;
43
}
44

45
OopStorage* JNIHandles::weak_global_handles() {
46
  return _weak_global_handles;
47
}
48

49
// Serviceability agent support.
50
OopStorage* JNIHandles::_global_handles = nullptr;
51
OopStorage* JNIHandles::_weak_global_handles = nullptr;
52

53
void jni_handles_init() {
54
  JNIHandles::_global_handles = OopStorageSet::create_strong("JNI Global", mtInternal);
55
  JNIHandles::_weak_global_handles = OopStorageSet::create_weak("JNI Weak", mtInternal);
56
}
57

58
jobject JNIHandles::make_local(oop obj) {
59
  return make_local(JavaThread::current(), obj);
60
}
61

62
// Used by NewLocalRef which requires null on out-of-memory
63
jobject JNIHandles::make_local(JavaThread* thread, oop obj, AllocFailType alloc_failmode) {
64
  if (obj == nullptr) {
65
    return nullptr;                // ignore null handles
66
  } else {
67
    assert(oopDesc::is_oop(obj), "not an oop");
68
    assert(!current_thread_in_native(), "must not be in native");
69
    STATIC_ASSERT(TypeTag::local == 0);
70
    return thread->active_handles()->allocate_handle(thread, obj, alloc_failmode);
71
  }
72
}
73

74
static void report_handle_allocation_failure(AllocFailType alloc_failmode,
75
                                             const char* handle_kind) {
76
  if (alloc_failmode == AllocFailStrategy::EXIT_OOM) {
77
    // Fake size value, since we don't know the min allocation size here.
78
    vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR,
79
                          "Cannot create %s JNI handle", handle_kind);
80
  } else {
81
    assert(alloc_failmode == AllocFailStrategy::RETURN_NULL, "invariant");
82
  }
83
}
84

85
jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) {
86
  assert(!Universe::heap()->is_stw_gc_active(), "can't extend the root set during GC pause");
87
  assert(!current_thread_in_native(), "must not be in native");
88
  jobject res = nullptr;
89
  if (!obj.is_null()) {
90
    // ignore null handles
91
    assert(oopDesc::is_oop(obj()), "not an oop");
92
    oop* ptr = global_handles()->allocate();
93
    // Return null on allocation failure.
94
    if (ptr != nullptr) {
95
      assert(NativeAccess<AS_NO_KEEPALIVE>::oop_load(ptr) == oop(nullptr), "invariant");
96
      NativeAccess<>::oop_store(ptr, obj());
97
      char* tptr = reinterpret_cast<char*>(ptr) + TypeTag::global;
98
      res = reinterpret_cast<jobject>(tptr);
99
    } else {
100
      report_handle_allocation_failure(alloc_failmode, "global");
101
    }
102
  }
103

104
  return res;
105
}
106

107
jweak JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) {
108
  assert(!Universe::heap()->is_stw_gc_active(), "can't extend the root set during GC pause");
109
  assert(!current_thread_in_native(), "must not be in native");
110
  jweak res = nullptr;
111
  if (!obj.is_null()) {
112
    // ignore null handles
113
    assert(oopDesc::is_oop(obj()), "not an oop");
114
    oop* ptr = weak_global_handles()->allocate();
115
    // Return nullptr on allocation failure.
116
    if (ptr != nullptr) {
117
      assert(NativeAccess<AS_NO_KEEPALIVE>::oop_load(ptr) == oop(nullptr), "invariant");
118
      NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(ptr, obj());
119
      char* tptr = reinterpret_cast<char*>(ptr) + TypeTag::weak_global;
120
      res = reinterpret_cast<jweak>(tptr);
121
    } else {
122
      report_handle_allocation_failure(alloc_failmode, "weak global");
123
    }
124
  }
125
  return res;
126
}
127

128
// Resolve some erroneous cases to null, rather than treating them as
129
// possibly unchecked errors.  In particular, deleted handles are
130
// treated as null (though a deleted and later reallocated handle
131
// isn't detected).
132
oop JNIHandles::resolve_external_guard(jobject handle) {
133
  oop result = nullptr;
134
  if (handle != nullptr) {
135
    result = resolve_impl<DECORATORS_NONE, true /* external_guard */>(handle);
136
  }
137
  return result;
138
}
139

140
bool JNIHandles::is_weak_global_cleared(jweak handle) {
141
  assert(handle != nullptr, "precondition");
142
  oop* oop_ptr = weak_global_ptr(handle);
143
  oop value = NativeAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(oop_ptr);
144
  return value == nullptr;
145
}
146

147
void JNIHandles::destroy_global(jobject handle) {
148
  if (handle != nullptr) {
149
    oop* oop_ptr = global_ptr(handle);
150
    NativeAccess<>::oop_store(oop_ptr, (oop)nullptr);
151
    global_handles()->release(oop_ptr);
152
  }
153
}
154

155

156
void JNIHandles::destroy_weak_global(jweak handle) {
157
  if (handle != nullptr) {
158
    oop* oop_ptr = weak_global_ptr(handle);
159
    NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_ptr, (oop)nullptr);
160
    weak_global_handles()->release(oop_ptr);
161
  }
162
}
163

164

165
void JNIHandles::oops_do(OopClosure* f) {
166
  global_handles()->oops_do(f);
167
}
168

169

170
void JNIHandles::weak_oops_do(OopClosure* f) {
171
  weak_global_handles()->weak_oops_do(f);
172
}
173

174
bool JNIHandles::is_global_storage(const OopStorage* storage) {
175
  return _global_handles == storage;
176
}
177

178
inline bool is_storage_handle(const OopStorage* storage, const oop* ptr) {
179
  return storage->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY;
180
}
181

182

183
jobjectRefType JNIHandles::handle_type(JavaThread* thread, jobject handle) {
184
  assert(handle != nullptr, "precondition");
185
  jobjectRefType result = JNIInvalidRefType;
186
  if (is_weak_global_tagged(handle)) {
187
    if (is_storage_handle(weak_global_handles(), weak_global_ptr(handle))) {
188
      result = JNIWeakGlobalRefType;
189
    }
190
  } else if (is_global_tagged(handle)) {
191
    switch (global_handles()->allocation_status(global_ptr(handle))) {
192
    case OopStorage::ALLOCATED_ENTRY:
193
      result = JNIGlobalRefType;
194
      break;
195

196
    case OopStorage::UNALLOCATED_ENTRY:
197
      break;                    // Invalid global handle
198

199
    default:
200
      ShouldNotReachHere();
201
    }
202
  } else if (is_local_handle(thread, handle) || is_frame_handle(thread, handle)) {
203
    // Not in global storage.  Might be a local handle.
204
    result = JNILocalRefType;
205
  }
206
  return result;
207
}
208

209

210
bool JNIHandles::is_local_handle(JavaThread* thread, jobject handle) {
211
  assert(handle != nullptr, "precondition");
212
  JNIHandleBlock* block = thread->active_handles();
213

214
  // Look back past possible native calls to jni_PushLocalFrame.
215
  while (block != nullptr) {
216
    if (block->chain_contains(handle)) {
217
      return true;
218
    }
219
    block = block->pop_frame_link();
220
  }
221
  return false;
222
}
223

224

225
// Determine if the handle is somewhere in the current thread's stack.
226
// We easily can't isolate any particular stack frame the handle might
227
// come from, so we'll check the whole stack.
228

229
bool JNIHandles::is_frame_handle(JavaThread* thr, jobject handle) {
230
  assert(handle != nullptr, "precondition");
231
  // If there is no java frame, then this must be top level code, such
232
  // as the java command executable, in which case, this type of handle
233
  // is not permitted.
234
  return (thr->has_last_Java_frame() &&
235
          thr->is_in_stack_range_incl((address)handle, (address)thr->last_Java_sp()));
236
}
237

238

239
bool JNIHandles::is_global_handle(jobject handle) {
240
  assert(handle != nullptr, "precondition");
241
  return is_global_tagged(handle) && is_storage_handle(global_handles(), global_ptr(handle));
242
}
243

244

245
bool JNIHandles::is_weak_global_handle(jobject handle) {
246
  assert(handle != nullptr, "precondition");
247
  return is_weak_global_tagged(handle) && is_storage_handle(weak_global_handles(), weak_global_ptr(handle));
248
}
249

250
// We assume this is called at a safepoint: no lock is needed.
251
void JNIHandles::print_on(outputStream* st) {
252
  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
253

254
  st->print_cr("JNI global refs: " SIZE_FORMAT ", weak refs: " SIZE_FORMAT,
255
               global_handles()->allocation_count(),
256
               weak_global_handles()->allocation_count());
257
  st->cr();
258
  st->flush();
259
}
260

261
void JNIHandles::print() { print_on(tty); }
262

263
class VerifyJNIHandles: public OopClosure {
264
public:
265
  virtual void do_oop(oop* root) {
266
    guarantee(oopDesc::is_oop_or_null(RawAccess<>::oop_load(root)), "Invalid oop");
267
  }
268
  virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); }
269
};
270

271
void JNIHandles::verify() {
272
  VerifyJNIHandles verify_handle;
273

274
  oops_do(&verify_handle);
275
  weak_oops_do(&verify_handle);
276
}
277

278
// This method is implemented here to avoid circular includes between
279
// jniHandles.hpp and thread.hpp.
280
bool JNIHandles::current_thread_in_native() {
281
  Thread* thread = Thread::current();
282
  return (thread->is_Java_thread() &&
283
          JavaThread::cast(thread)->thread_state() == _thread_in_native);
284
}
285

286
int JNIHandleBlock::_blocks_allocated = 0;
287

288
static inline bool is_tagged_free_list(uintptr_t value) {
289
  return (value & 1u) != 0;
290
}
291

292
static inline uintptr_t tag_free_list(uintptr_t value) {
293
  return value | 1u;
294
}
295

296
static inline uintptr_t untag_free_list(uintptr_t value) {
297
  return value & ~(uintptr_t)1u;
298
}
299

300
// There is a freelist of handles running through the JNIHandleBlock
301
// with a tagged next pointer, distinguishing these next pointers from
302
// oops. The freelist handling currently relies on the size of oops
303
// being the same as a native pointer. If this ever changes, then
304
// this freelist handling must change too.
305
STATIC_ASSERT(sizeof(oop) == sizeof(uintptr_t));
306

307
#ifdef ASSERT
308
void JNIHandleBlock::zap() {
309
  // Zap block values
310
  _top = 0;
311
  for (int index = 0; index < block_size_in_oops; index++) {
312
    // NOT using Access here; just bare clobbering to null, since the
313
    // block no longer contains valid oops.
314
    _handles[index] = 0;
315
  }
316
}
317
#endif // ASSERT
318

319
JNIHandleBlock* JNIHandleBlock::allocate_block(JavaThread* thread, AllocFailType alloc_failmode)  {
320
  // The VM thread can allocate a handle block in behalf of another thread during a safepoint.
321
  assert(thread == nullptr || thread == Thread::current() || SafepointSynchronize::is_at_safepoint(),
322
         "sanity check");
323
  JNIHandleBlock* block;
324
  // Check the thread-local free list for a block so we don't
325
  // have to acquire a mutex.
326
  if (thread != nullptr && thread->free_handle_block() != nullptr) {
327
    block = thread->free_handle_block();
328
    thread->set_free_handle_block(block->_next);
329
  } else {
330
    // Allocate new block
331
    if (alloc_failmode == AllocFailStrategy::RETURN_NULL) {
332
      block = new (std::nothrow) JNIHandleBlock();
333
      if (block == nullptr) {
334
        return nullptr;
335
      }
336
    } else {
337
      block = new JNIHandleBlock();
338
    }
339
    Atomic::inc(&_blocks_allocated);
340
    block->zap();
341
  }
342
  block->_top = 0;
343
  block->_next = nullptr;
344
  block->_pop_frame_link = nullptr;
345
  // _last, _free_list & _allocate_before_rebuild initialized in allocate_handle
346
  debug_only(block->_last = nullptr);
347
  debug_only(block->_free_list = nullptr);
348
  debug_only(block->_allocate_before_rebuild = -1);
349
  return block;
350
}
351

352

353
void JNIHandleBlock::release_block(JNIHandleBlock* block, JavaThread* thread) {
354
  assert(thread == nullptr || thread == Thread::current(), "sanity check");
355
  JNIHandleBlock* pop_frame_link = block->pop_frame_link();
356
  // Put returned block at the beginning of the thread-local free list.
357
  // Note that if thread == nullptr, we use it as an implicit argument that
358
  // we _don't_ want the block to be kept on the free_handle_block.
359
  // See for instance JavaThread::exit().
360
  if (thread != nullptr ) {
361
    block->zap();
362
    JNIHandleBlock* freelist = thread->free_handle_block();
363
    block->_pop_frame_link = nullptr;
364
    thread->set_free_handle_block(block);
365

366
    // Add original freelist to end of chain
367
    if ( freelist != nullptr ) {
368
      while ( block->_next != nullptr ) block = block->_next;
369
      block->_next = freelist;
370
    }
371
    block = nullptr;
372
  } else {
373
    DEBUG_ONLY(block->set_pop_frame_link(nullptr));
374
    while (block != nullptr) {
375
      JNIHandleBlock* next = block->_next;
376
      Atomic::dec(&_blocks_allocated);
377
      assert(block->pop_frame_link() == nullptr, "pop_frame_link should be null");
378
      delete block;
379
      block = next;
380
    }
381
  }
382
  if (pop_frame_link != nullptr) {
383
    // As a sanity check we release blocks pointed to by the pop_frame_link.
384
    // This should never happen (only if PopLocalFrame is not called the
385
    // correct number of times).
386
    release_block(pop_frame_link, thread);
387
  }
388
}
389

390

391
void JNIHandleBlock::oops_do(OopClosure* f) {
392
  JNIHandleBlock* current_chain = this;
393
  // Iterate over chain of blocks, followed by chains linked through the
394
  // pop frame links.
395
  while (current_chain != nullptr) {
396
    for (JNIHandleBlock* current = current_chain; current != nullptr;
397
         current = current->_next) {
398
      assert(current == current_chain || current->pop_frame_link() == nullptr,
399
        "only blocks first in chain should have pop frame link set");
400
      for (int index = 0; index < current->_top; index++) {
401
        uintptr_t* addr = &(current->_handles)[index];
402
        uintptr_t value = *addr;
403
        // traverse heap pointers only, not deleted handles or free list
404
        // pointers
405
        if (value != 0 && !is_tagged_free_list(value)) {
406
          oop* root = (oop*)addr;
407
          f->do_oop(root);
408
        }
409
      }
410
      // the next handle block is valid only if current block is full
411
      if (current->_top < block_size_in_oops) {
412
        break;
413
      }
414
    }
415
    current_chain = current_chain->pop_frame_link();
416
  }
417
}
418

419

420
jobject JNIHandleBlock::allocate_handle(JavaThread* caller, oop obj, AllocFailType alloc_failmode) {
421
  assert(Universe::heap()->is_in(obj), "sanity check");
422
  if (_top == 0) {
423
    // This is the first allocation or the initial block got zapped when
424
    // entering a native function. If we have any following blocks they are
425
    // not valid anymore.
426
    for (JNIHandleBlock* current = _next; current != nullptr;
427
         current = current->_next) {
428
      assert(current->_last == nullptr, "only first block should have _last set");
429
      assert(current->_free_list == nullptr,
430
             "only first block should have _free_list set");
431
      if (current->_top == 0) {
432
        // All blocks after the first clear trailing block are already cleared.
433
#ifdef ASSERT
434
        for (current = current->_next; current != nullptr; current = current->_next) {
435
          assert(current->_top == 0, "trailing blocks must already be cleared");
436
        }
437
#endif
438
        break;
439
      }
440
      current->_top = 0;
441
      current->zap();
442
    }
443
    // Clear initial block
444
    _free_list = nullptr;
445
    _allocate_before_rebuild = 0;
446
    _last = this;
447
    zap();
448
  }
449

450
  // Try last block
451
  if (_last->_top < block_size_in_oops) {
452
    oop* handle = (oop*)&(_last->_handles)[_last->_top++];
453
    *handle = obj;
454
    return (jobject) handle;
455
  }
456

457
  // Try free list
458
  if (_free_list != nullptr) {
459
    oop* handle = (oop*)_free_list;
460
    _free_list = (uintptr_t*) untag_free_list(*_free_list);
461
    *handle = obj;
462
    return (jobject) handle;
463
  }
464
  // Check if unused block follow last
465
  if (_last->_next != nullptr) {
466
    // update last and retry
467
    _last = _last->_next;
468
    return allocate_handle(caller, obj, alloc_failmode);
469
  }
470

471
  // No space available, we have to rebuild free list or expand
472
  if (_allocate_before_rebuild == 0) {
473
      rebuild_free_list();        // updates _allocate_before_rebuild counter
474
  } else {
475
    _last->_next = JNIHandleBlock::allocate_block(caller, alloc_failmode);
476
    if (_last->_next == nullptr) {
477
      return nullptr;
478
    }
479
    _last = _last->_next;
480
    _allocate_before_rebuild--;
481
  }
482
  return allocate_handle(caller, obj, alloc_failmode);  // retry
483
}
484

485
void JNIHandleBlock::rebuild_free_list() {
486
  assert(_allocate_before_rebuild == 0 && _free_list == nullptr, "just checking");
487
  int free = 0;
488
  int blocks = 0;
489
  for (JNIHandleBlock* current = this; current != nullptr; current = current->_next) {
490
    for (int index = 0; index < current->_top; index++) {
491
      uintptr_t* handle = &(current->_handles)[index];
492
      if (*handle == 0) {
493
        // this handle was cleared out by a delete call, reuse it
494
        *handle = _free_list == nullptr ? 0 : tag_free_list((uintptr_t)_free_list);
495
        _free_list = handle;
496
        free++;
497
      }
498
    }
499
    // we should not rebuild free list if there are unused handles at the end
500
    assert(current->_top == block_size_in_oops, "just checking");
501
    blocks++;
502
  }
503
  // Heuristic: if more than half of the handles are free we rebuild next time
504
  // as well, otherwise we append a corresponding number of new blocks before
505
  // attempting a free list rebuild again.
506
  int total = blocks * block_size_in_oops;
507
  int extra = total - 2*free;
508
  if (extra > 0) {
509
    // Not as many free handles as we would like - compute number of new blocks to append
510
    _allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops;
511
  }
512
}
513

514

515
bool JNIHandleBlock::contains(jobject handle) const {
516
  return ((jobject)&_handles[0] <= handle && handle<(jobject)&_handles[_top]);
517
}
518

519

520
bool JNIHandleBlock::chain_contains(jobject handle) const {
521
  for (JNIHandleBlock* current = (JNIHandleBlock*) this; current != nullptr; current = current->_next) {
522
    if (current->contains(handle)) {
523
      return true;
524
    }
525
  }
526
  return false;
527
}
528

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.