mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 14:11:36 +00:00
272 lines
8.9 KiB
C++
272 lines
8.9 KiB
C++
/*
|
|
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
*/
|
|
|
|
#include "precompiled.hpp"
|
|
#include "classfile/vmClasses.hpp"
|
|
#include "compiler/oopMap.inline.hpp"
|
|
#include "gc/shared/gc_globals.hpp"
|
|
#include "memory/oopFactory.hpp"
|
|
#include "memory/resourceArea.hpp"
|
|
#include "oops/instanceStackChunkKlass.inline.hpp"
|
|
#include "oops/stackChunkOop.inline.hpp"
|
|
#include "runtime/continuation.hpp"
|
|
#include "runtime/continuationJavaClasses.inline.hpp"
|
|
#include "runtime/frame.hpp"
|
|
#include "runtime/handles.hpp"
|
|
#include "runtime/registerMap.hpp"
|
|
#include "runtime/smallRegisterMap.inline.hpp"
|
|
#include "runtime/stackChunkFrameStream.inline.hpp"
|
|
#include "utilities/devirtualizer.inline.hpp"
|
|
#include "utilities/globalDefinitions.hpp"
|
|
#include "utilities/macros.hpp"
|
|
#include "utilities/ostream.hpp"
|
|
|
|
int InstanceStackChunkKlass::_offset_of_stack = 0;
|
|
|
|
#if INCLUDE_CDS
|
|
void InstanceStackChunkKlass::serialize_offsets(SerializeClosure* f) {
|
|
f->do_u4((u4*)&_offset_of_stack);
|
|
}
|
|
#endif
|
|
|
|
InstanceStackChunkKlass::InstanceStackChunkKlass(const ClassFileParser& parser)
|
|
: InstanceKlass(parser, Kind) {
|
|
// Change the layout_helper to use the slow path because StackChunkOops are
|
|
// variable sized InstanceOops.
|
|
const jint lh = Klass::instance_layout_helper(size_helper(), true);
|
|
set_layout_helper(lh);
|
|
}
|
|
|
|
size_t InstanceStackChunkKlass::oop_size(oop obj) const {
|
|
return instance_size(jdk_internal_vm_StackChunk::size(obj));
|
|
}
|
|
|
|
#ifndef PRODUCT
|
|
void InstanceStackChunkKlass::oop_print_on(oop obj, outputStream* st) {
|
|
print_chunk(stackChunkOopDesc::cast(obj), false, st);
|
|
}
|
|
#endif
|
|
|
|
template<typename OopClosureType>
|
|
class StackChunkOopIterateFilterClosure: public OopClosure {
|
|
private:
|
|
OopClosureType* const _closure;
|
|
MemRegion _bound;
|
|
|
|
public:
|
|
|
|
StackChunkOopIterateFilterClosure(OopClosureType* closure, MemRegion bound)
|
|
: _closure(closure),
|
|
_bound(bound) {}
|
|
|
|
virtual void do_oop(oop* p) override { do_oop_work(p); }
|
|
virtual void do_oop(narrowOop* p) override { do_oop_work(p); }
|
|
|
|
template <typename T>
|
|
void do_oop_work(T* p) {
|
|
if (_bound.contains(p)) {
|
|
Devirtualizer::do_oop(_closure, p);
|
|
}
|
|
}
|
|
};
|
|
|
|
class DoMethodsStackChunkFrameClosure {
|
|
OopIterateClosure* _closure;
|
|
|
|
public:
|
|
DoMethodsStackChunkFrameClosure(OopIterateClosure* cl) : _closure(cl) {}
|
|
|
|
template <ChunkFrames frame_kind, typename RegisterMapT>
|
|
bool do_frame(const StackChunkFrameStream<frame_kind>& f, const RegisterMapT* map) {
|
|
if (f.is_interpreted()) {
|
|
Method* m = f.to_frame().interpreter_frame_method();
|
|
_closure->do_method(m);
|
|
} else if (f.is_compiled()) {
|
|
nmethod* nm = f.cb()->as_nmethod();
|
|
// The do_nmethod function takes care of having the right synchronization
|
|
// when keeping the nmethod alive during concurrent execution.
|
|
_closure->do_nmethod(nm);
|
|
// There is no need to mark the Method, as class redefinition will walk the
|
|
// CodeCache, noting their Methods
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void InstanceStackChunkKlass::do_methods(stackChunkOop chunk, OopIterateClosure* cl) {
|
|
DoMethodsStackChunkFrameClosure closure(cl);
|
|
chunk->iterate_stack(&closure);
|
|
}
|
|
|
|
class OopIterateStackChunkFrameClosure {
|
|
OopIterateClosure* const _closure;
|
|
MemRegion _bound;
|
|
const bool _do_metadata;
|
|
|
|
public:
|
|
OopIterateStackChunkFrameClosure(OopIterateClosure* closure, MemRegion mr)
|
|
: _closure(closure),
|
|
_bound(mr),
|
|
_do_metadata(_closure->do_metadata()) {
|
|
assert(_closure != nullptr, "must be set");
|
|
}
|
|
|
|
template <ChunkFrames frame_kind, typename RegisterMapT>
|
|
bool do_frame(const StackChunkFrameStream<frame_kind>& f, const RegisterMapT* map) {
|
|
if (_do_metadata) {
|
|
DoMethodsStackChunkFrameClosure(_closure).do_frame(f, map);
|
|
}
|
|
|
|
StackChunkOopIterateFilterClosure<OopIterateClosure> cl(_closure, _bound);
|
|
f.iterate_oops(&cl, map);
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void InstanceStackChunkKlass::oop_oop_iterate_stack_slow(stackChunkOop chunk, OopIterateClosure* closure, MemRegion mr) {
|
|
if (UseZGC || UseShenandoahGC) {
|
|
// An OopClosure could apply barriers to a stack chunk. The side effects
|
|
// of the load barriers could destroy derived pointers, which must be
|
|
// processed before their base oop is processed. So we force processing
|
|
// of derived pointers before applying the closures.
|
|
chunk->relativize_derived_pointers_concurrently();
|
|
}
|
|
OopIterateStackChunkFrameClosure frame_closure(closure, mr);
|
|
chunk->iterate_stack(&frame_closure);
|
|
}
|
|
|
|
#ifdef ASSERT
|
|
|
|
class DescribeStackChunkClosure {
|
|
stackChunkOop _chunk;
|
|
FrameValues _values;
|
|
RegisterMap _map;
|
|
int _frame_no;
|
|
|
|
public:
|
|
DescribeStackChunkClosure(stackChunkOop chunk)
|
|
: _chunk(chunk),
|
|
_map((JavaThread*)nullptr,
|
|
RegisterMap::UpdateMap::include,
|
|
RegisterMap::ProcessFrames::skip,
|
|
RegisterMap::WalkContinuation::include),
|
|
_frame_no(0) {
|
|
_map.set_include_argument_oops(false);
|
|
}
|
|
|
|
const RegisterMap* get_map(const RegisterMap* map, intptr_t* sp) { return map; }
|
|
const RegisterMap* get_map(const SmallRegisterMap* map, intptr_t* sp) { return map->copy_to_RegisterMap(&_map, sp); }
|
|
|
|
template <ChunkFrames frame_kind, typename RegisterMapT>
|
|
bool do_frame(const StackChunkFrameStream<frame_kind>& f, const RegisterMapT* map) {
|
|
ResetNoHandleMark rnhm;
|
|
HandleMark hm(Thread::current());
|
|
|
|
frame fr = f.to_frame();
|
|
fr.describe(_values, _frame_no++, get_map(map, f.sp()));
|
|
return true;
|
|
}
|
|
|
|
void describe_chunk() {
|
|
// _values.describe(-1, _chunk->start_address(), "CHUNK START");
|
|
_values.describe(-1, _chunk->sp_address(), "CHUNK SP");
|
|
_values.describe(-1, _chunk->bottom_address() - 1, "CHUNK ARGS");
|
|
_values.describe(-1, _chunk->end_address() - 1, "CHUNK END");
|
|
}
|
|
|
|
void print_on(outputStream* out) {
|
|
if (_frame_no > 0) {
|
|
describe_chunk();
|
|
_values.print_on(_chunk, out);
|
|
} else {
|
|
out->print_cr(" EMPTY");
|
|
}
|
|
}
|
|
};
|
|
#endif
|
|
|
|
class PrintStackChunkClosure {
|
|
outputStream* _st;
|
|
|
|
public:
|
|
PrintStackChunkClosure(outputStream* st) : _st(st) {}
|
|
|
|
template <ChunkFrames frame_kind, typename RegisterMapT>
|
|
bool do_frame(const StackChunkFrameStream<frame_kind>& fs, const RegisterMapT* map) {
|
|
frame f = fs.to_frame();
|
|
_st->print_cr("-- frame sp: " PTR_FORMAT " interpreted: %d size: %d argsize: %d",
|
|
p2i(fs.sp()), fs.is_interpreted(), f.frame_size(),
|
|
fs.is_interpreted() ? 0 : f.compiled_frame_stack_argsize());
|
|
#ifdef ASSERT
|
|
f.print_value_on(_st, nullptr);
|
|
#else
|
|
f.print_on(_st);
|
|
#endif
|
|
const ImmutableOopMap* oopmap = fs.oopmap();
|
|
if (oopmap != nullptr) {
|
|
oopmap->print_on(_st);
|
|
_st->cr();
|
|
}
|
|
return true;
|
|
}
|
|
};
|
|
|
|
void InstanceStackChunkKlass::print_chunk(const stackChunkOop c, bool verbose, outputStream* st) {
|
|
if (c == nullptr) {
|
|
st->print_cr("CHUNK NULL");
|
|
return;
|
|
}
|
|
|
|
st->print_cr("CHUNK " PTR_FORMAT " " PTR_FORMAT " - " PTR_FORMAT " :: " INTPTR_FORMAT,
|
|
p2i(c), p2i(c->start_address()), p2i(c->end_address()), c->identity_hash());
|
|
st->print_cr(" barriers: %d gc_mode: %d bitmap: %d parent: " PTR_FORMAT,
|
|
c->requires_barriers(), c->is_gc_mode(), c->has_bitmap(), p2i(c->parent()));
|
|
st->print_cr(" flags mixed: %d", c->has_mixed_frames());
|
|
st->print_cr(" size: %d argsize: %d max_size: %d sp: %d pc: " PTR_FORMAT,
|
|
c->stack_size(), c->argsize(), c->max_thawing_size(), c->sp(), p2i(c->pc()));
|
|
|
|
if (verbose) {
|
|
st->cr();
|
|
st->print_cr("------ chunk frames end: " PTR_FORMAT, p2i(c->bottom_address()));
|
|
PrintStackChunkClosure closure(st);
|
|
c->iterate_stack(&closure);
|
|
st->print_cr("------");
|
|
|
|
#ifdef ASSERT
|
|
ResourceMark rm;
|
|
DescribeStackChunkClosure describe(c);
|
|
c->iterate_stack(&describe);
|
|
describe.print_on(st);
|
|
st->print_cr("======");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void InstanceStackChunkKlass::init_offset_of_stack() {
|
|
// Cache the offset of the static fields in the Class instance
|
|
assert(_offset_of_stack == 0, "once");
|
|
_offset_of_stack = cast(vmClasses::StackChunk_klass())->size_helper() << LogHeapWordSize;
|
|
}
|