8325469: Freeze/Thaw code can crash in the presence of OSR frames
Reviewed-by: rpressler, dlong
This commit is contained in:
parent
9fd78022b1
commit
fd331ff173
@ -241,7 +241,7 @@ inline int frame::frame_size() const {
|
||||
|
||||
inline int frame::compiled_frame_stack_argsize() const {
|
||||
assert(cb()->is_nmethod(), "");
|
||||
return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
}
|
||||
|
||||
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
|
||||
|
@ -35,7 +35,7 @@ template <ChunkFrames frame_kind>
|
||||
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
|
||||
assert(!is_done(), "");
|
||||
intptr_t* p = (intptr_t*)p0;
|
||||
int argsize = is_compiled() ? (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
|
||||
int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
|
||||
int frame_size = _cb->frame_size() + argsize;
|
||||
return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size);
|
||||
}
|
||||
|
@ -369,7 +369,7 @@ inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
|
||||
|
||||
inline int frame::compiled_frame_stack_argsize() const {
|
||||
assert(cb()->is_nmethod(), "");
|
||||
return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
}
|
||||
|
||||
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
|
||||
|
@ -35,7 +35,7 @@ inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
|
||||
assert(!is_done(), "");
|
||||
assert(is_compiled(), "");
|
||||
intptr_t* p = (intptr_t*)p0;
|
||||
int argsize = (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
int argsize = (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
int frame_size = _cb->frame_size() + (argsize > 0 ? argsize + frame::metadata_words_at_top : 0);
|
||||
return (p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size;
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ inline int frame::frame_size() const {
|
||||
|
||||
inline int frame::compiled_frame_stack_argsize() const {
|
||||
assert(cb()->is_nmethod(), "");
|
||||
return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
}
|
||||
|
||||
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
|
||||
|
@ -34,7 +34,7 @@ template <ChunkFrames frame_kind>
|
||||
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
|
||||
assert(!is_done(), "");
|
||||
intptr_t* p = (intptr_t*)p0;
|
||||
int argsize = is_compiled() ? (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
|
||||
int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
|
||||
int frame_size = _cb->frame_size() + argsize;
|
||||
return p == sp() - 2 || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size);
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ inline int frame::frame_size() const {
|
||||
|
||||
inline int frame::compiled_frame_stack_argsize() const {
|
||||
assert(cb()->is_nmethod(), "");
|
||||
return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
}
|
||||
|
||||
inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const {
|
||||
|
@ -34,7 +34,7 @@ template <ChunkFrames frame_kind>
|
||||
inline bool StackChunkFrameStream<frame_kind>::is_in_frame(void* p0) const {
|
||||
assert(!is_done(), "");
|
||||
intptr_t* p = (intptr_t*)p0;
|
||||
int argsize = is_compiled() ? (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
|
||||
int argsize = is_compiled() ? (_cb->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0;
|
||||
int frame_size = _cb->frame_size() + argsize;
|
||||
return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size);
|
||||
}
|
||||
|
@ -1230,6 +1230,7 @@ nmethod::nmethod(
|
||||
init_defaults();
|
||||
_comp_level = CompLevel_none;
|
||||
_entry_bci = InvocationEntryBci;
|
||||
_num_stack_arg_slots = _method->constMethod()->num_stack_arg_slots();
|
||||
// We have no exception handler or deopt handler make the
|
||||
// values something that will never match a pc like the nmethod vtable entry
|
||||
_exception_offset = 0;
|
||||
@ -1374,12 +1375,13 @@ nmethod::nmethod(
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
|
||||
init_defaults();
|
||||
_entry_bci = entry_bci;
|
||||
_compile_id = compile_id;
|
||||
_compiler_type = type;
|
||||
_comp_level = comp_level;
|
||||
_orig_pc_offset = orig_pc_offset;
|
||||
_gc_epoch = CodeCache::gc_epoch();
|
||||
_entry_bci = entry_bci;
|
||||
_num_stack_arg_slots = entry_bci != InvocationEntryBci ? 0 : _method->constMethod()->num_stack_arg_slots();
|
||||
_compile_id = compile_id;
|
||||
_compiler_type = type;
|
||||
_comp_level = comp_level;
|
||||
_orig_pc_offset = orig_pc_offset;
|
||||
_gc_epoch = CodeCache::gc_epoch();
|
||||
|
||||
// Section offsets
|
||||
_consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts());
|
||||
|
@ -243,6 +243,8 @@ class nmethod : public CodeBlob {
|
||||
|
||||
int _compile_id; // which compilation made this nmethod
|
||||
|
||||
int _num_stack_arg_slots; // Number of arguments passed on the stack
|
||||
|
||||
CompilerType _compiler_type; // which compiler made this nmethod (u1)
|
||||
|
||||
bool _is_unlinked;
|
||||
@ -792,6 +794,10 @@ public:
|
||||
nmethod* osr_link() const { return _osr_link; }
|
||||
void set_osr_link(nmethod *n) { _osr_link = n; }
|
||||
|
||||
int num_stack_arg_slots(bool rounded = true) const {
|
||||
return rounded ? align_up(_num_stack_arg_slots, 2) : _num_stack_arg_slots;
|
||||
}
|
||||
|
||||
// Verify calls to dead methods have been cleaned.
|
||||
void verify_clean_inline_caches();
|
||||
|
||||
|
@ -394,10 +394,6 @@ public:
|
||||
void unlink_method() NOT_CDS_RETURN;
|
||||
void remove_unshareable_flags() NOT_CDS_RETURN;
|
||||
|
||||
// the number of argument reg slots that the compiled method uses on the stack.
|
||||
int num_stack_arg_slots(bool rounded = true) const {
|
||||
return rounded ? align_up(constMethod()->num_stack_arg_slots(), 2) : constMethod()->num_stack_arg_slots(); }
|
||||
|
||||
virtual void metaspace_pointers_do(MetaspaceClosure* iter);
|
||||
virtual MetaspaceObj::Type type() const { return MethodType; }
|
||||
|
||||
|
@ -562,9 +562,9 @@ bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames,
|
||||
assert(!is_empty() || closure._cb == nullptr, "");
|
||||
if (closure._cb != nullptr && closure._cb->is_nmethod()) {
|
||||
assert(argsize() ==
|
||||
(closure._cb->as_nmethod()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord,
|
||||
(closure._cb->as_nmethod()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord,
|
||||
"chunk argsize: %d bottom frame argsize: %d", argsize(),
|
||||
(closure._cb->as_nmethod()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord);
|
||||
(closure._cb->as_nmethod()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord);
|
||||
}
|
||||
|
||||
assert(closure._num_interpreted_frames == 0 || has_mixed_frames(), "");
|
||||
|
@ -1242,7 +1242,6 @@ NOINLINE freeze_result FreezeBase::recurse_freeze_stub_frame(frame& f, frame& ca
|
||||
|
||||
NOINLINE void FreezeBase::finish_freeze(const frame& f, const frame& top) {
|
||||
stackChunkOop chunk = _cont.tail();
|
||||
assert(chunk->to_offset(top.sp()) <= chunk->sp(), "");
|
||||
|
||||
LogTarget(Trace, continuations) lt;
|
||||
if (lt.develop_is_enabled()) {
|
||||
@ -2309,7 +2308,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n
|
||||
_cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance);
|
||||
} else if (_cont.tail()->has_bitmap() && added_argsize > 0) {
|
||||
address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top);
|
||||
int stack_args_slots = f.cb()->as_nmethod()->method()->num_stack_arg_slots(false /* rounded */);
|
||||
int stack_args_slots = f.cb()->as_nmethod()->num_stack_arg_slots(false /* rounded */);
|
||||
int argsize_in_bytes = stack_args_slots * VMRegImpl::stack_slot_size;
|
||||
clear_bitmap_bits(start, start + argsize_in_bytes);
|
||||
}
|
||||
|
@ -1435,7 +1435,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m
|
||||
assert(sig_index == sizeargs, "");
|
||||
}
|
||||
int stack_arg_slots = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs);
|
||||
assert(stack_arg_slots == m->num_stack_arg_slots(false /* rounded */), "");
|
||||
assert(stack_arg_slots == nm->as_nmethod()->num_stack_arg_slots(false /* rounded */) || nm->is_osr_method(), "");
|
||||
int out_preserve = SharedRuntime::out_preserve_stack_slots();
|
||||
int sig_index = 0;
|
||||
int arg_index = (m->is_static() ? 0 : -1);
|
||||
|
@ -191,7 +191,7 @@ inline int StackChunkFrameStream<frame_kind>::stack_argsize() const {
|
||||
assert(cb() != nullptr, "");
|
||||
assert(cb()->is_nmethod(), "");
|
||||
assert(cb()->as_nmethod()->method() != nullptr, "");
|
||||
return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
return (cb()->as_nmethod()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord;
|
||||
}
|
||||
|
||||
template <ChunkFrames frame_kind>
|
||||
|
238
test/jdk/jdk/internal/vm/Continuation/OSRTest.java
Normal file
238
test/jdk/jdk/internal/vm/Continuation/OSRTest.java
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2024, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8325469
|
||||
* @summary Test freeze/thaw with OSR frames
|
||||
* @requires vm.continuations
|
||||
* @requires vm.compMode != "Xint" & vm.compMode != "Xcomp"
|
||||
* @modules java.base/jdk.internal.vm
|
||||
* @library /test/lib /test/hotspot/jtreg
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI OSRTest true true true
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=inline,*::yield0 OSRTest true true false
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=dontinline,*::yield* OSRTest true true false
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,*::bar() OSRTest true false false
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI OSRTest false true true
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI OSRTest false true false
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=exclude,*::bar() OSRTest false false false
|
||||
*
|
||||
*/
|
||||
|
||||
import jdk.internal.vm.Continuation;
|
||||
import jdk.internal.vm.ContinuationScope;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
|
||||
public class OSRTest {
|
||||
static final WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
static final ContinuationScope FOO = new ContinuationScope() {};
|
||||
static final Method foo = getMethod("foo");
|
||||
static final Method fooBigFrame = getMethod("fooBigFrame");
|
||||
boolean osrAtBottom;
|
||||
boolean freezeFast;
|
||||
boolean thawFast;
|
||||
int fooCallCount;
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 3) {
|
||||
throw new Error("Error: args.length must be 3");
|
||||
}
|
||||
boolean TEST_OSR_AT_BOTTOM = Boolean.parseBoolean(args[0]);
|
||||
boolean FREEZE_FAST = Boolean.parseBoolean(args[1]);
|
||||
boolean THAW_FAST = Boolean.parseBoolean(args[2]);
|
||||
assert !THAW_FAST || FREEZE_FAST : "THAW_FAST requires FREEZE_FAST";
|
||||
|
||||
OSRTest test = new OSRTest(TEST_OSR_AT_BOTTOM, FREEZE_FAST, THAW_FAST);
|
||||
test.runTest();
|
||||
}
|
||||
|
||||
public OSRTest(boolean osrAtBottom, boolean freezeFast, boolean thawFast) {
|
||||
this.osrAtBottom = osrAtBottom;
|
||||
this.freezeFast = freezeFast;
|
||||
this.thawFast = thawFast;
|
||||
}
|
||||
|
||||
public void runTest() {
|
||||
Runnable testCase = osrAtBottom ? ()-> testOSRAtStackBottom() : ()-> TestOSRNotAtStackBottom();
|
||||
Continuation cont = new Continuation(FOO, testCase);
|
||||
|
||||
while (!cont.isDone()) {
|
||||
cont.run();
|
||||
if (freezeFast && !thawFast && fooCallCount == 2) {
|
||||
// All frames frozen in last yield should be compiled
|
||||
// including OSR version of foo. Invoke full GC now so
|
||||
// that chunk is marked and we force thaw slow path.
|
||||
System.gc();
|
||||
fooCallCount++; // Don't call again
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testOSRAtStackBottom() {
|
||||
if (freezeFast) {
|
||||
// Trigger compilation of Continuation.yield/yield0
|
||||
for (int i = 0; i < 10_000; i++) {
|
||||
Continuation.yield(FOO);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (freezeFast && !thawFast) {
|
||||
foo(new Object(), new Object(), new Object(), new Object(), new Object(),
|
||||
new Object(), new Object(), new Object(), new Object(), new Object(),
|
||||
1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f);
|
||||
} else {
|
||||
fooBigFrame(new Object(), new Object(), new Object(), new Object(), new Object(),
|
||||
new Object(), new Object(), new Object(), new Object(), new Object(),
|
||||
1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Declare many parameters and unused locals so that size of interpreter frame is bigger
|
||||
// than size of OSR frame + size of Continuation.yield/yield0 frames. This is so that once
|
||||
// foo is OSR, on yield we clear cont_fastpath() forcing the freeze fast path.
|
||||
public void foo(Object o1, Object o2, Object o3, Object o4, Object o5,
|
||||
Object o6, Object o7, Object o8, Object o9, Object o10,
|
||||
float f1, float f2, float f3, float f4, float f5, float f6, float f7) {
|
||||
int i1 = 1;
|
||||
int i2 = i1 + 1;
|
||||
int i3 = i2 + 1;
|
||||
int i4 = i3 + 1;
|
||||
int i5 = i4 + 1;
|
||||
int i6 = i5 + 1;
|
||||
int i7 = i6 + 1;
|
||||
long ll = 2*(long)i1;
|
||||
float ff = ll + 1.2f;
|
||||
double dd = ff + 1.3D;
|
||||
|
||||
if (osrAtBottom) {
|
||||
// freeze all frames so that we only run with foo on the stack
|
||||
Continuation.yield(FOO);
|
||||
}
|
||||
|
||||
// Provoke OSR compilation. After we verified the method was compiled keep looping
|
||||
// until we trigger the _backedge_counter overflow to actually trigger OSR.
|
||||
for (int i = 0; fooCallCount > 0 && (!wb.isMethodCompiled(foo, true) || i++ < 2_000);) {
|
||||
}
|
||||
fooCallCount++;
|
||||
|
||||
if (freezeFast) {
|
||||
Continuation.yield(FOO);
|
||||
} else {
|
||||
bar();
|
||||
}
|
||||
}
|
||||
|
||||
public void bar() {
|
||||
Continuation.yield(FOO);
|
||||
}
|
||||
|
||||
public double fooBigFrame(Object o1, Object o2, Object o3, Object o4, Object o5,
|
||||
Object o6, Object o7, Object o8, Object o9, Object o10,
|
||||
float f1, float f2, float f3, float f4, float f5, float f6, float f7) {
|
||||
double d1=1,d2=2,d3=3,d4=4,d5=5,d6=6,d7=7,d8=8,d9=9,d10=10,d11=11,d12=12,d13=13,d14=14,d15=15,d16=16,d17=17,d18=18,d19=19,d20=20,d21=21,d22=22,d23=23,d24=24,d25=25;
|
||||
double d26=26,d27=27,d28=28,d29=29,d30=30,d31=31,d32=32,d33=33,d34=34,d35=35,d36=36,d37=37,d38=38,d39=39,d40=40,d41=41,d42=42,d43=43,d44=44,d45=45,d46=46,d47=47,d48=48,d49=49,d50=50;
|
||||
double d51=51,d52=52,d53=53,d54=54,d55=55,d56=56,d57=57,d58=58,d59=59,d60=60,d61=61,d62=62,d63=63,d64=64,d65=65,d66=66,d67=67,d68=68,d69=69,d70=70,d71=71,d72=72,d73=73,d74=74,d75=75;
|
||||
double d76=76,d77=77,d78=78,d79=79,d80=80,d81=81,d82=82,d83=83,d84=84,d85=85,d86=86,d87=87,d88=88,d89=89,d90=90,d91=91,d92=92,d93=93,d94=94,d95=95,d96=96,d97=97,d98=98,d99=99,d100=100;
|
||||
double d101=101,d102=102,d103=103,d104=104,d105=105,d106=106,d107=107,d108=108,d109=109,d110=110,d111=111,d112=112,d113=113,d114=114,d115=115,d116=116,d117=117,d118=118,d119=119,d120=120,d121=121,d122=122,d123=123,d124=124,d125=125;
|
||||
double d126=126,d127=127,d128=128,d129=129,d130=130,d131=131,d132=132,d133=133,d134=134,d135=135,d136=136,d137=137,d138=138,d139=139,d140=140,d141=141,d142=142,d143=143,d144=144,d145=145,d146=146,d147=147,d148=148,d149=149,d150=150;
|
||||
double d151=151,d152=152,d153=153,d154=154,d155=155,d156=156,d157=157,d158=158,d159=159,d160=160,d161=161,d162=162,d163=163,d164=164,d165=165,d166=166,d167=167,d168=168,d169=169,d170=170,d171=171,d172=172,d173=173,d174=174,d175=175;
|
||||
double d176=176,d177=177,d178=178,d179=179,d180=180,d181=181,d182=182,d183=183,d184=184,d185=185,d186=186,d187=187,d188=188,d189=189,d190=190,d191=191,d192=192,d193=193,d194=194,d195=195,d196=196,d197=197,d198=198,d199=199,d200=200;
|
||||
double d201=201,d202=202,d203=203,d204=204,d205=205,d206=206,d207=207,d208=208,d209=209,d210=210,d211=211,d212=212,d213=213,d214=214,d215=215,d216=216,d217=217,d218=218,d219=219,d220=220,d221=221,d222=222,d223=223,d224=224,d225=225;
|
||||
double d226=226,d227=227,d228=228,d229=229,d230=230,d231=231,d232=232,d233=233,d234=234,d235=235,d236=236,d237=237,d238=238,d239=239,d240=240,d241=241,d242=242,d243=243,d244=244,d245=245,d246=246,d247=247,d248=248,d249=249,d250=250;
|
||||
double d251=251,d252=252,d253=253,d254=254,d255=255,d256=256,d257=257,d258=258,d259=259,d260=260,d261=261,d262=262,d263=263,d264=264,d265=265,d266=266,d267=267,d268=268,d269=269,d270=270,d271=271,d272=272,d273=273,d274=274,d275=275;
|
||||
double d276=276,d277=277,d278=278,d279=279,d280=280,d281=281,d282=282,d283=283,d284=284,d285=285,d286=286,d287=287,d288=288,d289=289,d290=290,d291=291,d292=292,d293=293,d294=294,d295=295,d296=296,d297=297,d298=298,d299=299,d300=300;
|
||||
|
||||
// freeze all frames so that we only run with fooBigFrame on the stack
|
||||
Continuation.yield(FOO);
|
||||
|
||||
// Provoke OSR compilation. After we verified the method was compiled keep looping
|
||||
// until we trigger the _backedge_counter overflow to actually trigger OSR.
|
||||
for (int i = 0; fooCallCount > 0 && (!wb.isMethodCompiled(fooBigFrame, true) || i++ < 2_000);) {
|
||||
}
|
||||
fooCallCount++;
|
||||
|
||||
Continuation.yield(FOO);
|
||||
|
||||
// For the thaw fast case we want to trigger the case of thawing one
|
||||
// frame at a time. Because the OSR frame is at the bottom we have to
|
||||
// make its size > 500 words, so we use a lot of locals. We also want
|
||||
// the interpreted frame size be bigger than OSR frame + size of
|
||||
// Continuation.yield/yield0, so that we clear cont_fastpath() on yield
|
||||
// forcing the freeze fast path (same as with foo). For that, we just
|
||||
// declare more locals than the ones we use after OSR happens.
|
||||
// For the freeze slow case we also want the interpreted frame size to
|
||||
// be bigger than OSR frame + size of Continuation.yield/yield0, so the
|
||||
// last technique serves for this case too.
|
||||
double res = d1*d2*d3*d4*d5*d6*d7*d8*d9*d10*d11*d12*d13*d14*d15*d16*d17*d18*d19*d20*d21*d22*d23*d24*d25*d26*d27*d28*d29*d30*d31*d32*d33*d34*d35*d36*d37*d38*d39*d40*d41*d42*d43*d44*d45*d46*d47*d48*d49*d50*
|
||||
d51*d52*d53*d54*d55*d56*d57*d58*d59*d60*d61*d62*d63*d64*d65*d66*d67*d68*d69*d70*d71*d72*d73*d74*d75*d76*d77*d78*d79*d80*d81*d82*d83*d84*d85*d86*d87*d88*d89*d90*d91*d92*d93*d94*d95*d96*d97*d98*d99*d100*
|
||||
d101*d102*d103*d104*d105*d106*d107*d108*d109*d110*d111*d112*d113*d114*d115*d116*d117*d118*d119*d120*d121*d122*d123*d124*d125*d126*d127*d128*d129*d130*d131*d132*d133*d134*d135*d136*d137*d138*d139*d140*
|
||||
d141*d142*d143*d144*d145*d146*d147*d148*d149*d150*d151*d152*d153*d154*d155*d156*d157*d158*d159*d160*d161*d162*d163*d164*d165*d166*d167*d168*d169*d170*d171*d172*d173*d174*d175*d176*d177*d178*d179*d180*
|
||||
d181*d182*d183*d184*d185*d186*d187*d188*d189*d190*d191*d192*d193*d194*d195*d196*d197*d198*d199*d200*d201*d202*d203*d204*d205*d206*d207*d208*d209*d210*d211*d212*d213*d214*d215*d216*d217*d218*d219*d220*
|
||||
d221*d222*d223*d224*d225*d226*d227*d228*d229*d230*d231*d232*d233*d234*d235*d236*d237*d238*d239*d240*d241*d242*d243*d244*d245*d246*d247*d248*d249*d250*d251*d252*d253*d254*d255*d256*d257*d258*d259*d260*
|
||||
d261*d262*d263*d264*d265*d266*d267*d268*d269*d270*d271*d272*d273*d274*d275;
|
||||
return res;
|
||||
}
|
||||
|
||||
public void TestOSRNotAtStackBottom() {
|
||||
// freeze all frames currently in the stack
|
||||
boolean res = Continuation.yield(FOO);
|
||||
|
||||
for (int i = 1; i < 100000; i++) {
|
||||
// When testing the thaw fast path make recursion big enough so that
|
||||
// the size of all frames at freeze time is more than 500 words. This
|
||||
// way we later force thawing one frame at a time.
|
||||
recurse(thawFast ? 60 : 5, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void recurse(int depth, int iteration) {
|
||||
if (depth > 0) {
|
||||
recurse(depth - 1, iteration);
|
||||
} else {
|
||||
// Make compiler see this branch but not enough times to avoid foo
|
||||
// getting compiled, since we want the OSR version.
|
||||
if (iteration % 45000 == 0) {
|
||||
foo(new Object(), new Object(), new Object(), new Object(), new Object(),
|
||||
new Object(), new Object(), new Object(), new Object(), new Object(),
|
||||
1.1f, 1.2f, 1.3f, 1.4f, 1.5f, 1.6f, 1.7f);
|
||||
} else {
|
||||
Continuation.yield(FOO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Method getMethod(String method) {
|
||||
try {
|
||||
return OSRTest.class.getMethod(method, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class, Object.class,
|
||||
Object.class, Object.class, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE, Float.TYPE);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception: couldn't found method " + method + ". " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user