Skip to content
Permalink
Browse files
Lazify chunk frame fixing and simplify thaw
  • Loading branch information
pron committed Mar 31, 2021
1 parent f9db7ee commit 2b984299909c2a070fb8346fd5f36eccc96d9b08
Show file tree
Hide file tree
Showing 17 changed files with 316 additions and 425 deletions.
@@ -301,7 +301,8 @@ template<typename FKind> frame Thaw<ConfigT>::new_frame(const frame& hf, intptr_
return frame(vsp, vsp, fp, hf.pc());
} else {
assert (hf.cb() != nullptr && hf.oop_map() != nullptr, "");
return frame(vsp, vsp, hf.fp(), hf.pc(), hf.cb(), hf.oop_map()); // TODO PERF : this computes deopt state; is it necessary?
intptr_t* fp = *(intptr_t**)(hf.sp() - frame::sender_sp_offset); // we need to re-read fp because it may be an oop and we might have fixed the frame.
return frame(vsp, vsp, fp, hf.pc(), hf.cb(), hf.oop_map()); // TODO PERF : this computes deopt state; is it necessary?
}
}

@@ -596,10 +596,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
} else if (is_compiled_frame()) {
address ret_pc = *(address*)(real_fp() - return_addr_offset);
values.describe(frame_no, real_fp() - return_addr_offset, Continuation::is_return_barrier_entry(ret_pc) ? "return address (return barrier)" : "return address");
values.describe(-1, real_fp() - sender_sp_offset, "saved fp", 2);
#ifdef AMD64
} else if (is_entry_frame()) {
// This could be more descriptive if we use the enum in
@@ -610,6 +606,18 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
}
#endif // AMD64
}

if (is_java_frame()) {
address ret_pc = *(address*)(real_fp() - return_addr_offset);
values.describe(frame_no, real_fp() - return_addr_offset, Continuation::is_return_barrier_entry(ret_pc) ? "return address (return barrier)" : "return address");
values.describe(-1, real_fp() - sender_sp_offset, "saved fp", 2);
}
}

void frame::describe_top_pd(FrameValues& values) {
address ret_pc_callee = *(address*)(sp() - return_addr_offset);
values.describe(-1, sp() - return_addr_offset, Continuation::is_return_barrier_entry(ret_pc_callee) ? "return address (return barrier)" : "return address");
values.describe(-1, sp() - sender_sp_offset, "saved fp", 2);
}
#endif // !PRODUCT

@@ -122,12 +122,6 @@
<Field type="ulong" name="id" label="Continuation ID" />
</Event>

<Event name="ContinuationSquash" experimental="true" category="Java Virtual Machine" label="Continuation Squash" thread="true" stackTrace="false" startTime="false">
<Field type="ulong" name="id" label="Continuation ID" />
<Field type="ushort" name="numChunks" label="Chunks" />
<Field type="ushort" name="numFrames" label="Frames" />
</Event>

<Event name="ContinuationThawYoung" experimental="true" category="Java Virtual Machine" label="Continuation Thaw Young" thread="true" stackTrace="false" startTime="false">
<Field type="ulong" name="id" label="Continuation ID" />
<Field type="boolean" name="full" label="Full" />
@@ -138,12 +132,6 @@
<Field type="ulong" name="id" label="Continuation ID" />
</Event>

<Event name="ContinuationFix" experimental="true" category="Java Virtual Machine" label="Continuation Fix" thread="true" stackTrace="false" startTime="false">
<Field type="ulong" name="id" label="Continuation ID" />
<Field type="ushort" name="numFrames" label="Frames" />
<Field type="ushort" name="numOops" label="Oops" />
</Event>

<Event name="ReservedStackActivation" category="Java Virtual Machine, Runtime" label="Reserved Stack Activation"
description="Activation of Reserved Stack Area caused by stack overflow with ReservedStackAccess annotated method in call stack" thread="true" stackTrace="true"
startTime="false">
@@ -23,6 +23,7 @@
*/

#include "oops/instanceStackChunkKlass.hpp"
#include "gc/shared/gc_globals.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oopsHierarchy.hpp"
#include "precompiled.hpp"
@@ -51,17 +52,33 @@ bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames,
}
#endif

bool stackChunkOopDesc::should_fix() const {
const bool concurrent_gc = (UseZGC || UseShenandoahGC);
return
UseCompressedOops
? (concurrent_gc ? should_fix<narrowOop, true>()
: should_fix<narrowOop, false>())
: (concurrent_gc ? should_fix<oop, true>()
: should_fix<oop, false>());
}

// void stackChunkOopDesc::fix_frame_if_needed(const frame& fr, const RegisterMap* map) const {
// if (should_fix()) {
// InstanceStackChunkKlass::fix_frame<true, false>(StackChunkFrameStream<true>(const_cast<stackChunkOopDesc*>(this), derelativize(fr)), map);
// }
// }

frame stackChunkOopDesc::top_frame(RegisterMap* map) {
// tty->print_cr(">>> stackChunkOopDesc::top_frame this: %p map: %p map->chunk: %p", this, map, (stackChunkOopDesc*)map->stack_chunk()());
StackChunkFrameStream<true> fs(this);
frame f = fs.to_frame();

map->set_stack_chunk(this);
fs.initialize_register_map(map);
// if (map->update_map() && should_fix()) InstanceStackChunkKlass::fix_frame<true, false>(fs, map);

frame f = fs.to_frame();
relativize_frame(f);
f.set_frame_index(0);

f.set_frame_index(0);
return f;
}

@@ -77,6 +94,7 @@ frame stackChunkOopDesc::sender(const frame& f, RegisterMap* map) {
int index = f.frame_index();
StackChunkFrameStream<true> fs(this, derelativize(f));
fs.next(map);
// if (map->update_map() && should_fix()) InstanceStackChunkKlass::fix_frame<true, false>(fs, map);
if (!fs.is_done()) {
frame sender = fs.to_frame();
assert (is_usable_in_chunk(sender.unextended_sp()), "");
@@ -270,33 +288,6 @@ void InstanceStackChunkKlass::oop_print_on(oop obj, outputStream* st) {
}
#endif

template void InstanceStackChunkKlass::barriers_for_oops_in_chunk<false>(stackChunkOop chunk);
template void InstanceStackChunkKlass::barriers_for_oops_in_chunk<true> (stackChunkOop chunk);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<true, false>(const StackChunkFrameStream<true >& f, const RegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<true, true> (const StackChunkFrameStream<true >& f, const RegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<false, false>(const StackChunkFrameStream<false>& f, const RegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<false, true> (const StackChunkFrameStream<false>& f, const RegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<true, false>(const StackChunkFrameStream<true >& f, const SmallRegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<true, true> (const StackChunkFrameStream<true >& f, const SmallRegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<false, false>(const StackChunkFrameStream<false>& f, const SmallRegisterMap* map);
template void InstanceStackChunkKlass::barriers_for_oops_in_frame<false, true> (const StackChunkFrameStream<false>& f, const SmallRegisterMap* map);

template <bool store>
class BarriersIterateStackClosure {
public:
template <bool mixed, typename RegisterMapT>
bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map, MemRegion mr) {
InstanceStackChunkKlass::barriers_for_oops_in_frame<mixed, store>(f, map);
return true;
}
};

template <bool store>
void InstanceStackChunkKlass::barriers_for_oops_in_chunk(stackChunkOop chunk) {
BarriersIterateStackClosure<store> frame_closure;
chunk->iterate_stack(&frame_closure);
}

template<bool store>
class BarrierClosure: public OopClosure {
DEBUG_ONLY(intptr_t* _sp;)
@@ -311,95 +302,70 @@ class BarrierClosure: public OopClosure {
if (store) HeapAccess<>::oop_store(p, value);
log_develop_trace(jvmcont)("barriers_for_oops_in_frame narrow: %d p: " INTPTR_FORMAT " sp offset: %ld", sizeof(T) < sizeof(intptr_t), p2i(p), (intptr_t*)p - _sp);
}

// virtual void do_oop(oop* p) override { *(oop*)p = (oop)NativeAccess<>::oop_load((oop*)p); }
// virtual void do_oop(narrowOop* p) override { *(narrowOop*)p = CompressedOops::encode((oop)NativeAccess<>::oop_load((narrowOop*)p)); }
};


template <bool mixed, bool store, typename RegisterMapT>
void InstanceStackChunkKlass::barriers_for_oops_in_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map) {
void InstanceStackChunkKlass::fix_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map) {
// we need to invoke the write barriers so as not to miss oops in old chunks that haven't yet been concurrently scanned
if (f.is_done()) return;
log_develop_trace(jvmcont)("InstanceStackChunkKlass::fix_frame sp: " INTPTR_FORMAT " pc: " INTPTR_FORMAT, p2i(f.sp()), p2i(f.pc()));

if (mixed) f.handle_deopted(); // we could freeze deopted frames in slow mode.
if (log_develop_is_enabled(Trace, jvmcont) && !mixed && f.is_interpreted()) f.cb()->print_value_on(tty);

if (mixed) f.handle_deopted(); // we could freeze deopted frames in slow mode.

run_nmethod_entry_barrier_if_needed<mixed>(f);

BarrierClosure<store> oop_closure(f.sp());
f.iterate_oops(&oop_closure, map);
}

class FixOopsClosure: public OopClosure {
DEBUG_ONLY(intptr_t* _sp;)
public:
FixOopsClosure(intptr_t* sp) DEBUG_ONLY(: _sp(sp)) {}

virtual void do_oop(oop* p) override {
log_develop_trace(jvmcont)("fix_oops wide p: " INTPTR_FORMAT " sp offset: %ld", p2i(p), (intptr_t*)p - _sp);
*(oop*)p = (oop)NativeAccess<>::oop_load((oop*)p);
ZGC_ONLY(assert (!UseZGC || ZAddress::is_good_or_null(cast_from_oop<uintptr_t>(*(oop*)p)), "");)
}
virtual void do_oop(narrowOop* p) override {
log_develop_trace(jvmcont)("fix_oops narrow p: " INTPTR_FORMAT " sp offset: %ld", p2i(p), (intptr_t*)p - _sp);
*(narrowOop*)p = CompressedOops::encode((oop)NativeAccess<>::oop_load((narrowOop*)p));
}
};

class FixChunkIterateStackClosure {
stackChunkOop _chunk;
public:
int _num_frames, _num_oops;
FixChunkIterateStackClosure(stackChunkOop chunk) : _chunk(chunk), _num_frames(0), _num_oops(0) {}

template <bool mixed, typename RegisterMapT>
bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map, MemRegion mr) {
log_develop_trace(jvmcont)("fix_stack_chunk sp: %ld pc: " INTPTR_FORMAT, f.sp() - _chunk->start_address(), p2i(f.pc()));

if (log_develop_is_enabled(Trace, jvmcont) && !mixed && f.is_interpreted()) f.cb()->print_value_on(tty);

f.handle_deopted();

_num_frames++;
_num_oops += f.num_oops();

InstanceStackChunkKlass::run_nmethod_entry_barrier_if_needed<mixed>(f);

if (UseZGC || UseShenandoahGC) {
RelativizeDerivedPointers<true> derived_closure(_chunk);
f.iterate_derived_pointers(&derived_closure, map);

FixOopsClosure oops_closure(f.sp());
f.iterate_oops(&oops_closure, map);
OrderAccess::loadload();
}
DerelativizeDerivedPointers derived_closure;
if (UseZGC || UseShenandoahGC) {
RelativizeDerivedPointers<true> derived_closure;
f.iterate_derived_pointers(&derived_closure, map);

return true;
}
};

NOINLINE void InstanceStackChunkKlass::fix_chunk(stackChunkOop chunk) {
log_develop_trace(jvmcont)("fix_stack_chunk young: %d", !chunk->requires_barriers());
BarrierClosure<store> oops_closure(f.sp());
f.iterate_oops(&oops_closure, map);
OrderAccess::loadload(); // observing the barriers will prevent derived pointers from being derelativized concurrently

FixChunkIterateStackClosure frame_closure(chunk);
chunk->iterate_stack(&frame_closure);

OrderAccess::storestore();
chunk->set_gc_mode(false);

assert (frame_closure._num_frames >= 0, "");
assert (frame_closure._num_oops >= 0, "");

EventContinuationFix e;
if (e.should_commit()) {
e.set_id(cast_from_oop<u8>(chunk));
e.set_numFrames((u2)frame_closure._num_frames);
e.set_numOops((u2)frame_closure._num_oops);
e.commit();
}

log_develop_trace(jvmcont)("fix_stack_chunk ------- end -------");
// tty->print_cr("<<< fix_stack_chunk %p %p", (oopDesc*)chunk, Thread::current());
DerelativizeDerivedPointers derived_closure;
f.iterate_derived_pointers(&derived_closure, map);
}

template void InstanceStackChunkKlass::fix_frame<true, false>(const StackChunkFrameStream<true >& f, const RegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<true, true> (const StackChunkFrameStream<true >& f, const RegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<false, false>(const StackChunkFrameStream<false>& f, const RegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<false, true> (const StackChunkFrameStream<false>& f, const RegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<true, false>(const StackChunkFrameStream<true >& f, const SmallRegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<true, true> (const StackChunkFrameStream<true >& f, const SmallRegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<false, false>(const StackChunkFrameStream<false>& f, const SmallRegisterMap* map);
template void InstanceStackChunkKlass::fix_frame<false, true> (const StackChunkFrameStream<false>& f, const SmallRegisterMap* map);


// template <bool store>
// class BarriersIterateStackClosure {
// public:
// template <bool mixed, typename RegisterMapT>
// bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map) {
// InstanceStackChunkKlass::barriers_for_oops_in_frame<mixed, store>(f, map);
// return true;
// }
// };

// template <bool store>
// void InstanceStackChunkKlass::barriers_for_oops_in_chunk(stackChunkOop chunk) {
// BarriersIterateStackClosure<store> frame_closure;
// chunk->iterate_stack(&frame_closure);
// }

// NOINLINE void InstanceStackChunkKlass::fix_chunk(stackChunkOop chunk) {
// log_develop_trace(jvmcont)("fix_stack_chunk young: %d", !chunk->requires_barriers());
// FixChunkIterateStackClosure frame_closure(chunk);
// chunk->iterate_stack(&frame_closure);
// log_develop_trace(jvmcont)("fix_stack_chunk ------- end -------");
// }

#ifdef ASSERT

template<class P>
@@ -467,7 +433,7 @@ class VerifyStackClosure {
_size(size), _argsize(0), _num_oops(0), _num_frames(num_frames), _num_interpreted_frames(0), _num_i2c(0) {}

template <bool mixed, typename RegisterMapT>
bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map, MemRegion mr) {
bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map) {
_sp = f.sp();
_cb = f.cb();

@@ -616,11 +582,13 @@ class DescribeStackChunkClosure {
const RegisterMap* get_map(const SmallRegisterMap* map, intptr_t* sp) { return map->copy_to_RegisterMap(&_map, sp); }

template <bool mixed, typename RegisterMapT>
bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map, MemRegion mr) {
bool do_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map) {
ResetNoHandleMark rnhm;
HandleMark hm(Thread::current());

f.to_frame().template describe<true>(_values, _frame_no++, get_map(map, f.sp()));
frame fr = f.to_frame();
if (_frame_no == 0) fr.describe_top(_values);
fr.template describe<true>(_values, _frame_no++, get_map(map, f.sp()));
return true;
}

@@ -651,7 +619,7 @@ class PrintStackChunkClosure {
PrintStackChunkClosure(stackChunkOop chunk, outputStream* st) : _chunk(chunk), _st(st) {}

template <bool mixed, typename RegisterMapT>
bool do_frame(const StackChunkFrameStream<mixed>& fs, const RegisterMapT* map, MemRegion mr) {
bool do_frame(const StackChunkFrameStream<mixed>& fs, const RegisterMapT* map) {
frame f = fs.to_frame();
_st->print_cr("-- frame sp: " INTPTR_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());
f.print_on<true>(_st);
@@ -136,13 +136,8 @@ class InstanceStackChunkKlass: public InstanceKlass {
inline void oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr);

public:
template <bool store>
static void barriers_for_oops_in_chunk(stackChunkOop chunk);

template <bool mixed, bool store, typename RegisterMapT>
static void barriers_for_oops_in_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map);

static void fix_chunk(stackChunkOop chunk);
static void fix_frame(const StackChunkFrameStream<mixed>& f, const RegisterMapT* map);

static inline void derelativize_interpreted_frame_metadata(const frame& hf, const frame& f);
static inline void relativize_interpreted_frame_metadata(const frame& f, const frame& hf);
@@ -260,8 +255,8 @@ class StackChunkFrameStream : public StackObj {
inline void* reg_to_loc(VMReg reg, const RegisterMapT* map) const;

public:
template <class OopClosureType, class RegisterMapT> inline void iterate_oops(OopClosureType* closure, const RegisterMapT* map, MemRegion mr = MemRegion(NULL, SIZE_MAX)) const;
template <class DerivedOopClosureType, class RegisterMapT> inline void iterate_derived_pointers(DerivedOopClosureType* closure, const RegisterMapT* map, MemRegion mr = MemRegion(NULL, SIZE_MAX)) const;
template <class OopClosureType, class RegisterMapT> inline void iterate_oops(OopClosureType* closure, const RegisterMapT* map) const;
template <class DerivedOopClosureType, class RegisterMapT> inline void iterate_derived_pointers(DerivedOopClosureType* closure, const RegisterMapT* map) const;
};

#endif // SHARE_OOPS_INSTANCESTACKCHUNKKLASS_HPP

0 comments on commit 2b98429

Please sign in to comment.