Merge
This commit is contained in:
commit
f457cabe80
@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 1999, 2014, 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
|
||||
@ -64,7 +64,7 @@ MFLAGS=`
|
||||
echo "$MFLAGS" \
|
||||
| sed '
|
||||
s/^-/ -/
|
||||
s/ -\([^ ][^ ]*\)j/ -\1 -j/
|
||||
s/ -\([^ I][^ I]*\)j/ -\1 -j/
|
||||
s/ -j[0-9][0-9]*/ -j/
|
||||
s/ -j\([^ ]\)/ -j -\1/
|
||||
s/ -j/ -j'${HOTSPOT_BUILD_JOBS:-${default_build_jobs}}'/
|
||||
|
@ -25,6 +25,9 @@
|
||||
|
||||
# Setup common to Zero (non-Shark) and Shark versions of VM
|
||||
|
||||
# override this from the main file because some version of llvm do not like -Wundef
|
||||
WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wunused-function -Wunused-value
|
||||
|
||||
# The copied fdlibm routines in sharedRuntimeTrig.o must not be optimized
|
||||
OPT_CFLAGS/sharedRuntimeTrig.o = $(OPT_CFLAGS/NOOPT)
|
||||
# The copied fdlibm routines in sharedRuntimeTrans.o must not be optimized
|
||||
|
@ -124,6 +124,7 @@ class Argument VALUE_OBJ_CLASS_SPEC {
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(ABI_ELFv2)
|
||||
// A ppc64 function descriptor.
|
||||
struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
@ -161,6 +162,7 @@ struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||
_env = (address) 0xbad;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
class Assembler : public AbstractAssembler {
|
||||
protected:
|
||||
@ -1067,6 +1069,7 @@ class Assembler : public AbstractAssembler {
|
||||
// Emit an address.
|
||||
inline address emit_addr(const address addr = NULL);
|
||||
|
||||
#if !defined(ABI_ELFv2)
|
||||
// Emit a function descriptor with the specified entry point, TOC,
|
||||
// and ENV. If the entry point is NULL, the descriptor will point
|
||||
// just past the descriptor.
|
||||
@ -1074,6 +1077,7 @@ class Assembler : public AbstractAssembler {
|
||||
inline address emit_fd(address entry = NULL,
|
||||
address toc = (address) FunctionDescriptor::friend_toc,
|
||||
address env = (address) FunctionDescriptor::friend_env);
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
// PPC instructions
|
||||
|
@ -55,6 +55,7 @@ inline address Assembler::emit_addr(const address addr) {
|
||||
return start;
|
||||
}
|
||||
|
||||
#if !defined(ABI_ELFv2)
|
||||
// Emit a function descriptor with the specified entry point, TOC, and
|
||||
// ENV. If the entry point is NULL, the descriptor will point just
|
||||
// past the descriptor.
|
||||
@ -73,6 +74,7 @@ inline address Assembler::emit_fd(address entry, address toc, address env) {
|
||||
|
||||
return (address)fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Issue an illegal instruction. 0 is guaranteed to be an illegal instruction.
|
||||
inline void Assembler::illtrap() { Assembler::emit_int32(0); }
|
||||
|
@ -1136,7 +1136,9 @@ address CppInterpreterGenerator::generate_native_entry(void) {
|
||||
// (outgoing C args), R3_ARG1 to R10_ARG8, and F1_ARG1 to
|
||||
// F13_ARG13.
|
||||
__ mr(R3_ARG1, R18_locals);
|
||||
#if !defined(ABI_ELFv2)
|
||||
__ ld(signature_handler_fd, 0, signature_handler_fd);
|
||||
#endif
|
||||
__ call_stub(signature_handler_fd);
|
||||
// reload method
|
||||
__ ld(R19_method, state_(_method));
|
||||
@ -1295,8 +1297,13 @@ address CppInterpreterGenerator::generate_native_entry(void) {
|
||||
// native result acrosss the call. No oop is present
|
||||
|
||||
__ mr(R3_ARG1, R16_thread);
|
||||
#if defined(ABI_ELFv2)
|
||||
__ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
|
||||
relocInfo::none);
|
||||
#else
|
||||
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
|
||||
relocInfo::none);
|
||||
#endif
|
||||
__ bind(sync_check_done);
|
||||
|
||||
//=============================================================================
|
||||
@ -1413,7 +1420,7 @@ address CppInterpreterGenerator::generate_native_entry(void) {
|
||||
// First, pop to caller's frame.
|
||||
__ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2);
|
||||
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
// Get the address of the exception handler.
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
|
||||
R16_thread,
|
||||
@ -2545,7 +2552,7 @@ address CppInterpreterGenerator::generate_normal_entry(void) {
|
||||
__ mr(R4_ARG2, R3_ARG1); // ARG2 := ARG1
|
||||
|
||||
// Find the address of the "catch_exception" stub.
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
|
||||
R16_thread,
|
||||
R4_ARG2);
|
||||
|
@ -50,7 +50,7 @@
|
||||
// [C_FRAME]
|
||||
//
|
||||
// C_FRAME:
|
||||
// 0 [ABI_112]
|
||||
// 0 [ABI_REG_ARGS]
|
||||
// 112 CARG_9: outgoing arg 9 (arg_1 ... arg_8 via gpr_3 ... gpr_{10})
|
||||
// ...
|
||||
// 40+M*8 CARG_M: outgoing arg M (M is the maximum of outgoing args taken over all call sites in the procedure)
|
||||
@ -77,7 +77,7 @@
|
||||
// 32 reserved
|
||||
// 40 space for TOC (=R2) register for next call
|
||||
//
|
||||
// ABI_112:
|
||||
// ABI_REG_ARGS:
|
||||
// 0 [ABI_48]
|
||||
// 48 CARG_1: spill slot for outgoing arg 1. used by next callee.
|
||||
// ... ...
|
||||
@ -95,23 +95,25 @@
|
||||
log_2_of_alignment_in_bits = 7
|
||||
};
|
||||
|
||||
// ABI_48:
|
||||
struct abi_48 {
|
||||
// ABI_MINFRAME:
|
||||
struct abi_minframe {
|
||||
uint64_t callers_sp;
|
||||
uint64_t cr; //_16
|
||||
uint64_t lr;
|
||||
#if !defined(ABI_ELFv2)
|
||||
uint64_t reserved1; //_16
|
||||
uint64_t reserved2;
|
||||
#endif
|
||||
uint64_t toc; //_16
|
||||
// nothing to add here!
|
||||
// aligned to frame::alignment_in_bytes (16)
|
||||
};
|
||||
|
||||
enum {
|
||||
abi_48_size = sizeof(abi_48)
|
||||
abi_minframe_size = sizeof(abi_minframe)
|
||||
};
|
||||
|
||||
struct abi_112 : abi_48 {
|
||||
struct abi_reg_args : abi_minframe {
|
||||
uint64_t carg_1;
|
||||
uint64_t carg_2; //_16
|
||||
uint64_t carg_3;
|
||||
@ -124,13 +126,13 @@
|
||||
};
|
||||
|
||||
enum {
|
||||
abi_112_size = sizeof(abi_112)
|
||||
abi_reg_args_size = sizeof(abi_reg_args)
|
||||
};
|
||||
|
||||
#define _abi(_component) \
|
||||
(offset_of(frame::abi_112, _component))
|
||||
(offset_of(frame::abi_reg_args, _component))
|
||||
|
||||
struct abi_112_spill : abi_112 {
|
||||
struct abi_reg_args_spill : abi_reg_args {
|
||||
// additional spill slots
|
||||
uint64_t spill_ret;
|
||||
uint64_t spill_fret; //_16
|
||||
@ -138,11 +140,11 @@
|
||||
};
|
||||
|
||||
enum {
|
||||
abi_112_spill_size = sizeof(abi_112_spill)
|
||||
abi_reg_args_spill_size = sizeof(abi_reg_args_spill)
|
||||
};
|
||||
|
||||
#define _abi_112_spill(_component) \
|
||||
(offset_of(frame::abi_112_spill, _component))
|
||||
#define _abi_reg_args_spill(_component) \
|
||||
(offset_of(frame::abi_reg_args_spill, _component))
|
||||
|
||||
// non-volatile GPRs:
|
||||
|
||||
@ -242,7 +244,7 @@
|
||||
// [ENTRY_FRAME_LOCALS]
|
||||
//
|
||||
// PARENT_IJAVA_FRAME_ABI:
|
||||
// 0 [ABI_48]
|
||||
// 0 [ABI_MINFRAME]
|
||||
// top_frame_sp
|
||||
// initial_caller_sp
|
||||
//
|
||||
@ -258,7 +260,7 @@
|
||||
|
||||
// PARENT_IJAVA_FRAME_ABI
|
||||
|
||||
struct parent_ijava_frame_abi : abi_48 {
|
||||
struct parent_ijava_frame_abi : abi_minframe {
|
||||
// SOE registers.
|
||||
// C2i adapters spill their top-frame stack-pointer here.
|
||||
uint64_t top_frame_sp; // carg_1
|
||||
@ -285,7 +287,7 @@
|
||||
uint64_t carg_6_unused; //_16 carg_6
|
||||
uint64_t carg_7_unused; // carg_7
|
||||
// Use arg8 for storing frame_manager_lr. The size of
|
||||
// top_ijava_frame_abi must match abi_112.
|
||||
// top_ijava_frame_abi must match abi_reg_args.
|
||||
uint64_t frame_manager_lr; //_16 carg_8
|
||||
// nothing to add here!
|
||||
// aligned to frame::alignment_in_bytes (16)
|
||||
@ -395,8 +397,8 @@
|
||||
intptr_t* fp() const { return _fp; }
|
||||
|
||||
// Accessors for ABIs
|
||||
inline abi_48* own_abi() const { return (abi_48*) _sp; }
|
||||
inline abi_48* callers_abi() const { return (abi_48*) _fp; }
|
||||
inline abi_minframe* own_abi() const { return (abi_minframe*) _sp; }
|
||||
inline abi_minframe* callers_abi() const { return (abi_minframe*) _fp; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -109,8 +109,10 @@ void InterpreterRuntime::SignatureHandlerGenerator::pass_object() {
|
||||
}
|
||||
|
||||
void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) {
|
||||
#if !defined(ABI_ELFv2)
|
||||
// Emit fd for current codebuffer. Needs patching!
|
||||
__ emit_fd();
|
||||
#endif
|
||||
|
||||
// Generate code to handle arguments.
|
||||
iterate(fingerprint);
|
||||
@ -127,11 +129,13 @@ void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprin
|
||||
// Implementation of SignatureHandlerLibrary
|
||||
|
||||
void SignatureHandlerLibrary::pd_set_handler(address handler) {
|
||||
#if !defined(ABI_ELFv2)
|
||||
// patch fd here.
|
||||
FunctionDescriptor* fd = (FunctionDescriptor*) handler;
|
||||
|
||||
fd->set_entry(handler + (int)sizeof(FunctionDescriptor));
|
||||
assert(fd->toc() == (address)0xcafe, "need to adjust TOC here");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,13 +128,13 @@ address AbstractInterpreterGenerator::generate_slow_signature_handler() {
|
||||
const Register target_sp = R28_tmp8;
|
||||
const FloatRegister floatSlot = F0;
|
||||
|
||||
address entry = __ emit_fd();
|
||||
address entry = __ function_entry();
|
||||
|
||||
__ save_LR_CR(R0);
|
||||
__ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14));
|
||||
// We use target_sp for storing arguments in the C frame.
|
||||
__ mr(target_sp, R1_SP);
|
||||
__ push_frame_abi112_nonvolatiles(0, R11_scratch1);
|
||||
__ push_frame_reg_args_nonvolatiles(0, R11_scratch1);
|
||||
|
||||
__ mr(arg_java, R3_ARG1);
|
||||
|
||||
@ -474,7 +474,7 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
|
||||
// Push a new C frame and save LR.
|
||||
__ save_LR_CR(R0);
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
|
||||
// This is not a leaf but we have a JavaFrameAnchor now and we will
|
||||
// check (create) exceptions afterward so this is ok.
|
||||
|
@ -594,7 +594,13 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool
|
||||
"can't identify emitted call");
|
||||
} else {
|
||||
// variant 1:
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
nop();
|
||||
calculate_address_from_global_toc(R12, dest, true, true, false);
|
||||
mtctr(R12);
|
||||
nop();
|
||||
nop();
|
||||
#else
|
||||
mr(R0, R11); // spill R11 -> R0.
|
||||
|
||||
// Load the destination address into CTR,
|
||||
@ -604,6 +610,7 @@ void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool
|
||||
mtctr(R11);
|
||||
mr(R11, R0); // spill R11 <- R0.
|
||||
nop();
|
||||
#endif
|
||||
|
||||
// do the call/jump
|
||||
if (link) {
|
||||
@ -912,16 +919,16 @@ void MacroAssembler::push_frame(unsigned int bytes, Register tmp) {
|
||||
}
|
||||
}
|
||||
|
||||
// Push a frame of size `bytes' plus abi112 on top.
|
||||
void MacroAssembler::push_frame_abi112(unsigned int bytes, Register tmp) {
|
||||
push_frame(bytes + frame::abi_112_size, tmp);
|
||||
// Push a frame of size `bytes' plus abi_reg_args on top.
|
||||
void MacroAssembler::push_frame_reg_args(unsigned int bytes, Register tmp) {
|
||||
push_frame(bytes + frame::abi_reg_args_size, tmp);
|
||||
}
|
||||
|
||||
// Setup up a new C frame with a spill area for non-volatile GPRs and
|
||||
// additional space for local variables.
|
||||
void MacroAssembler::push_frame_abi112_nonvolatiles(unsigned int bytes,
|
||||
Register tmp) {
|
||||
push_frame(bytes + frame::abi_112_size + frame::spill_nonvolatiles_size, tmp);
|
||||
void MacroAssembler::push_frame_reg_args_nonvolatiles(unsigned int bytes,
|
||||
Register tmp) {
|
||||
push_frame(bytes + frame::abi_reg_args_size + frame::spill_nonvolatiles_size, tmp);
|
||||
}
|
||||
|
||||
// Pop current C frame.
|
||||
@ -929,6 +936,42 @@ void MacroAssembler::pop_frame() {
|
||||
ld(R1_SP, _abi(callers_sp), R1_SP);
|
||||
}
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address MacroAssembler::branch_to(Register r_function_entry, bool and_link) {
|
||||
// TODO(asmundak): make sure the caller uses R12 as function descriptor
|
||||
// most of the times.
|
||||
if (R12 != r_function_entry) {
|
||||
mr(R12, r_function_entry);
|
||||
}
|
||||
mtctr(R12);
|
||||
// Do a call or a branch.
|
||||
if (and_link) {
|
||||
bctrl();
|
||||
} else {
|
||||
bctr();
|
||||
}
|
||||
_last_calls_return_pc = pc();
|
||||
|
||||
return _last_calls_return_pc;
|
||||
}
|
||||
|
||||
// Call a C function via a function descriptor and use full C
|
||||
// calling conventions. Updates and returns _last_calls_return_pc.
|
||||
address MacroAssembler::call_c(Register r_function_entry) {
|
||||
return branch_to(r_function_entry, /*and_link=*/true);
|
||||
}
|
||||
|
||||
// For tail calls: only branch, don't link, so callee returns to caller of this function.
|
||||
address MacroAssembler::call_c_and_return_to_caller(Register r_function_entry) {
|
||||
return branch_to(r_function_entry, /*and_link=*/false);
|
||||
}
|
||||
|
||||
address MacroAssembler::call_c(address function_entry, relocInfo::relocType rt) {
|
||||
load_const(R12, function_entry, R0);
|
||||
return branch_to(R12, /*and_link=*/true);
|
||||
}
|
||||
|
||||
#else
|
||||
// Generic version of a call to C function via a function descriptor
|
||||
// with variable support for C calling conventions (TOC, ENV, etc.).
|
||||
// Updates and returns _last_calls_return_pc.
|
||||
@ -1077,6 +1120,7 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd,
|
||||
}
|
||||
return _last_calls_return_pc;
|
||||
}
|
||||
#endif
|
||||
|
||||
void MacroAssembler::call_VM_base(Register oop_result,
|
||||
Register last_java_sp,
|
||||
@ -1091,8 +1135,11 @@ void MacroAssembler::call_VM_base(Register oop_result,
|
||||
|
||||
// ARG1 must hold thread address.
|
||||
mr(R3_ARG1, R16_thread);
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address return_pc = call_c(entry_point, relocInfo::none);
|
||||
#else
|
||||
address return_pc = call_c((FunctionDescriptor*)entry_point, relocInfo::none);
|
||||
#endif
|
||||
|
||||
reset_last_Java_frame();
|
||||
|
||||
@ -1113,7 +1160,11 @@ void MacroAssembler::call_VM_base(Register oop_result,
|
||||
|
||||
void MacroAssembler::call_VM_leaf_base(address entry_point) {
|
||||
BLOCK_COMMENT("call_VM_leaf {");
|
||||
#if defined(ABI_ELFv2)
|
||||
call_c(entry_point, relocInfo::none);
|
||||
#else
|
||||
call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::none);
|
||||
#endif
|
||||
BLOCK_COMMENT("} call_VM_leaf");
|
||||
}
|
||||
|
||||
@ -2227,7 +2278,7 @@ void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offs
|
||||
// VM call need frame to access(write) O register.
|
||||
if (needs_frame) {
|
||||
save_LR_CR(Rtmp1);
|
||||
push_frame_abi112(0, Rtmp2);
|
||||
push_frame_reg_args(0, Rtmp2);
|
||||
}
|
||||
|
||||
if (Rpre_val->is_volatile() && Robj == noreg) mr(R31, Rpre_val); // Save pre_val across C call if it was preloaded.
|
||||
@ -3006,13 +3057,13 @@ void MacroAssembler::verify_oop(Register oop, const char* msg) {
|
||||
mr(R0, tmp);
|
||||
// kill tmp
|
||||
save_LR_CR(tmp);
|
||||
push_frame_abi112(nbytes_save, tmp);
|
||||
push_frame_reg_args(nbytes_save, tmp);
|
||||
// restore tmp
|
||||
mr(tmp, R0);
|
||||
save_volatile_gprs(R1_SP, 112); // except R0
|
||||
// load FunctionDescriptor**
|
||||
// load FunctionDescriptor** / entry_address *
|
||||
load_const(tmp, fd);
|
||||
// load FunctionDescriptor*
|
||||
// load FunctionDescriptor* / entry_address
|
||||
ld(tmp, 0, tmp);
|
||||
mr(R4_ARG2, oop);
|
||||
load_const(R3_ARG1, (address)msg);
|
||||
|
@ -279,12 +279,12 @@ class MacroAssembler: public Assembler {
|
||||
// Push a frame of size `bytes'. No abi space provided.
|
||||
void push_frame(unsigned int bytes, Register tmp);
|
||||
|
||||
// Push a frame of size `bytes' plus abi112 on top.
|
||||
void push_frame_abi112(unsigned int bytes, Register tmp);
|
||||
// Push a frame of size `bytes' plus abi_reg_args on top.
|
||||
void push_frame_reg_args(unsigned int bytes, Register tmp);
|
||||
|
||||
// Setup up a new C frame with a spill area for non-volatile GPRs and additional
|
||||
// space for local variables
|
||||
void push_frame_abi112_nonvolatiles(unsigned int bytes, Register tmp);
|
||||
void push_frame_reg_args_nonvolatiles(unsigned int bytes, Register tmp);
|
||||
|
||||
// pop current C frame
|
||||
void pop_frame();
|
||||
@ -296,17 +296,31 @@ class MacroAssembler: public Assembler {
|
||||
private:
|
||||
address _last_calls_return_pc;
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
// Generic version of a call to C function.
|
||||
// Updates and returns _last_calls_return_pc.
|
||||
address branch_to(Register function_entry, bool and_link);
|
||||
#else
|
||||
// Generic version of a call to C function via a function descriptor
|
||||
// with variable support for C calling conventions (TOC, ENV, etc.).
|
||||
// updates and returns _last_calls_return_pc.
|
||||
address branch_to(Register function_descriptor, bool and_link, bool save_toc_before_call,
|
||||
bool restore_toc_after_call, bool load_toc_of_callee, bool load_env_of_callee);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
// Get the pc where the last call will return to. returns _last_calls_return_pc.
|
||||
inline address last_calls_return_pc();
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
// Call a C function via a function descriptor and use full C
|
||||
// calling conventions. Updates and returns _last_calls_return_pc.
|
||||
address call_c(Register function_entry);
|
||||
// For tail calls: only branch, don't link, so callee returns to caller of this function.
|
||||
address call_c_and_return_to_caller(Register function_entry);
|
||||
address call_c(address function_entry, relocInfo::relocType rt);
|
||||
#else
|
||||
// Call a C function via a function descriptor and use full C
|
||||
// calling conventions. Updates and returns _last_calls_return_pc.
|
||||
address call_c(Register function_descriptor);
|
||||
@ -315,6 +329,7 @@ class MacroAssembler: public Assembler {
|
||||
address call_c(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt);
|
||||
address call_c_using_toc(const FunctionDescriptor* function_descriptor, relocInfo::relocType rt,
|
||||
Register toc);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
@ -649,6 +664,11 @@ class MacroAssembler: public Assembler {
|
||||
void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
|
||||
void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line) {}
|
||||
|
||||
// Convenience method returning function entry. For the ELFv1 case
|
||||
// creates function descriptor at the current address and returs
|
||||
// the pointer to it. For the ELFv2 case returns the current address.
|
||||
inline address function_entry();
|
||||
|
||||
#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
|
||||
#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
|
||||
|
||||
|
@ -385,4 +385,10 @@ inline void MacroAssembler::trap_range_check_ge(Register a, int si16) {
|
||||
twi(traptoEqual | traptoGreaterThanUnsigned, a/*reg a*/, si16);
|
||||
}
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
inline address MacroAssembler::function_entry() { return pc(); }
|
||||
#else
|
||||
inline address MacroAssembler::function_entry() { return emit_fd(); }
|
||||
#endif
|
||||
|
||||
#endif // CPU_PPC_VM_MACROASSEMBLER_PPC_INLINE_HPP
|
||||
|
@ -453,11 +453,11 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
|
||||
if (Verbose) {
|
||||
tty->print_cr("Registers:");
|
||||
const int abi_offset = frame::abi_112_size / 8;
|
||||
const int abi_offset = frame::abi_reg_args_size / 8;
|
||||
for (int i = R3->encoding(); i <= R12->encoding(); i++) {
|
||||
Register r = as_Register(i);
|
||||
int count = i - R3->encoding();
|
||||
// The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_112_size)).
|
||||
// The registers are stored in reverse order on the stack (by save_volatile_gprs(R1_SP, abi_reg_args_size)).
|
||||
tty->print("%3s=" PTR_FORMAT, r->name(), saved_regs[abi_offset + count]);
|
||||
if ((count + 1) % 4 == 0) {
|
||||
tty->cr();
|
||||
@ -524,9 +524,9 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt
|
||||
__ save_LR_CR(R0);
|
||||
__ mr(R0, R1_SP); // saved_sp
|
||||
assert(Assembler::is_simm(-nbytes_save, 16), "Overwriting R0");
|
||||
// push_frame_abi112 only uses R0 if nbytes_save is wider than 16 bit
|
||||
__ push_frame_abi112(nbytes_save, R0);
|
||||
__ save_volatile_gprs(R1_SP, frame::abi_112_size); // Except R0.
|
||||
// Push_frame_reg_args only uses R0 if nbytes_save is wider than 16 bit.
|
||||
__ push_frame_reg_args(nbytes_save, R0);
|
||||
__ save_volatile_gprs(R1_SP, frame::abi_reg_args_size); // Except R0.
|
||||
|
||||
__ load_const(R3_ARG1, (address)adaptername);
|
||||
__ mr(R4_ARG2, R23_method_handle);
|
||||
|
@ -1008,7 +1008,11 @@ int MachCallDynamicJavaNode::ret_addr_offset() {
|
||||
}
|
||||
|
||||
int MachCallRuntimeNode::ret_addr_offset() {
|
||||
#if defined(ABI_ELFv2)
|
||||
return 28;
|
||||
#else
|
||||
return 40;
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@ -3674,6 +3678,10 @@ encode %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
const address start_pc = __ pc();
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address entry= !($meth$$method) ? NULL : (address)$meth$$method;
|
||||
__ call_c(entry, relocInfo::runtime_call_type);
|
||||
#else
|
||||
// The function we're going to call.
|
||||
FunctionDescriptor fdtemp;
|
||||
const FunctionDescriptor* fd = !($meth$$method) ? &fdtemp : (FunctionDescriptor*)$meth$$method;
|
||||
@ -3684,6 +3692,7 @@ encode %{
|
||||
// Put entry, env, toc into the constant pool, this needs up to 3 constant
|
||||
// pool entries; call_c_using_toc will optimize the call.
|
||||
__ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc);
|
||||
#endif
|
||||
|
||||
// Check the ret_addr_offset.
|
||||
assert(((MachCallRuntimeNode*)this)->ret_addr_offset() == __ last_calls_return_pc() - start_pc,
|
||||
@ -3699,20 +3708,25 @@ encode %{
|
||||
__ mtctr($src$$Register);
|
||||
%}
|
||||
|
||||
// postalloc expand emitter for runtime leaf calls.
|
||||
// Postalloc expand emitter for runtime leaf calls.
|
||||
enc_class postalloc_expand_java_to_runtime_call(method meth, iRegLdst toc) %{
|
||||
loadConLNodesTuple loadConLNodes_Entry;
|
||||
#if defined(ABI_ELFv2)
|
||||
jlong entry_address = (jlong) this->entry_point();
|
||||
assert(entry_address, "need address here");
|
||||
loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper(entry_address),
|
||||
OptoReg::Name(R12_H_num), OptoReg::Name(R12_num));
|
||||
#else
|
||||
// Get the struct that describes the function we are about to call.
|
||||
FunctionDescriptor* fd = (FunctionDescriptor*) this->entry_point();
|
||||
assert(fd, "need fd here");
|
||||
jlong entry_address = (jlong) fd->entry();
|
||||
// new nodes
|
||||
loadConLNodesTuple loadConLNodes_Entry;
|
||||
loadConLNodesTuple loadConLNodes_Env;
|
||||
loadConLNodesTuple loadConLNodes_Toc;
|
||||
MachNode *mtctr = NULL;
|
||||
MachCallLeafNode *call = NULL;
|
||||
|
||||
// Create nodes and operands for loading the entry point.
|
||||
loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper((jlong) fd->entry()),
|
||||
loadConLNodes_Entry = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper(entry_address),
|
||||
OptoReg::Name(R12_H_num), OptoReg::Name(R12_num));
|
||||
|
||||
|
||||
@ -3733,8 +3747,9 @@ encode %{
|
||||
// Create nodes and operands for loading the Toc point.
|
||||
loadConLNodes_Toc = loadConLNodesTuple_create(C, ra_, n_toc, new (C) immLOper((jlong) fd->toc()),
|
||||
OptoReg::Name(R2_H_num), OptoReg::Name(R2_num));
|
||||
#endif // ABI_ELFv2
|
||||
// mtctr node
|
||||
mtctr = new (C) CallLeafDirect_mtctrNode();
|
||||
MachNode *mtctr = new (C) CallLeafDirect_mtctrNode();
|
||||
|
||||
assert(loadConLNodes_Entry._last != NULL, "entry must exist");
|
||||
mtctr->add_req(0, loadConLNodes_Entry._last);
|
||||
@ -3743,10 +3758,10 @@ encode %{
|
||||
mtctr->_opnds[1] = new (C) iRegLdstOper();
|
||||
|
||||
// call node
|
||||
call = new (C) CallLeafDirectNode();
|
||||
MachCallLeafNode *call = new (C) CallLeafDirectNode();
|
||||
|
||||
call->_opnds[0] = _opnds[0];
|
||||
call->_opnds[1] = new (C) methodOper((intptr_t) fd->entry()); // may get set later
|
||||
call->_opnds[1] = new (C) methodOper((intptr_t) entry_address); // May get set later.
|
||||
|
||||
// Make the new call node look like the old one.
|
||||
call->_name = _name;
|
||||
@ -3773,8 +3788,10 @@ encode %{
|
||||
// These must be reqired edges, as the registers are live up to
|
||||
// the call. Else the constants are handled as kills.
|
||||
call->add_req(mtctr);
|
||||
#if !defined(ABI_ELFv2)
|
||||
call->add_req(loadConLNodes_Env._last);
|
||||
call->add_req(loadConLNodes_Toc._last);
|
||||
#endif
|
||||
|
||||
// ...as well as prec
|
||||
for (uint i = req(); i < len(); ++i) {
|
||||
@ -3787,10 +3804,12 @@ encode %{
|
||||
// Insert the new nodes.
|
||||
if (loadConLNodes_Entry._large_hi) nodes->push(loadConLNodes_Entry._large_hi);
|
||||
if (loadConLNodes_Entry._last) nodes->push(loadConLNodes_Entry._last);
|
||||
#if !defined(ABI_ELFv2)
|
||||
if (loadConLNodes_Env._large_hi) nodes->push(loadConLNodes_Env._large_hi);
|
||||
if (loadConLNodes_Env._last) nodes->push(loadConLNodes_Env._last);
|
||||
if (loadConLNodes_Toc._large_hi) nodes->push(loadConLNodes_Toc._large_hi);
|
||||
if (loadConLNodes_Toc._last) nodes->push(loadConLNodes_Toc._last);
|
||||
#endif
|
||||
nodes->push(mtctr);
|
||||
nodes->push(call);
|
||||
%}
|
||||
@ -3837,7 +3856,7 @@ frame %{
|
||||
// out_preserve_stack_slots for calls to C. Supports the var-args
|
||||
// backing area for register parms.
|
||||
//
|
||||
varargs_C_out_slots_killed(((frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size));
|
||||
varargs_C_out_slots_killed(((frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size));
|
||||
|
||||
// The after-PROLOG location of the return address. Location of
|
||||
// return address specifies a type (REG or STACK) and a number
|
||||
|
@ -87,7 +87,7 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
address start = __ pc();
|
||||
|
||||
int frame_size_in_bytes = frame::abi_112_size;
|
||||
int frame_size_in_bytes = frame::abi_reg_args_size;
|
||||
OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
|
||||
|
||||
// Exception pc is 'return address' for stack walker.
|
||||
@ -99,7 +99,7 @@ void OptoRuntime::generate_exception_blob() {
|
||||
|
||||
// Save callee-saved registers.
|
||||
// Push a C frame for the exception blob. It is needed for the C call later on.
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
|
||||
// This call does all the hard work. It checks if an exception handler
|
||||
// exists in the method.
|
||||
@ -109,8 +109,12 @@ void OptoRuntime::generate_exception_blob() {
|
||||
__ set_last_Java_frame(/*sp=*/R1_SP, noreg);
|
||||
|
||||
__ mr(R3_ARG1, R16_thread);
|
||||
#if defined(ABI_ELFv2)
|
||||
__ call_c((address) OptoRuntime::handle_exception_C, relocInfo::none);
|
||||
#else
|
||||
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, OptoRuntime::handle_exception_C),
|
||||
relocInfo::none);
|
||||
#endif
|
||||
address calls_return_pc = __ last_calls_return_pc();
|
||||
# ifdef ASSERT
|
||||
__ cmpdi(CCR0, R3_RET, 0);
|
||||
@ -162,7 +166,11 @@ void OptoRuntime::generate_exception_blob() {
|
||||
__ bind(mh_callsite);
|
||||
__ mr(R31, R3_RET); // Save branch address.
|
||||
__ mr(R3_ARG1, R16_thread);
|
||||
#if defined(ABI_ELFv2)
|
||||
__ call_c((address) adjust_SP_for_methodhandle_callsite, relocInfo::none);
|
||||
#else
|
||||
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, adjust_SP_for_methodhandle_callsite), relocInfo::none);
|
||||
#endif
|
||||
// Returns unextended_sp in R3_RET.
|
||||
|
||||
__ mtctr(R31); // Move address of exception handler to SR_CTR.
|
||||
|
@ -67,7 +67,7 @@ class RegisterSaver {
|
||||
return_pc_is_thread_saved_exception_pc
|
||||
};
|
||||
|
||||
static OopMap* push_frame_abi112_and_save_live_registers(MacroAssembler* masm,
|
||||
static OopMap* push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
|
||||
int* out_frame_size_in_bytes,
|
||||
bool generate_oop_map,
|
||||
int return_pc_adjustment,
|
||||
@ -200,12 +200,12 @@ static const RegisterSaver::LiveRegType RegisterSaver_LiveRegs[] = {
|
||||
RegisterSaver_LiveIntReg( R30 ), // r30 must be the last register
|
||||
};
|
||||
|
||||
OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler* masm,
|
||||
OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssembler* masm,
|
||||
int* out_frame_size_in_bytes,
|
||||
bool generate_oop_map,
|
||||
int return_pc_adjustment,
|
||||
ReturnPCLocation return_pc_location) {
|
||||
// Push an abi112-frame and store all registers which may be live.
|
||||
// Push an abi_reg_args-frame and store all registers which may be live.
|
||||
// If requested, create an OopMap: Record volatile registers as
|
||||
// callee-save values in an OopMap so their save locations will be
|
||||
// propagated to the RegisterMap of the caller frame during
|
||||
@ -221,7 +221,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler*
|
||||
sizeof(RegisterSaver::LiveRegType);
|
||||
const int register_save_size = regstosave_num * reg_size;
|
||||
const int frame_size_in_bytes = round_to(register_save_size, frame::alignment_in_bytes)
|
||||
+ frame::abi_112_size;
|
||||
+ frame::abi_reg_args_size;
|
||||
*out_frame_size_in_bytes = frame_size_in_bytes;
|
||||
const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
|
||||
const int register_save_offset = frame_size_in_bytes - register_save_size;
|
||||
@ -229,7 +229,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler*
|
||||
// OopMap frame size is in c2 stack slots (sizeof(jint)) not bytes or words.
|
||||
OopMap* map = generate_oop_map ? new OopMap(frame_size_in_slots, 0) : NULL;
|
||||
|
||||
BLOCK_COMMENT("push_frame_abi112_and_save_live_registers {");
|
||||
BLOCK_COMMENT("push_frame_reg_args_and_save_live_registers {");
|
||||
|
||||
// Save r30 in the last slot of the not yet pushed frame so that we
|
||||
// can use it as scratch reg.
|
||||
@ -294,7 +294,7 @@ OopMap* RegisterSaver::push_frame_abi112_and_save_live_registers(MacroAssembler*
|
||||
offset += reg_size;
|
||||
}
|
||||
|
||||
BLOCK_COMMENT("} push_frame_abi112_and_save_live_registers");
|
||||
BLOCK_COMMENT("} push_frame_reg_args_and_save_live_registers");
|
||||
|
||||
// And we're done.
|
||||
return map;
|
||||
@ -699,15 +699,19 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
|
||||
int i;
|
||||
VMReg reg;
|
||||
// Leave room for C-compatible ABI_112.
|
||||
int stk = (frame::abi_112_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size;
|
||||
// Leave room for C-compatible ABI_REG_ARGS.
|
||||
int stk = (frame::abi_reg_args_size - frame::jit_out_preserve_size) / VMRegImpl::stack_slot_size;
|
||||
int arg = 0;
|
||||
int freg = 0;
|
||||
|
||||
// Avoid passing C arguments in the wrong stack slots.
|
||||
#if defined(ABI_ELFv2)
|
||||
assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 96,
|
||||
"passing C arguments in wrong stack slots");
|
||||
#else
|
||||
assert((SharedRuntime::out_preserve_stack_slots() + stk) * VMRegImpl::stack_slot_size == 112,
|
||||
"passing C arguments in wrong stack slots");
|
||||
|
||||
#endif
|
||||
// We fill-out regs AND regs2 if an argument must be passed in a
|
||||
// register AND in a stack slot. If regs2 is NULL in such a
|
||||
// situation, we bail-out with a fatal error.
|
||||
@ -1504,7 +1508,11 @@ static void check_needs_gc_for_critical_native(MacroAssembler* masm,
|
||||
|
||||
__ block_comment("block_for_jni_critical");
|
||||
address entry_point = CAST_FROM_FN_PTR(address, SharedRuntime::block_for_jni_critical);
|
||||
#if defined(ABI_ELFv2)
|
||||
__ call_c(entry_point, relocInfo::runtime_call_type);
|
||||
#else
|
||||
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, entry_point), relocInfo::runtime_call_type);
|
||||
#endif
|
||||
address start = __ pc() - __ offset(),
|
||||
calls_return_pc = __ last_calls_return_pc();
|
||||
oop_maps->add_gc_map(calls_return_pc - start, map);
|
||||
@ -1877,7 +1885,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
// Layout of the native wrapper frame:
|
||||
// (stack grows upwards, memory grows downwards)
|
||||
//
|
||||
// NW [ABI_112] <-- 1) R1_SP
|
||||
// NW [ABI_REG_ARGS] <-- 1) R1_SP
|
||||
// [outgoing arguments] <-- 2) R1_SP + out_arg_slot_offset
|
||||
// [oopHandle area] <-- 3) R1_SP + oop_handle_offset (save area for critical natives)
|
||||
// klass <-- 4) R1_SP + klass_offset
|
||||
@ -2211,8 +2219,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
// slow case of monitor enter. Inline a special case of call_VM that
|
||||
// disallows any pending_exception.
|
||||
|
||||
// Save argument registers and leave room for C-compatible ABI_112.
|
||||
int frame_size = frame::abi_112_size +
|
||||
// Save argument registers and leave room for C-compatible ABI_REG_ARGS.
|
||||
int frame_size = frame::abi_reg_args_size +
|
||||
round_to(total_c_args * wordSize, frame::alignment_in_bytes);
|
||||
__ mr(R11_scratch1, R1_SP);
|
||||
RegisterSaver::push_frame_and_save_argument_registers(masm, R12_scratch2, frame_size, total_c_args, out_regs, out_regs2);
|
||||
@ -2250,9 +2258,12 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
|
||||
// The JNI call
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
__ call_c(native_func, relocInfo::runtime_call_type);
|
||||
#else
|
||||
FunctionDescriptor* fd_native_method = (FunctionDescriptor*) native_func;
|
||||
__ call_c(fd_native_method, relocInfo::runtime_call_type);
|
||||
#endif
|
||||
|
||||
|
||||
// Now, we are back from the native code.
|
||||
@ -2724,7 +2735,7 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
OopMapSet *oop_maps = new OopMapSet();
|
||||
|
||||
// size of ABI112 plus spill slots for R3_RET and F1_RET.
|
||||
const int frame_size_in_bytes = frame::abi_112_spill_size;
|
||||
const int frame_size_in_bytes = frame::abi_reg_args_spill_size;
|
||||
const int frame_size_in_slots = frame_size_in_bytes / sizeof(jint);
|
||||
int first_frame_size_in_bytes = 0; // frame size of "unpack frame" for call to fetch_unroll_info.
|
||||
|
||||
@ -2757,11 +2768,11 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
|
||||
// Push the "unpack frame"
|
||||
// Save everything in sight.
|
||||
map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
|
||||
&first_frame_size_in_bytes,
|
||||
/*generate_oop_map=*/ true,
|
||||
return_pc_adjustment_no_exception,
|
||||
RegisterSaver::return_pc_is_lr);
|
||||
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
|
||||
&first_frame_size_in_bytes,
|
||||
/*generate_oop_map=*/ true,
|
||||
return_pc_adjustment_no_exception,
|
||||
RegisterSaver::return_pc_is_lr);
|
||||
assert(map != NULL, "OopMap must have been created");
|
||||
|
||||
__ li(exec_mode_reg, Deoptimization::Unpack_deopt);
|
||||
@ -2787,11 +2798,11 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// Push the "unpack frame".
|
||||
// Save everything in sight.
|
||||
assert(R4 == R4_ARG2, "exception pc must be in r4");
|
||||
RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
|
||||
&first_frame_size_in_bytes,
|
||||
/*generate_oop_map=*/ false,
|
||||
return_pc_adjustment_exception,
|
||||
RegisterSaver::return_pc_is_r4);
|
||||
RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
|
||||
&first_frame_size_in_bytes,
|
||||
/*generate_oop_map=*/ false,
|
||||
return_pc_adjustment_exception,
|
||||
RegisterSaver::return_pc_is_r4);
|
||||
|
||||
// Deopt during an exception. Save exec mode for unpack_frames.
|
||||
__ li(exec_mode_reg, Deoptimization::Unpack_exception);
|
||||
@ -2876,8 +2887,8 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
// ...).
|
||||
|
||||
// Spill live volatile registers since we'll do a call.
|
||||
__ std( R3_RET, _abi_112_spill(spill_ret), R1_SP);
|
||||
__ stfd(F1_RET, _abi_112_spill(spill_fret), R1_SP);
|
||||
__ std( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP);
|
||||
__ stfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP);
|
||||
|
||||
// Let the unpacker layout information in the skeletal frames just
|
||||
// allocated.
|
||||
@ -2889,8 +2900,8 @@ void SharedRuntime::generate_deopt_blob() {
|
||||
__ reset_last_Java_frame();
|
||||
|
||||
// Restore the volatiles saved above.
|
||||
__ ld( R3_RET, _abi_112_spill(spill_ret), R1_SP);
|
||||
__ lfd(F1_RET, _abi_112_spill(spill_fret), R1_SP);
|
||||
__ ld( R3_RET, _abi_reg_args_spill(spill_ret), R1_SP);
|
||||
__ lfd(F1_RET, _abi_reg_args_spill(spill_fret), R1_SP);
|
||||
|
||||
// Pop the unpack frame.
|
||||
__ pop_frame();
|
||||
@ -2930,7 +2941,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
|
||||
Register unc_trap_reg = R23_tmp3;
|
||||
|
||||
OopMapSet* oop_maps = new OopMapSet();
|
||||
int frame_size_in_bytes = frame::abi_112_size;
|
||||
int frame_size_in_bytes = frame::abi_reg_args_size;
|
||||
OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
|
||||
|
||||
// stack: (deoptee, optional i2c, caller_of_deoptee, ...).
|
||||
@ -2943,7 +2954,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
|
||||
__ save_LR_CR(R11_scratch1);
|
||||
|
||||
// Push an "uncommon_trap" frame.
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
|
||||
// stack: (unpack frame, deoptee, optional i2c, caller_of_deoptee, ...).
|
||||
|
||||
@ -2996,7 +3007,7 @@ void SharedRuntime::generate_uncommon_trap_blob() {
|
||||
// interpreter frames just created.
|
||||
|
||||
// Push a simple "unpack frame" here.
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
|
||||
// stack: (unpack frame, skeletal interpreter frame, ..., optional
|
||||
// skeletal interpreter frame, optional c2i, caller of deoptee,
|
||||
@ -3064,11 +3075,11 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
|
||||
}
|
||||
|
||||
// Save registers, fpu state, and flags.
|
||||
map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
|
||||
&frame_size_in_bytes,
|
||||
/*generate_oop_map=*/ true,
|
||||
/*return_pc_adjustment=*/0,
|
||||
return_pc_location);
|
||||
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
|
||||
&frame_size_in_bytes,
|
||||
/*generate_oop_map=*/ true,
|
||||
/*return_pc_adjustment=*/0,
|
||||
return_pc_location);
|
||||
|
||||
// The following is basically a call_VM. However, we need the precise
|
||||
// address of the call in order to generate an oopmap. Hence, we do all the
|
||||
@ -3151,11 +3162,11 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
|
||||
|
||||
address start = __ pc();
|
||||
|
||||
map = RegisterSaver::push_frame_abi112_and_save_live_registers(masm,
|
||||
&frame_size_in_bytes,
|
||||
/*generate_oop_map*/ true,
|
||||
/*return_pc_adjustment*/ 0,
|
||||
RegisterSaver::return_pc_is_lr);
|
||||
map = RegisterSaver::push_frame_reg_args_and_save_live_registers(masm,
|
||||
&frame_size_in_bytes,
|
||||
/*generate_oop_map*/ true,
|
||||
/*return_pc_adjustment*/ 0,
|
||||
RegisterSaver::return_pc_is_lr);
|
||||
|
||||
// Use noreg as last_Java_pc, the return pc will be reconstructed
|
||||
// from the physical frame.
|
||||
|
@ -79,11 +79,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
StubCodeMark mark(this, "StubRoutines", "call_stub");
|
||||
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
// some sanity checks
|
||||
assert((sizeof(frame::abi_48) % 16) == 0, "unaligned");
|
||||
assert((sizeof(frame::abi_112) % 16) == 0, "unaligned");
|
||||
assert((sizeof(frame::abi_minframe) % 16) == 0, "unaligned");
|
||||
assert((sizeof(frame::abi_reg_args) % 16) == 0, "unaligned");
|
||||
assert((sizeof(frame::spill_nonvolatiles) % 16) == 0, "unaligned");
|
||||
assert((sizeof(frame::parent_ijava_frame_abi) % 16) == 0, "unaligned");
|
||||
assert((sizeof(frame::entry_frame_locals) % 16) == 0, "unaligned");
|
||||
@ -444,7 +444,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
// Save LR/CR and copy exception pc (LR) into R4_ARG2.
|
||||
__ save_LR_CR(R4_ARG2);
|
||||
__ push_frame_abi112(0, R0);
|
||||
__ push_frame_reg_args(0, R0);
|
||||
// Find exception handler.
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::exception_handler_for_return_address),
|
||||
@ -519,7 +519,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
MacroAssembler* masm = new MacroAssembler(&code);
|
||||
|
||||
OopMapSet* oop_maps = new OopMapSet();
|
||||
int frame_size_in_bytes = frame::abi_112_size;
|
||||
int frame_size_in_bytes = frame::abi_reg_args_size;
|
||||
OopMap* map = new OopMap(frame_size_in_bytes / sizeof(jint), 0);
|
||||
|
||||
StubCodeMark mark(this, "StubRoutines", "throw_exception");
|
||||
@ -529,7 +529,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ save_LR_CR(R11_scratch1);
|
||||
|
||||
// Push a frame.
|
||||
__ push_frame_abi112(0, R11_scratch1);
|
||||
__ push_frame_reg_args(0, R11_scratch1);
|
||||
|
||||
address frame_complete_pc = __ pc();
|
||||
|
||||
@ -551,8 +551,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
if (arg2 != noreg) {
|
||||
__ mr(R5_ARG3, arg2);
|
||||
}
|
||||
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry),
|
||||
relocInfo::none);
|
||||
#if defined(ABI_ELFv2)
|
||||
__ call_c(runtime_entry, relocInfo::none);
|
||||
#else
|
||||
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, runtime_entry), relocInfo::none);
|
||||
#endif
|
||||
|
||||
// Set an oopmap for the call site.
|
||||
oop_maps->add_gc_map((int)(gc_map_pc - start), map);
|
||||
@ -614,7 +617,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// With G1, don't generate the call if we statically know that the target in uninitialized
|
||||
if (!dest_uninitialized) {
|
||||
const int spill_slots = 4 * wordSize;
|
||||
const int frame_size = frame::abi_112_size + spill_slots;
|
||||
const int frame_size = frame::abi_reg_args_size + spill_slots;
|
||||
Label filtered;
|
||||
|
||||
// Is marking active?
|
||||
@ -628,7 +631,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ beq(CCR0, filtered);
|
||||
|
||||
__ save_LR_CR(R0);
|
||||
__ push_frame_abi112(spill_slots, R0);
|
||||
__ push_frame_reg_args(spill_slots, R0);
|
||||
__ std(from, frame_size - 1 * wordSize, R1_SP);
|
||||
__ std(to, frame_size - 2 * wordSize, R1_SP);
|
||||
__ std(count, frame_size - 3 * wordSize, R1_SP);
|
||||
@ -672,7 +675,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
if (branchToEnd) {
|
||||
__ save_LR_CR(R0);
|
||||
// We need this frame only to spill LR.
|
||||
__ push_frame_abi112(0, R0);
|
||||
__ push_frame_reg_args(0, R0);
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count);
|
||||
__ pop_frame();
|
||||
__ restore_LR_CR(R0);
|
||||
@ -742,7 +745,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubCodeMark mark(this, "StubRoutines", "zero_words_aligned8");
|
||||
|
||||
// Implemented as in ClearArray.
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
Register base_ptr_reg = R3_ARG1; // tohw (needs to be 8b aligned)
|
||||
Register cnt_dwords_reg = R4_ARG2; // count (in dwords)
|
||||
@ -820,7 +823,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_handler_for_unsafe_access() {
|
||||
StubCodeMark mark(this, "StubRoutines", "handler_for_unsafe_access");
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
__ unimplemented("StubRoutines::handler_for_unsafe_access", 93);
|
||||
return start;
|
||||
}
|
||||
@ -861,7 +864,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// to read from the safepoint polling page.
|
||||
address generate_load_from_poll() {
|
||||
StubCodeMark mark(this, "StubRoutines", "generate_load_from_poll");
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
__ unimplemented("StubRoutines::verify_oop", 95); // TODO PPC port
|
||||
return start;
|
||||
}
|
||||
@ -885,7 +888,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_fill(BasicType t, bool aligned, const char* name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
const Register to = R3_ARG1; // source array address
|
||||
const Register value = R4_ARG2; // fill value
|
||||
@ -1123,7 +1126,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_disjoint_byte_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
Register tmp1 = R6_ARG4;
|
||||
Register tmp2 = R7_ARG5;
|
||||
@ -1254,15 +1257,21 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_conjoint_byte_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
Register tmp1 = R6_ARG4;
|
||||
Register tmp2 = R7_ARG5;
|
||||
Register tmp3 = R8_ARG6;
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address nooverlap_target = aligned ?
|
||||
StubRoutines::arrayof_jbyte_disjoint_arraycopy() :
|
||||
StubRoutines::jbyte_disjoint_arraycopy();
|
||||
#else
|
||||
address nooverlap_target = aligned ?
|
||||
((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() :
|
||||
((FunctionDescriptor*)StubRoutines::jbyte_disjoint_arraycopy())->entry();
|
||||
#endif
|
||||
|
||||
array_overlap_test(nooverlap_target, 0);
|
||||
// Do reverse copy. We assume the case of actual overlap is rare enough
|
||||
@ -1345,7 +1354,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
Register tmp3 = R8_ARG6;
|
||||
Register tmp4 = R9_ARG7;
|
||||
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
Label l_1, l_2, l_3, l_4, l_5, l_6, l_7, l_8;
|
||||
// don't try anything fancy if arrays don't have many elements
|
||||
@ -1474,15 +1483,21 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_conjoint_short_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
Register tmp1 = R6_ARG4;
|
||||
Register tmp2 = R7_ARG5;
|
||||
Register tmp3 = R8_ARG6;
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address nooverlap_target = aligned ?
|
||||
StubRoutines::arrayof_jshort_disjoint_arraycopy() :
|
||||
StubRoutines::jshort_disjoint_arraycopy();
|
||||
#else
|
||||
address nooverlap_target = aligned ?
|
||||
((FunctionDescriptor*)StubRoutines::arrayof_jshort_disjoint_arraycopy())->entry() :
|
||||
((FunctionDescriptor*)StubRoutines::jshort_disjoint_arraycopy())->entry();
|
||||
#endif
|
||||
|
||||
array_overlap_test(nooverlap_target, 1);
|
||||
|
||||
@ -1597,7 +1612,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_disjoint_int_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
generate_disjoint_int_copy_core(aligned);
|
||||
__ blr();
|
||||
return start;
|
||||
@ -1681,11 +1696,17 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_conjoint_int_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address nooverlap_target = aligned ?
|
||||
StubRoutines::arrayof_jint_disjoint_arraycopy() :
|
||||
StubRoutines::jint_disjoint_arraycopy();
|
||||
#else
|
||||
address nooverlap_target = aligned ?
|
||||
((FunctionDescriptor*)StubRoutines::arrayof_jint_disjoint_arraycopy())->entry() :
|
||||
((FunctionDescriptor*)StubRoutines::jint_disjoint_arraycopy())->entry();
|
||||
#endif
|
||||
|
||||
array_overlap_test(nooverlap_target, 2);
|
||||
|
||||
@ -1767,7 +1788,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_disjoint_long_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
generate_disjoint_long_copy_core(aligned);
|
||||
__ blr();
|
||||
|
||||
@ -1849,11 +1870,17 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_conjoint_long_copy(bool aligned, const char * name) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address nooverlap_target = aligned ?
|
||||
StubRoutines::arrayof_jlong_disjoint_arraycopy() :
|
||||
StubRoutines::jlong_disjoint_arraycopy();
|
||||
#else
|
||||
address nooverlap_target = aligned ?
|
||||
((FunctionDescriptor*)StubRoutines::arrayof_jlong_disjoint_arraycopy())->entry() :
|
||||
((FunctionDescriptor*)StubRoutines::jlong_disjoint_arraycopy())->entry();
|
||||
#endif
|
||||
|
||||
array_overlap_test(nooverlap_target, 3);
|
||||
generate_conjoint_long_copy_core(aligned);
|
||||
@ -1875,11 +1902,17 @@ class StubGenerator: public StubCodeGenerator {
|
||||
address generate_conjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
#if defined(ABI_ELFv2)
|
||||
address nooverlap_target = aligned ?
|
||||
StubRoutines::arrayof_oop_disjoint_arraycopy() :
|
||||
StubRoutines::oop_disjoint_arraycopy();
|
||||
#else
|
||||
address nooverlap_target = aligned ?
|
||||
((FunctionDescriptor*)StubRoutines::arrayof_oop_disjoint_arraycopy())->entry() :
|
||||
((FunctionDescriptor*)StubRoutines::oop_disjoint_arraycopy())->entry();
|
||||
#endif
|
||||
|
||||
gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7);
|
||||
|
||||
@ -1910,7 +1943,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
//
|
||||
address generate_disjoint_oop_copy(bool aligned, const char * name, bool dest_uninitialized) {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ emit_fd();
|
||||
address start = __ function_entry();
|
||||
|
||||
gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7);
|
||||
|
||||
@ -1991,7 +2024,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
|
||||
// Entry point, pc or function descriptor.
|
||||
*entry = __ emit_fd();
|
||||
*entry = __ function_entry();
|
||||
|
||||
// Load *adr into R4_ARG2, may fault.
|
||||
*fault_pc = __ pc();
|
||||
|
@ -24,7 +24,8 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "assembler_ppc.inline.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
@ -168,7 +169,7 @@ void VM_Version::determine_section_size() {
|
||||
|
||||
uint32_t *code = (uint32_t *)a->pc();
|
||||
// Emit code.
|
||||
void (*test1)() = (void(*)())(void *)a->emit_fd();
|
||||
void (*test1)() = (void(*)())(void *)a->function_entry();
|
||||
|
||||
Label l1;
|
||||
|
||||
@ -242,7 +243,7 @@ void VM_Version::determine_section_size() {
|
||||
a->blr();
|
||||
|
||||
// Emit code.
|
||||
void (*test2)() = (void(*)())(void *)a->emit_fd();
|
||||
void (*test2)() = (void(*)())(void *)a->function_entry();
|
||||
// uint32_t *code = (uint32_t *)a->pc();
|
||||
|
||||
Label l2;
|
||||
@ -383,8 +384,12 @@ void VM_Version::determine_section_size() {
|
||||
#endif // COMPILER2
|
||||
|
||||
void VM_Version::determine_features() {
|
||||
#if defined(ABI_ELFv2)
|
||||
const int code_size = (num_features+1+2*7)*BytesPerInstWord; // TODO(asmundak): calculation is incorrect.
|
||||
#else
|
||||
// 7 InstWords for each call (function descriptor + blr instruction).
|
||||
const int code_size = (num_features+1+2*7)*BytesPerInstWord;
|
||||
#endif
|
||||
int features = 0;
|
||||
|
||||
// create test area
|
||||
@ -398,7 +403,7 @@ void VM_Version::determine_features() {
|
||||
MacroAssembler* a = new MacroAssembler(&cb);
|
||||
|
||||
// Emit code.
|
||||
void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->emit_fd();
|
||||
void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry();
|
||||
uint32_t *code = (uint32_t *)a->pc();
|
||||
// Don't use R0 in ldarx.
|
||||
// Keep R3_ARG1 unmodified, it contains &field (see below).
|
||||
@ -415,7 +420,7 @@ void VM_Version::determine_features() {
|
||||
a->blr();
|
||||
|
||||
// Emit function to set one cache line to zero. Emit function descriptor and get pointer to it.
|
||||
void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->emit_fd();
|
||||
void (*zero_cacheline_func_ptr)(char*) = (void(*)(char*))(void *)a->function_entry();
|
||||
a->dcbz(R3_ARG1); // R3_ARG1 = addr
|
||||
a->blr();
|
||||
|
||||
|
@ -413,16 +413,15 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile
|
||||
// Update standard invocation counters
|
||||
__ increment_invocation_counter(Rcounters, O0, G4_scratch);
|
||||
if (ProfileInterpreter) {
|
||||
Address interpreter_invocation_counter(Rcounters, 0,
|
||||
Address interpreter_invocation_counter(Rcounters,
|
||||
in_bytes(MethodCounters::interpreter_invocation_counter_offset()));
|
||||
__ ld(interpreter_invocation_counter, G4_scratch);
|
||||
__ inc(G4_scratch);
|
||||
__ st(G4_scratch, interpreter_invocation_counter);
|
||||
}
|
||||
|
||||
Address invocation_limit(G3_scratch, (address)&InvocationCounter::InterpreterInvocationLimit);
|
||||
__ sethi(invocation_limit);
|
||||
__ ld(invocation_limit, G3_scratch);
|
||||
AddressLiteral invocation_limit((address)&InvocationCounter::InterpreterInvocationLimit);
|
||||
__ load_contents(invocation_limit, G3_scratch);
|
||||
__ cmp(O0, G3_scratch);
|
||||
__ br(Assembler::greaterEqualUnsigned, false, Assembler::pn, *overflow);
|
||||
__ delayed()->nop();
|
||||
@ -439,7 +438,7 @@ address InterpreterGenerator::generate_empty_entry(void) {
|
||||
// do nothing for empty methods (do not even increment invocation counter)
|
||||
if ( UseFastEmptyMethods) {
|
||||
// If we need a safepoint check, generate full interpreter entry.
|
||||
Address sync_state(G3_scratch, SafepointSynchronize::address_of_state());
|
||||
AddressLiteral sync_state(SafepointSynchronize::address_of_state());
|
||||
__ load_contents(sync_state, G3_scratch);
|
||||
__ cmp(G3_scratch, SafepointSynchronize::_not_synchronized);
|
||||
__ br(Assembler::notEqual, false, Assembler::pn, frame_manager_entry);
|
||||
@ -471,7 +470,7 @@ address InterpreterGenerator::generate_accessor_entry(void) {
|
||||
if ( UseFastAccessorMethods) {
|
||||
// Check if we need to reach a safepoint and generate full interpreter
|
||||
// frame if so.
|
||||
Address sync_state(G3_scratch, SafepointSynchronize::address_of_state());
|
||||
AddressLiteral sync_state(SafepointSynchronize::address_of_state());
|
||||
__ load_contents(sync_state, G3_scratch);
|
||||
__ cmp(G3_scratch, SafepointSynchronize::_not_synchronized);
|
||||
__ br(Assembler::notEqual, false, Assembler::pn, slow_path);
|
||||
@ -486,8 +485,8 @@ address InterpreterGenerator::generate_accessor_entry(void) {
|
||||
|
||||
// read first instruction word and extract bytecode @ 1 and index @ 2
|
||||
// get first 4 bytes of the bytecodes (big endian!)
|
||||
__ ld_ptr(Address(G5_method, 0, in_bytes(Method::const_offset())), G1_scratch);
|
||||
__ ld(Address(G1_scratch, 0, in_bytes(ConstMethod::codes_offset())), G1_scratch);
|
||||
__ ld_ptr(Address(G5_method, in_bytes(Method::const_offset())), G1_scratch);
|
||||
__ ld(Address(G1_scratch, in_bytes(ConstMethod::codes_offset())), G1_scratch);
|
||||
|
||||
// move index @ 2 far left then to the right most two bytes.
|
||||
__ sll(G1_scratch, 2*BitsPerByte, G1_scratch);
|
||||
@ -590,15 +589,15 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
const Register Gtmp1 = G3_scratch ;
|
||||
const Register Gtmp2 = G1_scratch;
|
||||
const Register RconstMethod = Gtmp1;
|
||||
const Address constMethod(G5_method, 0, in_bytes(Method::const_offset()));
|
||||
const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
const Address constMethod(G5_method, in_bytes(Method::const_offset()));
|
||||
const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
|
||||
bool inc_counter = UseCompiler || CountCompiledCalls;
|
||||
|
||||
// make sure registers are different!
|
||||
assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
|
||||
|
||||
const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
|
||||
const Address access_flags (G5_method, in_bytes(Method::access_flags_offset()));
|
||||
|
||||
Label Lentry;
|
||||
__ bind(Lentry);
|
||||
@ -643,7 +642,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
// At this point Lstate points to new interpreter state
|
||||
//
|
||||
|
||||
const Address do_not_unlock_if_synchronized(G2_thread, 0,
|
||||
const Address do_not_unlock_if_synchronized(G2_thread,
|
||||
in_bytes(JavaThread::do_not_unlock_if_synchronized_offset()));
|
||||
// Since at this point in the method invocation the exception handler
|
||||
// would try to exit the monitor of synchronized methods which hasn't
|
||||
@ -717,17 +716,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
|
||||
{ Label L;
|
||||
__ ld_ptr(STATE(_method), G5_method);
|
||||
__ ld_ptr(Address(G5_method, 0, in_bytes(Method::signature_handler_offset())), G3_scratch);
|
||||
__ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch);
|
||||
__ tst(G3_scratch);
|
||||
__ brx(Assembler::notZero, false, Assembler::pt, L);
|
||||
__ delayed()->nop();
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), G5_method, false);
|
||||
__ ld_ptr(STATE(_method), G5_method);
|
||||
|
||||
Address exception_addr(G2_thread, 0, in_bytes(Thread::pending_exception_offset()));
|
||||
Address exception_addr(G2_thread, in_bytes(Thread::pending_exception_offset()));
|
||||
__ ld_ptr(exception_addr, G3_scratch);
|
||||
__ br_notnull_short(G3_scratch, Assembler::pn, pending_exception_present);
|
||||
__ ld_ptr(Address(G5_method, 0, in_bytes(Method::signature_handler_offset())), G3_scratch);
|
||||
__ ld_ptr(Address(G5_method, in_bytes(Method::signature_handler_offset())), G3_scratch);
|
||||
__ bind(L);
|
||||
}
|
||||
|
||||
@ -771,13 +770,13 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
__ br( Assembler::zero, false, Assembler::pt, not_static);
|
||||
__ delayed()->
|
||||
// get native function entry point(O0 is a good temp until the very end)
|
||||
ld_ptr(Address(G5_method, 0, in_bytes(Method::native_function_offset())), O0);
|
||||
ld_ptr(Address(G5_method, in_bytes(Method::native_function_offset())), O0);
|
||||
// for static methods insert the mirror argument
|
||||
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
|
||||
|
||||
__ ld_ptr(Address(G5_method, 0, in_bytes(Method:: const_offset())), O1);
|
||||
__ ld_ptr(Address(O1, 0, in_bytes(ConstMethod::constants_offset())), O1);
|
||||
__ ld_ptr(Address(O1, 0, ConstantPool::pool_holder_offset_in_bytes()), O1);
|
||||
__ ld_ptr(Address(G5_method, in_bytes(Method:: const_offset())), O1);
|
||||
__ ld_ptr(Address(O1, in_bytes(ConstMethod::constants_offset())), O1);
|
||||
__ ld_ptr(Address(O1, ConstantPool::pool_holder_offset_in_bytes()), O1);
|
||||
__ ld_ptr(O1, mirror_offset, O1);
|
||||
// where the mirror handle body is allocated:
|
||||
#ifdef ASSERT
|
||||
@ -831,18 +830,17 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
// flush the windows now. We don't care about the current (protection) frame
|
||||
// only the outer frames
|
||||
|
||||
__ flush_windows();
|
||||
__ flushw();
|
||||
|
||||
// mark windows as flushed
|
||||
Address flags(G2_thread,
|
||||
0,
|
||||
in_bytes(JavaThread::frame_anchor_offset()) + in_bytes(JavaFrameAnchor::flags_offset()));
|
||||
__ set(JavaFrameAnchor::flushed, G3_scratch);
|
||||
__ st(G3_scratch, flags);
|
||||
|
||||
// Transition from _thread_in_Java to _thread_in_native. We are already safepoint ready.
|
||||
|
||||
Address thread_state(G2_thread, 0, in_bytes(JavaThread::thread_state_offset()));
|
||||
Address thread_state(G2_thread, in_bytes(JavaThread::thread_state_offset()));
|
||||
#ifdef ASSERT
|
||||
{ Label L;
|
||||
__ ld(thread_state, G3_scratch);
|
||||
@ -867,7 +865,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
// Block, if necessary, before resuming in _thread_in_Java state.
|
||||
// In order for GC to work, don't clear the last_Java_sp until after blocking.
|
||||
{ Label no_block;
|
||||
Address sync_state(G3_scratch, SafepointSynchronize::address_of_state());
|
||||
AddressLiteral sync_state(SafepointSynchronize::address_of_state());
|
||||
|
||||
// Switch thread to "native transition" state before reading the synchronization state.
|
||||
// This additional state is necessary because reading and testing the synchronization
|
||||
@ -890,7 +888,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
|
||||
|
||||
Label L;
|
||||
Address suspend_state(G2_thread, 0, in_bytes(JavaThread::suspend_flags_offset()));
|
||||
Address suspend_state(G2_thread, in_bytes(JavaThread::suspend_flags_offset()));
|
||||
__ br(Assembler::notEqual, false, Assembler::pn, L);
|
||||
__ delayed()->
|
||||
ld(suspend_state, G3_scratch);
|
||||
@ -965,7 +963,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
|
||||
// handle exceptions (exception handling will handle unlocking!)
|
||||
{ Label L;
|
||||
Address exception_addr (G2_thread, 0, in_bytes(Thread::pending_exception_offset()));
|
||||
Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset()));
|
||||
|
||||
__ ld_ptr(exception_addr, Gtemp);
|
||||
__ tst(Gtemp);
|
||||
@ -1055,8 +1053,8 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
assert_different_registers(state, prev_state);
|
||||
assert_different_registers(prev_state, G3_scratch);
|
||||
const Register Gtmp = G3_scratch;
|
||||
const Address constMethod (G5_method, 0, in_bytes(Method::const_offset()));
|
||||
const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
|
||||
const Address constMethod (G5_method, in_bytes(Method::const_offset()));
|
||||
const Address access_flags (G5_method, in_bytes(Method::access_flags_offset()));
|
||||
|
||||
// slop factor is two extra slots on the expression stack so that
|
||||
// we always have room to store a result when returning from a call without parameters
|
||||
@ -1075,7 +1073,7 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
|
||||
if (native) {
|
||||
const Register RconstMethod = Gtmp;
|
||||
const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
__ ld_ptr(constMethod, RconstMethod);
|
||||
__ lduh( size_of_parameters, Gtmp );
|
||||
__ calc_mem_param_words(Gtmp, Gtmp); // space for native call parameters passed on the stack in words
|
||||
@ -1246,8 +1244,8 @@ void CppInterpreterGenerator::generate_compute_interpreter_state(const Register
|
||||
if (init_value != noreg) {
|
||||
Label clear_loop;
|
||||
const Register RconstMethod = O1;
|
||||
const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset()));
|
||||
const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset()));
|
||||
|
||||
// NOTE: If you change the frame layout, this code will need to
|
||||
// be updated!
|
||||
@ -1496,11 +1494,11 @@ void CppInterpreterGenerator::adjust_callers_stack(Register args) {
|
||||
//
|
||||
// assert_different_registers(state, prev_state);
|
||||
const Register Gtmp = G3_scratch;
|
||||
const RconstMethod = G3_scratch;
|
||||
const Register RconstMethod = G3_scratch;
|
||||
const Register tmp = O2;
|
||||
const Address constMethod(G5_method, 0, in_bytes(Method::const_offset()));
|
||||
const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset()));
|
||||
const Address constMethod(G5_method, in_bytes(Method::const_offset()));
|
||||
const Address size_of_parameters(RconstMethod, in_bytes(ConstMethod::size_of_parameters_offset()));
|
||||
const Address size_of_locals (RconstMethod, in_bytes(ConstMethod::size_of_locals_offset()));
|
||||
|
||||
__ ld_ptr(constMethod, RconstMethod);
|
||||
__ lduh(size_of_parameters, tmp);
|
||||
@ -1555,8 +1553,8 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
const Register Gtmp1 = G3_scratch;
|
||||
// const Register Lmirror = L1; // native mirror (native calls only)
|
||||
|
||||
const Address constMethod (G5_method, 0, in_bytes(Method::const_offset()));
|
||||
const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
|
||||
const Address constMethod (G5_method, in_bytes(Method::const_offset()));
|
||||
const Address access_flags (G5_method, in_bytes(Method::access_flags_offset()));
|
||||
|
||||
address entry_point = __ pc();
|
||||
__ mov(G0, prevState); // no current activation
|
||||
@ -1709,7 +1707,7 @@ address InterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
|
||||
// We want exception in the thread no matter what we ultimately decide about frame type.
|
||||
|
||||
Address exception_addr (G2_thread, 0, in_bytes(Thread::pending_exception_offset()));
|
||||
Address exception_addr (G2_thread, in_bytes(Thread::pending_exception_offset()));
|
||||
__ verify_thread();
|
||||
__ st_ptr(O0, exception_addr);
|
||||
|
||||
|
@ -827,6 +827,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
}
|
||||
|
||||
if (is_interpreted_frame()) {
|
||||
#ifndef CC_INTERP
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_d_scratch_fp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_l_scratch_fp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_padding);
|
||||
@ -837,6 +838,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
if ((esp >= sp()) && (esp < fp())) {
|
||||
values.describe(-1, esp, "*Lesp");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!is_compiled_frame()) {
|
||||
|
@ -2497,6 +2497,24 @@ void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Regis
|
||||
void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
|
||||
if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth);
|
||||
}
|
||||
|
||||
|
||||
// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
|
||||
void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch1, Register scratch2,
|
||||
Condition cond, Label *where) {
|
||||
ld(counter_addr, scratch1);
|
||||
add(scratch1, increment, scratch1);
|
||||
if (is_simm13(mask)) {
|
||||
andcc(scratch1, mask, G0);
|
||||
} else {
|
||||
set(mask, scratch2);
|
||||
andcc(scratch1, scratch2, G0);
|
||||
}
|
||||
br(cond, false, Assembler::pn, *where);
|
||||
delayed()->st(scratch1, counter_addr);
|
||||
}
|
||||
#endif /* CC_INTERP */
|
||||
|
||||
// Inline assembly for:
|
||||
@ -2646,20 +2664,3 @@ void InterpreterMacroAssembler::restore_return_value( TosState state, bool is_na
|
||||
}
|
||||
#endif // CC_INTERP
|
||||
}
|
||||
|
||||
// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
|
||||
void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch1, Register scratch2,
|
||||
Condition cond, Label *where) {
|
||||
ld(counter_addr, scratch1);
|
||||
add(scratch1, increment, scratch1);
|
||||
if (is_simm13(mask)) {
|
||||
andcc(scratch1, mask, G0);
|
||||
} else {
|
||||
set(mask, scratch2);
|
||||
andcc(scratch1, scratch2, G0);
|
||||
}
|
||||
br(cond, false, Assembler::pn, *where);
|
||||
delayed()->st(scratch1, counter_addr);
|
||||
}
|
||||
|
@ -23,7 +23,8 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "nativeInst_sparc.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
|
@ -250,7 +250,7 @@ inline jint BytecodeInterpreter::VMintSub(jint op1, jint op2) {
|
||||
return op1 - op2;
|
||||
}
|
||||
|
||||
inline jint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
|
||||
inline juint BytecodeInterpreter::VMintUshr(jint op1, jint op2) {
|
||||
return ((juint) op1) >> (op2 & 0x1f);
|
||||
}
|
||||
|
||||
|
@ -574,7 +574,7 @@ void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile
|
||||
MethodCounters::invocation_counter_offset() +
|
||||
InvocationCounter::counter_offset());
|
||||
const Address backedge_counter (rax,
|
||||
MethodCounter::backedge_counter_offset() +
|
||||
MethodCounters::backedge_counter_offset() +
|
||||
InvocationCounter::counter_offset());
|
||||
|
||||
__ get_method_counters(rbx, rax, done);
|
||||
@ -982,16 +982,18 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
// to save/restore.
|
||||
address entry_point = __ pc();
|
||||
|
||||
const Address constMethod (rbx, Method::const_offset());
|
||||
const Address access_flags (rbx, Method::access_flags_offset());
|
||||
const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
|
||||
|
||||
// rsi/r13 == state/locals rdi == prevstate
|
||||
const Register locals = rdi;
|
||||
|
||||
// get parameter size (always needed)
|
||||
__ movptr(rcx, constMethod);
|
||||
__ load_unsigned_short(rcx, size_of_parameters);
|
||||
{
|
||||
const Address constMethod (rbx, Method::const_offset());
|
||||
const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
|
||||
__ movptr(rcx, constMethod);
|
||||
__ load_unsigned_short(rcx, size_of_parameters);
|
||||
}
|
||||
|
||||
// rbx: Method*
|
||||
// rcx: size of parameters
|
||||
@ -1111,14 +1113,16 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
const Register method = rbx;
|
||||
const Register thread = LP64_ONLY(r15_thread) NOT_LP64(rdi);
|
||||
const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); // rcx|rscratch1
|
||||
const Address constMethod (method, Method::const_offset());
|
||||
const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset());
|
||||
|
||||
// allocate space for parameters
|
||||
// allocate space for parameters
|
||||
__ movptr(method, STATE(_method));
|
||||
__ verify_method_ptr(method);
|
||||
__ movptr(t, constMethod);
|
||||
__ load_unsigned_short(t, size_of_parameters);
|
||||
{
|
||||
const Address constMethod (method, Method::const_offset());
|
||||
const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset());
|
||||
__ movptr(t, constMethod);
|
||||
__ load_unsigned_short(t, size_of_parameters);
|
||||
}
|
||||
__ shll(t, 2);
|
||||
#ifdef _LP64
|
||||
__ subptr(rsp, t);
|
||||
@ -2221,7 +2225,6 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
|
||||
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
|
||||
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
|
||||
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
|
||||
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
|
||||
|
||||
case Interpreter::java_lang_math_sin : // fall thru
|
||||
case Interpreter::java_lang_math_cos : // fall thru
|
||||
@ -2229,7 +2232,10 @@ address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter:
|
||||
case Interpreter::java_lang_math_abs : // fall thru
|
||||
case Interpreter::java_lang_math_log : // fall thru
|
||||
case Interpreter::java_lang_math_log10 : // fall thru
|
||||
case Interpreter::java_lang_math_sqrt : entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break;
|
||||
case Interpreter::java_lang_math_sqrt : // fall thru
|
||||
case Interpreter::java_lang_math_pow : // fall thru
|
||||
case Interpreter::java_lang_math_exp : // fall thru
|
||||
entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break;
|
||||
case Interpreter::java_lang_ref_reference_get
|
||||
: entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break;
|
||||
default : ShouldNotReachHere(); break;
|
||||
@ -2451,4 +2457,22 @@ int AbstractInterpreter::layout_activation(Method* method,
|
||||
return frame_size/BytesPerWord;
|
||||
}
|
||||
|
||||
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
|
||||
switch (method_kind(m)) {
|
||||
case Interpreter::java_lang_math_sin : // fall thru
|
||||
case Interpreter::java_lang_math_cos : // fall thru
|
||||
case Interpreter::java_lang_math_tan : // fall thru
|
||||
case Interpreter::java_lang_math_abs : // fall thru
|
||||
case Interpreter::java_lang_math_log : // fall thru
|
||||
case Interpreter::java_lang_math_log10 : // fall thru
|
||||
case Interpreter::java_lang_math_sqrt : // fall thru
|
||||
case Interpreter::java_lang_math_pow : // fall thru
|
||||
case Interpreter::java_lang_math_exp :
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // CC_INTERP (all)
|
||||
|
@ -687,6 +687,7 @@ intptr_t* frame::interpreter_frame_tos_at(jint offset) const {
|
||||
|
||||
void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
if (is_interpreted_frame()) {
|
||||
#ifndef CC_INTERP
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_method);
|
||||
@ -695,6 +696,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_bcx);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -266,20 +266,6 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, R
|
||||
addptr(cache, tmp); // construct pointer to cache entry
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::get_method_counters(Register method,
|
||||
Register mcs, Label& skip) {
|
||||
Label has_counters;
|
||||
movptr(mcs, Address(method, Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::notZero, has_counters);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::build_method_counters), method);
|
||||
movptr(mcs, Address(method,Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
|
||||
bind(has_counters);
|
||||
}
|
||||
|
||||
// Load object from cpool->resolved_references(index)
|
||||
void InterpreterMacroAssembler::load_resolved_reference_at_index(
|
||||
Register result, Register index) {
|
||||
@ -678,6 +664,20 @@ void InterpreterMacroAssembler::remove_activation(TosState state, Register ret_a
|
||||
|
||||
#endif /* !CC_INTERP */
|
||||
|
||||
void InterpreterMacroAssembler::get_method_counters(Register method,
|
||||
Register mcs, Label& skip) {
|
||||
Label has_counters;
|
||||
movptr(mcs, Address(method, Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::notZero, has_counters);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::build_method_counters), method);
|
||||
movptr(mcs, Address(method,Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
|
||||
bind(has_counters);
|
||||
}
|
||||
|
||||
|
||||
// Lock object
|
||||
//
|
||||
@ -1359,6 +1359,19 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
|
||||
if (state == ftos || state == dtos) MacroAssembler::verify_FPU(stack_depth);
|
||||
}
|
||||
|
||||
// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
|
||||
void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch, bool preloaded,
|
||||
Condition cond, Label* where) {
|
||||
if (!preloaded) {
|
||||
movl(scratch, counter_addr);
|
||||
}
|
||||
incrementl(scratch, increment);
|
||||
movl(counter_addr, scratch);
|
||||
andl(scratch, mask);
|
||||
jcc(cond, *where);
|
||||
}
|
||||
#endif /* CC_INTERP */
|
||||
|
||||
|
||||
@ -1430,17 +1443,3 @@ void InterpreterMacroAssembler::notify_method_exit(
|
||||
NOT_CC_INTERP(pop(state));
|
||||
}
|
||||
}
|
||||
|
||||
// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
|
||||
void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch, bool preloaded,
|
||||
Condition cond, Label* where) {
|
||||
if (!preloaded) {
|
||||
movl(scratch, counter_addr);
|
||||
}
|
||||
incrementl(scratch, increment);
|
||||
movl(counter_addr, scratch);
|
||||
andl(scratch, mask);
|
||||
jcc(cond, *where);
|
||||
}
|
||||
|
@ -77,7 +77,6 @@
|
||||
void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_method_counters(Register method, Register mcs, Label& skip);
|
||||
|
||||
// load cpool->resolved_references(index);
|
||||
void load_resolved_reference_at_index(Register result, Register index);
|
||||
@ -156,6 +155,7 @@
|
||||
bool install_monitor_exception = true,
|
||||
bool notify_jvmdi = true);
|
||||
#endif /* !CC_INTERP */
|
||||
void get_method_counters(Register method, Register mcs, Label& skip);
|
||||
|
||||
// Debugging
|
||||
void verify_oop(Register reg, TosState state = atos); // only if +VerifyOops && state == atos
|
||||
|
@ -271,20 +271,6 @@ void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache,
|
||||
addptr(cache, tmp); // construct pointer to cache entry
|
||||
}
|
||||
|
||||
void InterpreterMacroAssembler::get_method_counters(Register method,
|
||||
Register mcs, Label& skip) {
|
||||
Label has_counters;
|
||||
movptr(mcs, Address(method, Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::notZero, has_counters);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::build_method_counters), method);
|
||||
movptr(mcs, Address(method,Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
|
||||
bind(has_counters);
|
||||
}
|
||||
|
||||
// Load object from cpool->resolved_references(index)
|
||||
void InterpreterMacroAssembler::load_resolved_reference_at_index(
|
||||
Register result, Register index) {
|
||||
@ -676,6 +662,21 @@ void InterpreterMacroAssembler::remove_activation(
|
||||
|
||||
#endif // C_INTERP
|
||||
|
||||
void InterpreterMacroAssembler::get_method_counters(Register method,
|
||||
Register mcs, Label& skip) {
|
||||
Label has_counters;
|
||||
movptr(mcs, Address(method, Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::notZero, has_counters);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::build_method_counters), method);
|
||||
movptr(mcs, Address(method,Method::method_counters_offset()));
|
||||
testptr(mcs, mcs);
|
||||
jcc(Assembler::zero, skip); // No MethodCounters allocated, OutOfMemory
|
||||
bind(has_counters);
|
||||
}
|
||||
|
||||
|
||||
// Lock object
|
||||
//
|
||||
// Args:
|
||||
@ -1423,6 +1424,20 @@ void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) {
|
||||
|
||||
void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) {
|
||||
}
|
||||
|
||||
// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
|
||||
void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch, bool preloaded,
|
||||
Condition cond, Label* where) {
|
||||
if (!preloaded) {
|
||||
movl(scratch, counter_addr);
|
||||
}
|
||||
incrementl(scratch, increment);
|
||||
movl(counter_addr, scratch);
|
||||
andl(scratch, mask);
|
||||
jcc(cond, *where);
|
||||
}
|
||||
#endif // !CC_INTERP
|
||||
|
||||
|
||||
@ -1491,16 +1506,3 @@ void InterpreterMacroAssembler::notify_method_exit(
|
||||
}
|
||||
}
|
||||
|
||||
// Jump if ((*counter_addr += increment) & mask) satisfies the condition.
|
||||
void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr,
|
||||
int increment, int mask,
|
||||
Register scratch, bool preloaded,
|
||||
Condition cond, Label* where) {
|
||||
if (!preloaded) {
|
||||
movl(scratch, counter_addr);
|
||||
}
|
||||
incrementl(scratch, increment);
|
||||
movl(counter_addr, scratch);
|
||||
andl(scratch, mask);
|
||||
jcc(cond, *where);
|
||||
}
|
||||
|
@ -99,7 +99,6 @@
|
||||
void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2));
|
||||
void get_method_counters(Register method, Register mcs, Label& skip);
|
||||
|
||||
// load cpool->resolved_references(index);
|
||||
void load_resolved_reference_at_index(Register result, Register index);
|
||||
@ -172,6 +171,7 @@
|
||||
bool install_monitor_exception = true,
|
||||
bool notify_jvmdi = true);
|
||||
#endif // CC_INTERP
|
||||
void get_method_counters(Register method, Register mcs, Label& skip);
|
||||
|
||||
// Object locking
|
||||
void lock_object (Register lock_reg);
|
||||
|
@ -229,10 +229,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
|
||||
// abstract method entry
|
||||
|
||||
#ifndef CC_INTERP
|
||||
// pop return address, reset last_sp to NULL
|
||||
__ empty_expression_stack();
|
||||
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
|
||||
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
|
||||
#endif
|
||||
|
||||
// throw exception
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
|
||||
|
@ -310,10 +310,12 @@ address InterpreterGenerator::generate_abstract_entry(void) {
|
||||
|
||||
// abstract method entry
|
||||
|
||||
#ifndef CC_INTERP
|
||||
// pop return address, reset last_sp to NULL
|
||||
__ empty_expression_stack();
|
||||
__ restore_bcp(); // rsi must be correct for exception handler (was destroyed)
|
||||
__ restore_locals(); // make sure locals pointer is correct as well (was destroyed)
|
||||
#endif
|
||||
|
||||
// throw exception
|
||||
__ call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
|
@ -1135,15 +1135,10 @@ jlong os::javaTimeNanos() {
|
||||
}
|
||||
|
||||
void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) {
|
||||
{
|
||||
// gettimeofday - based on time in seconds since the Epoch thus does not wrap
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
|
||||
// gettimeofday is a real time clock so it skips
|
||||
info_ptr->may_skip_backward = true;
|
||||
info_ptr->may_skip_forward = true;
|
||||
}
|
||||
|
||||
info_ptr->max_value = ALL_64_BITS;
|
||||
// mread_real_time() is monotonic (see 'os::javaTimeNanos()')
|
||||
info_ptr->may_skip_backward = false;
|
||||
info_ptr->may_skip_forward = false;
|
||||
info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time
|
||||
}
|
||||
|
||||
@ -2799,105 +2794,6 @@ size_t os::read(int fd, void *buf, unsigned int nBytes) {
|
||||
return ::read(fd, buf, nBytes);
|
||||
}
|
||||
|
||||
#define NANOSECS_PER_MILLISEC 1000000
|
||||
|
||||
int os::sleep(Thread* thread, jlong millis, bool interruptible) {
|
||||
assert(thread == Thread::current(), "thread consistency check");
|
||||
|
||||
// Prevent nasty overflow in deadline calculation
|
||||
// by handling long sleeps similar to solaris or windows.
|
||||
const jlong limit = INT_MAX;
|
||||
int result;
|
||||
while (millis > limit) {
|
||||
if ((result = os::sleep(thread, limit, interruptible)) != OS_OK) {
|
||||
return result;
|
||||
}
|
||||
millis -= limit;
|
||||
}
|
||||
|
||||
ParkEvent * const slp = thread->_SleepEvent;
|
||||
slp->reset();
|
||||
OrderAccess::fence();
|
||||
|
||||
if (interruptible) {
|
||||
jlong prevtime = javaTimeNanos();
|
||||
|
||||
// Prevent precision loss and too long sleeps
|
||||
jlong deadline = prevtime + millis * NANOSECS_PER_MILLISEC;
|
||||
|
||||
for (;;) {
|
||||
if (os::is_interrupted(thread, true)) {
|
||||
return OS_INTRPT;
|
||||
}
|
||||
|
||||
jlong newtime = javaTimeNanos();
|
||||
|
||||
assert(newtime >= prevtime, "time moving backwards");
|
||||
// Doing prevtime and newtime in microseconds doesn't help precision,
|
||||
// and trying to round up to avoid lost milliseconds can result in a
|
||||
// too-short delay.
|
||||
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
|
||||
|
||||
if (millis <= 0) {
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
// Stop sleeping if we passed the deadline
|
||||
if (newtime >= deadline) {
|
||||
return OS_OK;
|
||||
}
|
||||
|
||||
prevtime = newtime;
|
||||
|
||||
{
|
||||
assert(thread->is_Java_thread(), "sanity check");
|
||||
JavaThread *jt = (JavaThread *) thread;
|
||||
ThreadBlockInVM tbivm(jt);
|
||||
OSThreadWaitState osts(jt->osthread(), false /* not Object.wait() */);
|
||||
|
||||
jt->set_suspend_equivalent();
|
||||
|
||||
slp->park(millis);
|
||||
|
||||
// were we externally suspended while we were waiting?
|
||||
jt->check_and_wait_while_suspended();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
|
||||
jlong prevtime = javaTimeNanos();
|
||||
|
||||
// Prevent precision loss and too long sleeps
|
||||
jlong deadline = prevtime + millis * NANOSECS_PER_MILLISEC;
|
||||
|
||||
for (;;) {
|
||||
// It'd be nice to avoid the back-to-back javaTimeNanos() calls on
|
||||
// the 1st iteration ...
|
||||
jlong newtime = javaTimeNanos();
|
||||
|
||||
if (newtime - prevtime < 0) {
|
||||
// time moving backwards, should only happen if no monotonic clock
|
||||
// not a guarantee() because JVM should not abort on kernel/glibc bugs
|
||||
// - HS14 Commented out as not implemented.
|
||||
// - TODO Maybe we should implement it?
|
||||
//assert(!Aix::supports_monotonic_clock(), "time moving backwards");
|
||||
} else {
|
||||
millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
|
||||
}
|
||||
|
||||
if (millis <= 0) break;
|
||||
|
||||
if (newtime >= deadline) {
|
||||
break;
|
||||
}
|
||||
|
||||
prevtime = newtime;
|
||||
slp->park(millis);
|
||||
}
|
||||
return OS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
void os::naked_short_sleep(jlong ms) {
|
||||
struct timespec req;
|
||||
|
||||
@ -3246,50 +3142,6 @@ static void do_resume(OSThread* osthread) {
|
||||
guarantee(osthread->sr.is_running(), "Must be running!");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// interrupt support
|
||||
|
||||
void os::interrupt(Thread* thread) {
|
||||
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
|
||||
if (!osthread->interrupted()) {
|
||||
osthread->set_interrupted(true);
|
||||
// More than one thread can get here with the same value of osthread,
|
||||
// resulting in multiple notifications. We do, however, want the store
|
||||
// to interrupted() to be visible to other threads before we execute unpark().
|
||||
OrderAccess::fence();
|
||||
ParkEvent * const slp = thread->_SleepEvent;
|
||||
if (slp != NULL) slp->unpark();
|
||||
}
|
||||
|
||||
// For JSR166. Unpark even if interrupt status already was set
|
||||
if (thread->is_Java_thread())
|
||||
((JavaThread*)thread)->parker()->unpark();
|
||||
|
||||
ParkEvent * ev = thread->_ParkEvent;
|
||||
if (ev != NULL) ev->unpark();
|
||||
|
||||
}
|
||||
|
||||
bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
|
||||
assert(Thread::current() == thread || Threads_lock->owned_by_self(),
|
||||
"possibility of dangling Thread pointer");
|
||||
|
||||
OSThread* osthread = thread->osthread();
|
||||
|
||||
bool interrupted = osthread->interrupted();
|
||||
|
||||
if (interrupted && clear_interrupted) {
|
||||
osthread->set_interrupted(false);
|
||||
// consider thread->_SleepEvent->reset() ... optional optimization
|
||||
}
|
||||
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// signal handling (except suspend/resume)
|
||||
|
||||
|
@ -283,4 +283,10 @@ inline int os::set_sock_opt(int fd, int level, int optname,
|
||||
const char* optval, socklen_t optlen) {
|
||||
return ::setsockopt(fd, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
inline bool os::supports_monotonic_clock() {
|
||||
// mread_real_time() is monotonic on AIX (see os::javaTimeNanos() comments)
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // OS_AIX_VM_OS_AIX_INLINE_HPP
|
||||
|
@ -1436,7 +1436,7 @@ void GraphBuilder::method_return(Value x) {
|
||||
|
||||
bool need_mem_bar = false;
|
||||
if (method()->name() == ciSymbol::object_initializer_name() &&
|
||||
scope()->wrote_final()) {
|
||||
(scope()->wrote_final() || (AlwaysSafeConstructors && scope()->wrote_fields()))) {
|
||||
need_mem_bar = true;
|
||||
}
|
||||
|
||||
@ -1550,6 +1550,10 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
scope()->set_wrote_final();
|
||||
}
|
||||
|
||||
if (code == Bytecodes::_putfield) {
|
||||
scope()->set_wrote_fields();
|
||||
}
|
||||
|
||||
const int offset = !needs_patching ? field->offset() : -1;
|
||||
switch (code) {
|
||||
case Bytecodes::_getstatic: {
|
||||
@ -3767,11 +3771,14 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
||||
}
|
||||
|
||||
// now perform tests that are based on flag settings
|
||||
if (callee->force_inline()) {
|
||||
if (inline_level() > MaxForceInlineLevel) INLINE_BAILOUT("MaxForceInlineLevel");
|
||||
print_inlining(callee, "force inline by annotation");
|
||||
} else if (callee->should_inline()) {
|
||||
print_inlining(callee, "force inline by CompileOracle");
|
||||
if (callee->force_inline() || callee->should_inline()) {
|
||||
if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel");
|
||||
if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep");
|
||||
|
||||
const char* msg = "";
|
||||
if (callee->force_inline()) msg = "force inline by annotation";
|
||||
if (callee->should_inline()) msg = "force inline by CompileOracle";
|
||||
print_inlining(callee, msg);
|
||||
} else {
|
||||
// use heuristic controls on inlining
|
||||
if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("inlining too deep");
|
||||
|
@ -142,6 +142,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe
|
||||
_number_of_locks = 0;
|
||||
_monitor_pairing_ok = method->has_balanced_monitors();
|
||||
_wrote_final = false;
|
||||
_wrote_fields = false;
|
||||
_start = NULL;
|
||||
|
||||
if (osr_bci == -1) {
|
||||
|
@ -150,6 +150,7 @@ class IRScope: public CompilationResourceObj {
|
||||
int _number_of_locks; // the number of monitor lock slots needed
|
||||
bool _monitor_pairing_ok; // the monitor pairing info
|
||||
bool _wrote_final; // has written final field
|
||||
bool _wrote_fields; // has written fields
|
||||
BlockBegin* _start; // the start block, successsors are method entries
|
||||
|
||||
BitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable
|
||||
@ -184,6 +185,9 @@ class IRScope: public CompilationResourceObj {
|
||||
BlockBegin* start() const { return _start; }
|
||||
void set_wrote_final() { _wrote_final = true; }
|
||||
bool wrote_final () const { return _wrote_final; }
|
||||
void set_wrote_fields() { _wrote_fields = true; }
|
||||
bool wrote_fields () const { return _wrote_fields; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -1734,7 +1734,8 @@ void LIRGenerator::do_StoreField(StoreField* x) {
|
||||
(info ? new CodeEmitInfo(info) : NULL));
|
||||
}
|
||||
|
||||
if (is_volatile && !needs_patching) {
|
||||
bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses;
|
||||
if (needs_atomic_access && !needs_patching) {
|
||||
volatile_field_store(value.result(), address, info);
|
||||
} else {
|
||||
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
|
||||
@ -1807,7 +1808,8 @@ void LIRGenerator::do_LoadField(LoadField* x) {
|
||||
address = generate_address(object.result(), x->offset(), field_type);
|
||||
}
|
||||
|
||||
if (is_volatile && !needs_patching) {
|
||||
bool needs_atomic_access = is_volatile || AlwaysAtomicAccesses;
|
||||
if (needs_atomic_access && !needs_patching) {
|
||||
volatile_field_load(address, reg, info);
|
||||
} else {
|
||||
LIR_PatchCode patch_code = needs_patching ? lir_patch_normal : lir_patch_none;
|
||||
|
@ -809,11 +809,10 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||
int bci = vfst.bci();
|
||||
Bytecodes::Code code = caller_method()->java_code_at(bci);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// this is used by assertions in the access_field_patching_id
|
||||
BasicType patch_field_type = T_ILLEGAL;
|
||||
#endif // PRODUCT
|
||||
bool deoptimize_for_volatile = false;
|
||||
bool deoptimize_for_atomic = false;
|
||||
int patch_field_offset = -1;
|
||||
KlassHandle init_klass(THREAD, NULL); // klass needed by load_klass_patching code
|
||||
KlassHandle load_klass(THREAD, NULL); // klass needed by load_klass_patching code
|
||||
@ -839,11 +838,24 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||
// is the path for patching field offsets. load_klass is only
|
||||
// used for patching references to oops which don't need special
|
||||
// handling in the volatile case.
|
||||
|
||||
deoptimize_for_volatile = result.access_flags().is_volatile();
|
||||
|
||||
#ifndef PRODUCT
|
||||
// If we are patching a field which should be atomic, then
|
||||
// the generated code is not correct either, force deoptimizing.
|
||||
// We need to only cover T_LONG and T_DOUBLE fields, as we can
|
||||
// break access atomicity only for them.
|
||||
|
||||
// Strictly speaking, the deoptimizaation on 64-bit platforms
|
||||
// is unnecessary, and T_LONG stores on 32-bit platforms need
|
||||
// to be handled by special patching code when AlwaysAtomicAccesses
|
||||
// becomes product feature. At this point, we are still going
|
||||
// for the deoptimization for consistency against volatile
|
||||
// accesses.
|
||||
|
||||
patch_field_type = result.field_type();
|
||||
#endif
|
||||
deoptimize_for_atomic = (AlwaysAtomicAccesses && (patch_field_type == T_DOUBLE || patch_field_type == T_LONG));
|
||||
|
||||
} else if (load_klass_or_mirror_patch_id) {
|
||||
Klass* k = NULL;
|
||||
switch (code) {
|
||||
@ -918,13 +930,19 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
if (deoptimize_for_volatile) {
|
||||
// At compile time we assumed the field wasn't volatile but after
|
||||
// loading it turns out it was volatile so we have to throw the
|
||||
if (deoptimize_for_volatile || deoptimize_for_atomic) {
|
||||
// At compile time we assumed the field wasn't volatile/atomic but after
|
||||
// loading it turns out it was volatile/atomic so we have to throw the
|
||||
// compiled code out and let it be regenerated.
|
||||
if (TracePatching) {
|
||||
tty->print_cr("Deoptimizing for patching volatile field reference");
|
||||
if (deoptimize_for_volatile) {
|
||||
tty->print_cr("Deoptimizing for patching volatile field reference");
|
||||
}
|
||||
if (deoptimize_for_atomic) {
|
||||
tty->print_cr("Deoptimizing for patching atomic field reference");
|
||||
}
|
||||
}
|
||||
|
||||
// It's possible the nmethod was invalidated in the last
|
||||
// safepoint, but if it's still alive then make it not_entrant.
|
||||
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
|
||||
|
@ -724,6 +724,11 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
|
||||
|
||||
VM_ENTRY_MARK;
|
||||
|
||||
// Disable CHA for default methods for now
|
||||
if (root_m->get_Method()->is_default_method()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
methodHandle target;
|
||||
{
|
||||
MutexLocker locker(Compile_lock);
|
||||
|
@ -87,8 +87,9 @@ void ciMethodData::load_extra_data() {
|
||||
DataLayout* dp_dst = extra_data_base();
|
||||
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
|
||||
assert(dp_src < end_src, "moved past end of extra data");
|
||||
assert(dp_src->tag() == dp_dst->tag(), err_msg("should be same tags %d != %d", dp_src->tag(), dp_dst->tag()));
|
||||
switch(dp_src->tag()) {
|
||||
// New traps in the MDO can be added as we translate the copy so
|
||||
// look at the entries in the copy.
|
||||
switch(dp_dst->tag()) {
|
||||
case DataLayout::speculative_trap_data_tag: {
|
||||
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
|
||||
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
|
||||
@ -102,7 +103,7 @@ void ciMethodData::load_extra_data() {
|
||||
// An empty slot or ArgInfoData entry marks the end of the trap data
|
||||
return;
|
||||
default:
|
||||
fatal(err_msg("bad tag = %d", dp_src->tag()));
|
||||
fatal(err_msg("bad tag = %d", dp_dst->tag()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -198,14 +198,12 @@ CodeBlob* CodeCache::allocate(int size, bool is_critical) {
|
||||
}
|
||||
maxCodeCacheUsed = MAX2(maxCodeCacheUsed, ((address)_heap->high_boundary() -
|
||||
(address)_heap->low_boundary()) - unallocated_capacity());
|
||||
verify_if_often();
|
||||
print_trace("allocation", cb, size);
|
||||
return cb;
|
||||
}
|
||||
|
||||
void CodeCache::free(CodeBlob* cb) {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
verify_if_often();
|
||||
|
||||
print_trace("free", cb);
|
||||
if (cb->is_nmethod()) {
|
||||
@ -221,7 +219,6 @@ void CodeCache::free(CodeBlob* cb) {
|
||||
|
||||
_heap->deallocate(cb);
|
||||
|
||||
verify_if_often();
|
||||
assert(_number_of_blobs >= 0, "sanity check");
|
||||
}
|
||||
|
||||
@ -244,12 +241,6 @@ void CodeCache::commit(CodeBlob* cb) {
|
||||
}
|
||||
|
||||
|
||||
void CodeCache::flush() {
|
||||
assert_locked_or_safepoint(CodeCache_lock);
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
|
||||
// Iteration over CodeBlobs
|
||||
|
||||
#define FOR_ALL_BLOBS(var) for (CodeBlob *var = first() ; var != NULL; var = next(var) )
|
||||
@ -269,7 +260,7 @@ bool CodeCache::contains(void *p) {
|
||||
CodeBlob* CodeCache::find_blob(void* start) {
|
||||
CodeBlob* result = find_blob_unsafe(start);
|
||||
if (result == NULL) return NULL;
|
||||
// We could potientially look up non_entrant methods
|
||||
// We could potentially look up non_entrant methods
|
||||
guarantee(!result->is_zombie() || result->is_locked_by_vm() || is_error_reported(), "unsafe access to zombie method");
|
||||
return result;
|
||||
}
|
||||
@ -741,17 +732,26 @@ void CodeCache::report_codemem_full() {
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::print_memory_overhead() {
|
||||
size_t wasted_bytes = 0;
|
||||
CodeBlob *cb;
|
||||
for (cb = first(); cb != NULL; cb = next(cb)) {
|
||||
HeapBlock* heap_block = ((HeapBlock*)cb) - 1;
|
||||
wasted_bytes += heap_block->length() * CodeCacheSegmentSize - cb->size();
|
||||
}
|
||||
// Print bytes that are allocated in the freelist
|
||||
ttyLocker ttl;
|
||||
tty->print_cr("Number of elements in freelist: %d", freelist_length());
|
||||
tty->print_cr("Allocated in freelist: %dkB", bytes_allocated_in_freelist()/K);
|
||||
tty->print_cr("Unused bytes in CodeBlobs: %dkB", (int)(wasted_bytes/K));
|
||||
tty->print_cr("Segment map size: %dkB", allocated_segments()/K); // 1 byte per segment
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Non-product version
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
void CodeCache::verify_if_often() {
|
||||
if (VerifyCodeCacheOften) {
|
||||
_heap->verify();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeCache::print_trace(const char* event, CodeBlob* cb, int size) {
|
||||
if (PrintCodeCache2) { // Need to add a new flag
|
||||
ResourceMark rm;
|
||||
@ -774,7 +774,7 @@ void CodeCache::print_internals() {
|
||||
int nmethodUnloaded = 0;
|
||||
int nmethodJava = 0;
|
||||
int nmethodNative = 0;
|
||||
int maxCodeSize = 0;
|
||||
int max_nm_size = 0;
|
||||
ResourceMark rm;
|
||||
|
||||
CodeBlob *cb;
|
||||
@ -798,13 +798,11 @@ void CodeCache::print_internals() {
|
||||
if(nm->is_not_entrant()) { nmethodNotEntrant++; }
|
||||
if(nm->is_zombie()) { nmethodZombie++; }
|
||||
if(nm->is_unloaded()) { nmethodUnloaded++; }
|
||||
if(nm->is_native_method()) { nmethodNative++; }
|
||||
if(nm->method() != NULL && nm->is_native_method()) { nmethodNative++; }
|
||||
|
||||
if(nm->method() != NULL && nm->is_java_method()) {
|
||||
nmethodJava++;
|
||||
if (nm->insts_size() > maxCodeSize) {
|
||||
maxCodeSize = nm->insts_size();
|
||||
}
|
||||
max_nm_size = MAX2(max_nm_size, nm->size());
|
||||
}
|
||||
} else if (cb->is_runtime_stub()) {
|
||||
runtimeStubCount++;
|
||||
@ -820,18 +818,19 @@ void CodeCache::print_internals() {
|
||||
}
|
||||
|
||||
int bucketSize = 512;
|
||||
int bucketLimit = maxCodeSize / bucketSize + 1;
|
||||
int bucketLimit = max_nm_size / bucketSize + 1;
|
||||
int *buckets = NEW_C_HEAP_ARRAY(int, bucketLimit, mtCode);
|
||||
memset(buckets,0,sizeof(int) * bucketLimit);
|
||||
memset(buckets, 0, sizeof(int) * bucketLimit);
|
||||
|
||||
for (cb = first(); cb != NULL; cb = next(cb)) {
|
||||
if (cb->is_nmethod()) {
|
||||
nmethod* nm = (nmethod*)cb;
|
||||
if(nm->is_java_method()) {
|
||||
buckets[nm->insts_size() / bucketSize]++;
|
||||
}
|
||||
buckets[nm->size() / bucketSize]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tty->print_cr("Code Cache Entries (total of %d)",total);
|
||||
tty->print_cr("-------------------------------------------------");
|
||||
tty->print_cr("nmethods: %d",nmethodCount);
|
||||
@ -858,6 +857,7 @@ void CodeCache::print_internals() {
|
||||
}
|
||||
|
||||
FREE_C_HEAP_ARRAY(int, buckets, mtCode);
|
||||
print_memory_overhead();
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
@ -58,12 +58,13 @@ class CodeCache : AllStatic {
|
||||
static bool _needs_cache_clean;
|
||||
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
|
||||
|
||||
static void verify_if_often() PRODUCT_RETURN;
|
||||
|
||||
static void mark_scavenge_root_nmethods() PRODUCT_RETURN;
|
||||
static void verify_perm_nmethods(CodeBlobClosure* f_or_null) PRODUCT_RETURN;
|
||||
|
||||
static int _codemem_full_count;
|
||||
static size_t bytes_allocated_in_freelist() { return _heap->allocated_in_freelist(); }
|
||||
static int allocated_segments() { return _heap->allocated_segments(); }
|
||||
static size_t freelist_length() { return _heap->freelist_length(); }
|
||||
|
||||
public:
|
||||
|
||||
@ -78,7 +79,6 @@ class CodeCache : AllStatic {
|
||||
static int alignment_unit(); // guaranteed alignment of all CodeBlobs
|
||||
static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)
|
||||
static void free(CodeBlob* cb); // frees a CodeBlob
|
||||
static void flush(); // flushes all CodeBlobs
|
||||
static bool contains(void *p); // returns whether p is included
|
||||
static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs
|
||||
static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs
|
||||
@ -150,6 +150,7 @@ class CodeCache : AllStatic {
|
||||
// Printing/debugging
|
||||
static void print(); // prints summary
|
||||
static void print_internals();
|
||||
static void print_memory_overhead();
|
||||
static void verify(); // verifies the code cache
|
||||
static void print_trace(const char* event, CodeBlob* cb, int size = 0) PRODUCT_RETURN;
|
||||
static void print_summary(outputStream* st, bool detailed = true); // Prints a summary of the code cache usage
|
||||
|
@ -725,13 +725,13 @@ Klass* Dependencies::DepStream::context_type() {
|
||||
}
|
||||
|
||||
// ----------------- DependencySignature --------------------------------------
|
||||
bool DependencySignature::equals(DependencySignature* sig) const {
|
||||
if ((type() != sig->type()) || (args_count() != sig->args_count())) {
|
||||
bool DependencySignature::equals(DependencySignature const& s1, DependencySignature const& s2) {
|
||||
if ((s1.type() != s2.type()) || (s1.args_count() != s2.args_count())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sig->args_count(); i++) {
|
||||
if (arg(i) != sig->arg(i)) {
|
||||
for (int i = 0; i < s1.args_count(); i++) {
|
||||
if (s1.arg(i) != s2.arg(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -527,7 +527,7 @@ class Dependencies: public ResourceObj {
|
||||
};
|
||||
|
||||
|
||||
class DependencySignature : public GenericHashtableEntry<DependencySignature, ResourceObj> {
|
||||
class DependencySignature : public ResourceObj {
|
||||
private:
|
||||
int _args_count;
|
||||
uintptr_t _argument_hash[Dependencies::max_arg_count];
|
||||
@ -542,12 +542,13 @@ class DependencySignature : public GenericHashtableEntry<DependencySignature, Re
|
||||
}
|
||||
}
|
||||
|
||||
bool equals(DependencySignature* sig) const;
|
||||
uintptr_t key() const { return _argument_hash[0] >> 2; }
|
||||
static bool equals(DependencySignature const& s1, DependencySignature const& s2);
|
||||
static unsigned hash (DependencySignature const& s1) { return s1.arg(0) >> 2; }
|
||||
|
||||
int args_count() const { return _args_count; }
|
||||
uintptr_t arg(int idx) const { return _argument_hash[idx]; }
|
||||
Dependencies::DepType type() const { return _type; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "prims/jvmtiImpl.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/sweeper.hpp"
|
||||
#include "utilities/resourceHash.hpp"
|
||||
#include "utilities/dtrace.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
@ -2135,7 +2136,11 @@ void nmethod::check_all_dependencies(DepChange& changes) {
|
||||
// Turn off dependency tracing while actually testing dependencies.
|
||||
NOT_PRODUCT( FlagSetting fs(TraceDependencies, false) );
|
||||
|
||||
GenericHashtable<DependencySignature, ResourceObj>* table = new GenericHashtable<DependencySignature, ResourceObj>(11027);
|
||||
typedef ResourceHashtable<DependencySignature, int, &DependencySignature::hash,
|
||||
&DependencySignature::equals, 11027> DepTable;
|
||||
|
||||
DepTable* table = new DepTable();
|
||||
|
||||
// Iterate over live nmethods and check dependencies of all nmethods that are not
|
||||
// marked for deoptimization. A particular dependency is only checked once.
|
||||
for(nmethod* nm = CodeCache::alive_nmethod(CodeCache::first()); nm != NULL; nm = CodeCache::alive_nmethod(CodeCache::next(nm))) {
|
||||
@ -2143,9 +2148,10 @@ void nmethod::check_all_dependencies(DepChange& changes) {
|
||||
for (Dependencies::DepStream deps(nm); deps.next(); ) {
|
||||
// Construct abstraction of a dependency.
|
||||
DependencySignature* current_sig = new DependencySignature(deps);
|
||||
// Determine if 'deps' is already checked. table->add() returns
|
||||
// 'true' if the dependency was added (i.e., was not in the hashtable).
|
||||
if (table->add(current_sig)) {
|
||||
|
||||
// Determine if dependency is already checked. table->put(...) returns
|
||||
// 'true' if the dependency is added (i.e., was not in the hashtable).
|
||||
if (table->put(*current_sig, 1)) {
|
||||
if (deps.check_dependency() != NULL) {
|
||||
// Dependency checking failed. Print out information about the failed
|
||||
// dependency and finally fail with an assert. We can fail here, since
|
||||
|
@ -3475,7 +3475,7 @@ BytecodeInterpreter::print() {
|
||||
tty->print_cr("&native_fresult: " INTPTR_FORMAT, (uintptr_t) &this->_native_fresult);
|
||||
tty->print_cr("native_lresult: " INTPTR_FORMAT, (uintptr_t) this->_native_lresult);
|
||||
#endif
|
||||
#if !defined(ZERO)
|
||||
#if !defined(ZERO) && defined(PPC)
|
||||
tty->print_cr("last_Java_fp: " INTPTR_FORMAT, (uintptr_t) this->_last_Java_fp);
|
||||
#endif // !ZERO
|
||||
tty->print_cr("self_link: " INTPTR_FORMAT, (uintptr_t) this->_self_link);
|
||||
|
@ -43,6 +43,7 @@ CodeHeap::CodeHeap() {
|
||||
_next_segment = 0;
|
||||
_freelist = NULL;
|
||||
_freelist_segments = 0;
|
||||
_freelist_length = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +54,7 @@ void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) {
|
||||
address p = (address)_segmap.low() + beg;
|
||||
address q = (address)_segmap.low() + end;
|
||||
// initialize interval
|
||||
while (p < q) *p++ = 0xFF;
|
||||
while (p < q) *p++ = free_sentinel;
|
||||
}
|
||||
|
||||
|
||||
@ -67,7 +68,7 @@ void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) {
|
||||
int i = 0;
|
||||
while (p < q) {
|
||||
*p++ = i++;
|
||||
if (i == 0xFF) i = 1;
|
||||
if (i == free_sentinel) i = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,11 +140,6 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size,
|
||||
}
|
||||
|
||||
|
||||
void CodeHeap::release() {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
|
||||
bool CodeHeap::expand_by(size_t size) {
|
||||
// expand _memory space
|
||||
size_t dm = align_to_page_size(_memory.committed_size() + size) - _memory.committed_size();
|
||||
@ -157,8 +153,8 @@ bool CodeHeap::expand_by(size_t size) {
|
||||
assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking");
|
||||
// expand _segmap space
|
||||
size_t ds = align_to_page_size(_number_of_committed_segments) - _segmap.committed_size();
|
||||
if (ds > 0) {
|
||||
if (!_segmap.expand_by(ds)) return false;
|
||||
if ((ds > 0) && !_segmap.expand_by(ds)) {
|
||||
return false;
|
||||
}
|
||||
assert(_segmap.committed_size() >= (size_t) _number_of_committed_segments, "just checking");
|
||||
// initialize additional segmap entries
|
||||
@ -167,12 +163,6 @@ bool CodeHeap::expand_by(size_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CodeHeap::shrink_by(size_t size) {
|
||||
Unimplemented();
|
||||
}
|
||||
|
||||
|
||||
void CodeHeap::clear() {
|
||||
_next_segment = 0;
|
||||
mark_segmap_as_free(0, _number_of_committed_segments);
|
||||
@ -180,26 +170,23 @@ void CodeHeap::clear() {
|
||||
|
||||
|
||||
void* CodeHeap::allocate(size_t instance_size, bool is_critical) {
|
||||
size_t number_of_segments = size_to_segments(instance_size + sizeof(HeapBlock));
|
||||
size_t number_of_segments = size_to_segments(instance_size + header_size());
|
||||
assert(segments_to_size(number_of_segments) >= sizeof(FreeBlock), "not enough room for FreeList");
|
||||
|
||||
// First check if we can satisfy request from freelist
|
||||
debug_only(verify());
|
||||
NOT_PRODUCT(verify());
|
||||
HeapBlock* block = search_freelist(number_of_segments, is_critical);
|
||||
debug_only(if (VerifyCodeCacheOften) verify());
|
||||
NOT_PRODUCT(verify());
|
||||
|
||||
if (block != NULL) {
|
||||
assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check");
|
||||
assert(!block->free(), "must be marked free");
|
||||
#ifdef ASSERT
|
||||
memset((void *)block->allocated_space(), badCodeHeapNewVal, instance_size);
|
||||
#endif
|
||||
DEBUG_ONLY(memset((void*)block->allocated_space(), badCodeHeapNewVal, instance_size));
|
||||
return block->allocated_space();
|
||||
}
|
||||
|
||||
// Ensure minimum size for allocation to the heap.
|
||||
if (number_of_segments < CodeCacheMinBlockLength) {
|
||||
number_of_segments = CodeCacheMinBlockLength;
|
||||
}
|
||||
number_of_segments = MAX2((int)CodeCacheMinBlockLength, (int)number_of_segments);
|
||||
|
||||
if (!is_critical) {
|
||||
// Make sure the allocation fits in the unallocated heap without using
|
||||
@ -215,9 +202,7 @@ void* CodeHeap::allocate(size_t instance_size, bool is_critical) {
|
||||
HeapBlock* b = block_at(_next_segment);
|
||||
b->initialize(number_of_segments);
|
||||
_next_segment += number_of_segments;
|
||||
#ifdef ASSERT
|
||||
memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size);
|
||||
#endif
|
||||
DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapNewVal, instance_size));
|
||||
return b->allocated_space();
|
||||
} else {
|
||||
return NULL;
|
||||
@ -230,28 +215,56 @@ void CodeHeap::deallocate(void* p) {
|
||||
// Find start of HeapBlock
|
||||
HeapBlock* b = (((HeapBlock *)p) - 1);
|
||||
assert(b->allocated_space() == p, "sanity check");
|
||||
#ifdef ASSERT
|
||||
memset((void *)b->allocated_space(),
|
||||
badCodeHeapFreeVal,
|
||||
segments_to_size(b->length()) - sizeof(HeapBlock));
|
||||
#endif
|
||||
DEBUG_ONLY(memset((void *)b->allocated_space(), badCodeHeapFreeVal,
|
||||
segments_to_size(b->length()) - sizeof(HeapBlock)));
|
||||
add_to_freelist(b);
|
||||
|
||||
debug_only(if (VerifyCodeCacheOften) verify());
|
||||
NOT_PRODUCT(verify());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Uses segment map to find the the start (header) of a nmethod. This works as follows:
|
||||
* The memory of the code cache is divided into 'segments'. The size of a segment is
|
||||
* determined by -XX:CodeCacheSegmentSize=XX. Allocation in the code cache can only
|
||||
* happen at segment boundaries. A pointer in the code cache can be mapped to a segment
|
||||
* by calling segment_for(addr). Each time memory is requested from the code cache,
|
||||
* the segmap is updated accordingly. See the following example, which illustrates the
|
||||
* state of code cache and the segment map: (seg -> segment, nm ->nmethod)
|
||||
*
|
||||
* code cache segmap
|
||||
* ----------- ---------
|
||||
* seg 1 | nm 1 | -> | 0 |
|
||||
* seg 2 | nm 1 | -> | 1 |
|
||||
* ... | nm 1 | -> | .. |
|
||||
* seg m | nm 2 | -> | 0 |
|
||||
* seg m+1 | nm 2 | -> | 1 |
|
||||
* ... | nm 2 | -> | 2 |
|
||||
* ... | nm 2 | -> | .. |
|
||||
* ... | nm 2 | -> | 0xFE |
|
||||
* seg m+n | nm 2 | -> | 1 |
|
||||
* ... | nm 2 | -> | |
|
||||
*
|
||||
* A value of '0' in the segmap indicates that this segment contains the beginning of
|
||||
* an nmethod. Let's walk through a simple example: If we want to find the start of
|
||||
* an nmethod that falls into seg 2, we read the value of the segmap[2]. The value
|
||||
* is an offset that points to the segment that contains the start of the nmethod.
|
||||
* Another example: If we want to get the start of nm 2, and we happen to get a pointer
|
||||
* that points to seg m+n, we first read seg[n+m], which returns '1'. So we have to
|
||||
* do one more read of the segmap[m+n-1] to finally get the segment header.
|
||||
*/
|
||||
void* CodeHeap::find_start(void* p) const {
|
||||
if (!contains(p)) {
|
||||
return NULL;
|
||||
}
|
||||
size_t i = segment_for(p);
|
||||
address b = (address)_segmap.low();
|
||||
if (b[i] == 0xFF) {
|
||||
size_t seg_idx = segment_for(p);
|
||||
address seg_map = (address)_segmap.low();
|
||||
if (is_segment_unused(seg_map[seg_idx])) {
|
||||
return NULL;
|
||||
}
|
||||
while (b[i] > 0) i -= (int)b[i];
|
||||
HeapBlock* h = block_at(i);
|
||||
while (seg_map[seg_idx] > 0) {
|
||||
seg_idx -= (int)seg_map[seg_idx];
|
||||
}
|
||||
|
||||
HeapBlock* h = block_at(seg_idx);
|
||||
if (h->free()) {
|
||||
return NULL;
|
||||
}
|
||||
@ -272,7 +285,7 @@ size_t CodeHeap::alignment_offset() const {
|
||||
}
|
||||
|
||||
// Finds the next free heapblock. If the current one is free, that it returned
|
||||
void* CodeHeap::next_free(HeapBlock *b) const {
|
||||
void* CodeHeap::next_free(HeapBlock* b) const {
|
||||
// Since free blocks are merged, there is max. on free block
|
||||
// between two used ones
|
||||
if (b != NULL && b->free()) b = next_block(b);
|
||||
@ -287,7 +300,7 @@ HeapBlock* CodeHeap::first_block() const {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HeapBlock *CodeHeap::block_start(void *q) const {
|
||||
HeapBlock* CodeHeap::block_start(void* q) const {
|
||||
HeapBlock* b = (HeapBlock*)find_start(q);
|
||||
if (b == NULL) return NULL;
|
||||
return b - 1;
|
||||
@ -312,6 +325,10 @@ size_t CodeHeap::max_capacity() const {
|
||||
return _memory.reserved_size();
|
||||
}
|
||||
|
||||
int CodeHeap::allocated_segments() const {
|
||||
return (int)_next_segment;
|
||||
}
|
||||
|
||||
size_t CodeHeap::allocated_capacity() const {
|
||||
// size of used heap - size on freelist
|
||||
return segments_to_size(_next_segment - _freelist_segments);
|
||||
@ -325,7 +342,7 @@ size_t CodeHeap::heap_unallocated_capacity() const {
|
||||
|
||||
// Free list management
|
||||
|
||||
FreeBlock *CodeHeap::following_block(FreeBlock *b) {
|
||||
FreeBlock* CodeHeap::following_block(FreeBlock *b) {
|
||||
return (FreeBlock*)(((address)b) + _segment_size * b->length());
|
||||
}
|
||||
|
||||
@ -343,7 +360,7 @@ void CodeHeap::insert_after(FreeBlock* a, FreeBlock* b) {
|
||||
}
|
||||
|
||||
// Try to merge this block with the following block
|
||||
void CodeHeap::merge_right(FreeBlock *a) {
|
||||
bool CodeHeap::merge_right(FreeBlock* a) {
|
||||
assert(a->free(), "must be a free block");
|
||||
if (following_block(a) == a->link()) {
|
||||
assert(a->link() != NULL && a->link()->free(), "must be free too");
|
||||
@ -353,13 +370,20 @@ void CodeHeap::merge_right(FreeBlock *a) {
|
||||
// Update find_start map
|
||||
size_t beg = segment_for(a);
|
||||
mark_segmap_as_used(beg, beg + a->length());
|
||||
_freelist_length--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CodeHeap::add_to_freelist(HeapBlock *a) {
|
||||
|
||||
void CodeHeap::add_to_freelist(HeapBlock* a) {
|
||||
FreeBlock* b = (FreeBlock*)a;
|
||||
_freelist_length++;
|
||||
|
||||
assert(b != _freelist, "cannot be removed twice");
|
||||
|
||||
|
||||
// Mark as free and update free space count
|
||||
_freelist_segments += b->length();
|
||||
b->set_free();
|
||||
@ -371,95 +395,96 @@ void CodeHeap::add_to_freelist(HeapBlock *a) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Scan for right place to put into list. List
|
||||
// is sorted by increasing addresses
|
||||
FreeBlock* prev = NULL;
|
||||
FreeBlock* cur = _freelist;
|
||||
while(cur != NULL && cur < b) {
|
||||
assert(prev == NULL || prev < cur, "must be ordered");
|
||||
prev = cur;
|
||||
cur = cur->link();
|
||||
}
|
||||
|
||||
assert( (prev == NULL && b < _freelist) ||
|
||||
(prev < b && (cur == NULL || b < cur)), "list must be ordered");
|
||||
|
||||
if (prev == NULL) {
|
||||
// Since the freelist is ordered (smaller addresses -> larger addresses) and the
|
||||
// element we want to insert into the freelist has a smaller address than the first
|
||||
// element, we can simply add 'b' as the first element and we are done.
|
||||
if (b < _freelist) {
|
||||
// Insert first in list
|
||||
b->set_link(_freelist);
|
||||
_freelist = b;
|
||||
merge_right(_freelist);
|
||||
} else {
|
||||
insert_after(prev, b);
|
||||
return;
|
||||
}
|
||||
|
||||
// Scan for right place to put into list. List
|
||||
// is sorted by increasing addresses
|
||||
FreeBlock* prev = _freelist;
|
||||
FreeBlock* cur = _freelist->link();
|
||||
while(cur != NULL && cur < b) {
|
||||
assert(prev < cur, "Freelist must be ordered");
|
||||
prev = cur;
|
||||
cur = cur->link();
|
||||
}
|
||||
assert((prev < b) && (cur == NULL || b < cur), "free-list must be ordered");
|
||||
insert_after(prev, b);
|
||||
}
|
||||
|
||||
// Search freelist for an entry on the list with the best fit
|
||||
// Return NULL if no one was found
|
||||
/**
|
||||
* Search freelist for an entry on the list with the best fit.
|
||||
* @return NULL, if no one was found
|
||||
*/
|
||||
FreeBlock* CodeHeap::search_freelist(size_t length, bool is_critical) {
|
||||
FreeBlock *best_block = NULL;
|
||||
FreeBlock *best_prev = NULL;
|
||||
size_t best_length = 0;
|
||||
FreeBlock* found_block = NULL;
|
||||
FreeBlock* found_prev = NULL;
|
||||
size_t found_length = 0;
|
||||
|
||||
// Search for smallest block which is bigger than length
|
||||
FreeBlock *prev = NULL;
|
||||
FreeBlock *cur = _freelist;
|
||||
FreeBlock* prev = NULL;
|
||||
FreeBlock* cur = _freelist;
|
||||
const size_t critical_boundary = (size_t)high_boundary() - CodeCacheMinimumFreeSpace;
|
||||
|
||||
// Search for first block that fits
|
||||
while(cur != NULL) {
|
||||
size_t l = cur->length();
|
||||
if (l >= length && (best_block == NULL || best_length > l)) {
|
||||
|
||||
if (cur->length() >= length) {
|
||||
// Non critical allocations are not allowed to use the last part of the code heap.
|
||||
if (!is_critical) {
|
||||
// Make sure the end of the allocation doesn't cross into the last part of the code heap
|
||||
if (((size_t)cur + length) > ((size_t)high_boundary() - CodeCacheMinimumFreeSpace)) {
|
||||
// the freelist is sorted by address - if one fails, all consecutive will also fail.
|
||||
break;
|
||||
}
|
||||
// Make sure the end of the allocation doesn't cross into the last part of the code heap.
|
||||
if (!is_critical && (((size_t)cur + length) > critical_boundary)) {
|
||||
// The freelist is sorted by address - if one fails, all consecutive will also fail.
|
||||
break;
|
||||
}
|
||||
// Remember block, its previous element, and its length
|
||||
found_block = cur;
|
||||
found_prev = prev;
|
||||
found_length = found_block->length();
|
||||
|
||||
// Remember best block, its previous element, and its length
|
||||
best_block = cur;
|
||||
best_prev = prev;
|
||||
best_length = best_block->length();
|
||||
break;
|
||||
}
|
||||
|
||||
// Next element in list
|
||||
prev = cur;
|
||||
cur = cur->link();
|
||||
}
|
||||
|
||||
if (best_block == NULL) {
|
||||
if (found_block == NULL) {
|
||||
// None found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert((best_prev == NULL && _freelist == best_block ) ||
|
||||
(best_prev != NULL && best_prev->link() == best_block), "sanity check");
|
||||
|
||||
// Exact (or at least good enough) fit. Remove from list.
|
||||
// Don't leave anything on the freelist smaller than CodeCacheMinBlockLength.
|
||||
if (best_length < length + CodeCacheMinBlockLength) {
|
||||
length = best_length;
|
||||
if (best_prev == NULL) {
|
||||
assert(_freelist == best_block, "sanity check");
|
||||
if (found_length - length < CodeCacheMinBlockLength) {
|
||||
_freelist_length--;
|
||||
length = found_length;
|
||||
if (found_prev == NULL) {
|
||||
assert(_freelist == found_block, "sanity check");
|
||||
_freelist = _freelist->link();
|
||||
} else {
|
||||
assert((found_prev->link() == found_block), "sanity check");
|
||||
// Unmap element
|
||||
best_prev->set_link(best_block->link());
|
||||
found_prev->set_link(found_block->link());
|
||||
}
|
||||
} else {
|
||||
// Truncate block and return a pointer to the following block
|
||||
best_block->set_length(best_length - length);
|
||||
best_block = following_block(best_block);
|
||||
// Set used bit and length on new block
|
||||
size_t beg = segment_for(best_block);
|
||||
found_block->set_length(found_length - length);
|
||||
found_block = following_block(found_block);
|
||||
|
||||
size_t beg = segment_for(found_block);
|
||||
mark_segmap_as_used(beg, beg + length);
|
||||
best_block->set_length(length);
|
||||
found_block->set_length(length);
|
||||
}
|
||||
|
||||
best_block->set_used();
|
||||
found_block->set_used();
|
||||
_freelist_segments -= length;
|
||||
return best_block;
|
||||
return found_block;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -471,33 +496,34 @@ void CodeHeap::print() {
|
||||
tty->print_cr("The Heap");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CodeHeap::verify() {
|
||||
// Count the number of blocks on the freelist, and the amount of space
|
||||
// represented.
|
||||
int count = 0;
|
||||
size_t len = 0;
|
||||
for(FreeBlock* b = _freelist; b != NULL; b = b->link()) {
|
||||
len += b->length();
|
||||
count++;
|
||||
}
|
||||
if (VerifyCodeCache) {
|
||||
size_t len = 0;
|
||||
int count = 0;
|
||||
for(FreeBlock* b = _freelist; b != NULL; b = b->link()) {
|
||||
len += b->length();
|
||||
count++;
|
||||
// Check if we have merged all free blocks
|
||||
assert(merge_right(b) == false, "Missed merging opportunity");
|
||||
}
|
||||
// Verify that freelist contains the right amount of free space
|
||||
assert(len == _freelist_segments, "wrong freelist");
|
||||
|
||||
// Verify that freelist contains the right amount of free space
|
||||
// guarantee(len == _freelist_segments, "wrong freelist");
|
||||
for(HeapBlock* h = first_block(); h != NULL; h = next_block(h)) {
|
||||
if (h->free()) count--;
|
||||
}
|
||||
// Verify that the freelist contains the same number of blocks
|
||||
// than free blocks found on the full list.
|
||||
assert(count == 0, "missing free blocks");
|
||||
|
||||
// Verify that the number of free blocks is not out of hand.
|
||||
static int free_block_threshold = 10000;
|
||||
if (count > free_block_threshold) {
|
||||
warning("CodeHeap: # of free blocks > %d", free_block_threshold);
|
||||
// Double the warning limit
|
||||
free_block_threshold *= 2;
|
||||
// Verify that the number of free blocks is not out of hand.
|
||||
static int free_block_threshold = 10000;
|
||||
if (count > free_block_threshold) {
|
||||
warning("CodeHeap: # of free blocks > %d", free_block_threshold);
|
||||
// Double the warning limit
|
||||
free_block_threshold *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the freelist contains the same number of free blocks that is
|
||||
// found on the full list.
|
||||
for(HeapBlock *h = first_block(); h != NULL; h = next_block(h)) {
|
||||
if (h->free()) count--;
|
||||
}
|
||||
// guarantee(count == 0, "missing free blocks");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -92,24 +92,28 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||
|
||||
FreeBlock* _freelist;
|
||||
size_t _freelist_segments; // No. of segments in freelist
|
||||
int _freelist_length;
|
||||
|
||||
enum { free_sentinel = 0xFF };
|
||||
|
||||
// Helper functions
|
||||
size_t size_to_segments(size_t size) const { return (size + _segment_size - 1) >> _log2_segment_size; }
|
||||
size_t segments_to_size(size_t number_of_segments) const { return number_of_segments << _log2_segment_size; }
|
||||
|
||||
size_t segment_for(void* p) const { return ((char*)p - _memory.low()) >> _log2_segment_size; }
|
||||
bool is_segment_unused(int val) const { return val == free_sentinel; }
|
||||
HeapBlock* block_at(size_t i) const { return (HeapBlock*)(_memory.low() + (i << _log2_segment_size)); }
|
||||
|
||||
void mark_segmap_as_free(size_t beg, size_t end);
|
||||
void mark_segmap_as_used(size_t beg, size_t end);
|
||||
|
||||
// Freelist management helpers
|
||||
FreeBlock* following_block(FreeBlock *b);
|
||||
FreeBlock* following_block(FreeBlock* b);
|
||||
void insert_after(FreeBlock* a, FreeBlock* b);
|
||||
void merge_right (FreeBlock* a);
|
||||
bool merge_right (FreeBlock* a);
|
||||
|
||||
// Toplevel freelist management
|
||||
void add_to_freelist(HeapBlock *b);
|
||||
void add_to_freelist(HeapBlock* b);
|
||||
FreeBlock* search_freelist(size_t length, bool is_critical);
|
||||
|
||||
// Iteration helpers
|
||||
@ -120,20 +124,18 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||
|
||||
// to perform additional actions on creation of executable code
|
||||
void on_code_mapping(char* base, size_t size);
|
||||
void clear(); // clears all heap contents
|
||||
|
||||
public:
|
||||
CodeHeap();
|
||||
|
||||
// Heap extents
|
||||
bool reserve(size_t reserved_size, size_t committed_size, size_t segment_size);
|
||||
void release(); // releases all allocated memory
|
||||
bool expand_by(size_t size); // expands committed memory by size
|
||||
void shrink_by(size_t size); // shrinks committed memory by size
|
||||
void clear(); // clears all heap contents
|
||||
|
||||
// Memory allocation
|
||||
void* allocate (size_t size, bool is_critical); // allocates a block of size or returns NULL
|
||||
void deallocate(void* p); // deallocates a block
|
||||
void deallocate(void* p); // deallocates a block
|
||||
|
||||
// Attributes
|
||||
char* low_boundary() const { return _memory.low_boundary (); }
|
||||
@ -141,12 +143,13 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||
char* high_boundary() const { return _memory.high_boundary(); }
|
||||
|
||||
bool contains(const void* p) const { return low_boundary() <= p && p < high(); }
|
||||
void* find_start(void* p) const; // returns the block containing p or NULL
|
||||
size_t alignment_unit() const; // alignment of any block
|
||||
size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit
|
||||
static size_t header_size(); // returns the header size for each heap block
|
||||
void* find_start(void* p) const; // returns the block containing p or NULL
|
||||
size_t alignment_unit() const; // alignment of any block
|
||||
size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit
|
||||
static size_t header_size(); // returns the header size for each heap block
|
||||
|
||||
// Iteration
|
||||
size_t allocated_in_freelist() const { return _freelist_segments * CodeCacheSegmentSize; }
|
||||
int freelist_length() const { return _freelist_length; } // number of elements in the freelist
|
||||
|
||||
// returns the first block or NULL
|
||||
void* first() const { return next_free(first_block()); }
|
||||
@ -156,6 +159,7 @@ class CodeHeap : public CHeapObj<mtCode> {
|
||||
// Statistics
|
||||
size_t capacity() const;
|
||||
size_t max_capacity() const;
|
||||
int allocated_segments() const;
|
||||
size_t allocated_capacity() const;
|
||||
size_t unallocated_capacity() const { return max_capacity() - allocated_capacity(); }
|
||||
|
||||
@ -164,7 +168,7 @@ private:
|
||||
|
||||
public:
|
||||
// Debugging
|
||||
void verify();
|
||||
void verify() PRODUCT_RETURN;
|
||||
void print() PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
|
@ -1071,7 +1071,8 @@ void MethodData::post_initialize(BytecodeStream* stream) {
|
||||
}
|
||||
|
||||
// Initialize the MethodData* corresponding to a given method.
|
||||
MethodData::MethodData(methodHandle method, int size, TRAPS) {
|
||||
MethodData::MethodData(methodHandle method, int size, TRAPS)
|
||||
: _extra_data_lock(Monitor::leaf, "MDO extra data lock") {
|
||||
No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC
|
||||
ResourceMark rm;
|
||||
// Set the method back-pointer.
|
||||
@ -1235,7 +1236,7 @@ DataLayout* MethodData::next_extra(DataLayout* dp) {
|
||||
return (DataLayout*)((address)dp + DataLayout::compute_size_in_bytes(nb_cells));
|
||||
}
|
||||
|
||||
ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp) {
|
||||
ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent) {
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
||||
for (;; dp = next_extra(dp)) {
|
||||
@ -1257,10 +1258,11 @@ ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout
|
||||
if (m != NULL) {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
// data->method() may be null in case of a concurrent
|
||||
// allocation. Assume it's for the same method and use that
|
||||
// allocation. Maybe it's for the same method. Try to use that
|
||||
// entry in that case.
|
||||
if (dp->bci() == bci) {
|
||||
if (data->method() == NULL) {
|
||||
assert(concurrent, "impossible because no concurrent allocation");
|
||||
return NULL;
|
||||
} else if (data->method() == m) {
|
||||
return data;
|
||||
@ -1289,40 +1291,40 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi
|
||||
// Allocation in the extra data space has to be atomic because not
|
||||
// all entries have the same size and non atomic concurrent
|
||||
// allocation would result in a corrupted extra data space.
|
||||
while (true) {
|
||||
ProfileData* result = bci_to_extra_data_helper(bci, m, dp);
|
||||
if (result != NULL) {
|
||||
ProfileData* result = bci_to_extra_data_helper(bci, m, dp, true);
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (create_if_missing && dp < end) {
|
||||
MutexLocker ml(&_extra_data_lock);
|
||||
// Check again now that we have the lock. Another thread may
|
||||
// have added extra data entries.
|
||||
ProfileData* result = bci_to_extra_data_helper(bci, m, dp, false);
|
||||
if (result != NULL || dp >= end) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (create_if_missing && dp < end) {
|
||||
assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free");
|
||||
assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info");
|
||||
u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag;
|
||||
// SpeculativeTrapData is 2 slots. Make sure we have room.
|
||||
if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) {
|
||||
return NULL;
|
||||
}
|
||||
DataLayout temp;
|
||||
temp.initialize(tag, bci, 0);
|
||||
// May have been set concurrently
|
||||
if (dp->header() != temp.header() && !dp->atomic_set_header(temp.header())) {
|
||||
// Allocation failure because of concurrent allocation. Try
|
||||
// again.
|
||||
continue;
|
||||
}
|
||||
assert(dp->tag() == tag, "sane");
|
||||
assert(dp->bci() == bci, "no concurrent allocation");
|
||||
if (tag == DataLayout::bit_data_tag) {
|
||||
return new BitData(dp);
|
||||
} else {
|
||||
// If being allocated concurrently, one trap may be lost
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
data->set_method(m);
|
||||
return data;
|
||||
}
|
||||
assert(dp->tag() == DataLayout::no_tag || (dp->tag() == DataLayout::speculative_trap_data_tag && m != NULL), "should be free");
|
||||
assert(next_extra(dp)->tag() == DataLayout::no_tag || next_extra(dp)->tag() == DataLayout::arg_info_data_tag, "should be free or arg info");
|
||||
u1 tag = m == NULL ? DataLayout::bit_data_tag : DataLayout::speculative_trap_data_tag;
|
||||
// SpeculativeTrapData is 2 slots. Make sure we have room.
|
||||
if (m != NULL && next_extra(dp)->tag() != DataLayout::no_tag) {
|
||||
return NULL;
|
||||
}
|
||||
DataLayout temp;
|
||||
temp.initialize(tag, bci, 0);
|
||||
|
||||
dp->set_header(temp.header());
|
||||
assert(dp->tag() == tag, "sane");
|
||||
assert(dp->bci() == bci, "no concurrent allocation");
|
||||
if (tag == DataLayout::bit_data_tag) {
|
||||
return new BitData(dp);
|
||||
} else {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
data->set_method(m);
|
||||
return data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -190,12 +190,6 @@ public:
|
||||
void set_header(intptr_t value) {
|
||||
_header._bits = value;
|
||||
}
|
||||
bool atomic_set_header(intptr_t value) {
|
||||
if (Atomic::cmpxchg_ptr(value, (volatile intptr_t*)&_header._bits, 0) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
intptr_t header() {
|
||||
return _header._bits;
|
||||
}
|
||||
@ -2047,10 +2041,12 @@ private:
|
||||
// Cached hint for bci_to_dp and bci_to_data
|
||||
int _hint_di;
|
||||
|
||||
Mutex _extra_data_lock;
|
||||
|
||||
MethodData(methodHandle method, int size, TRAPS);
|
||||
public:
|
||||
static MethodData* allocate(ClassLoaderData* loader_data, methodHandle method, TRAPS);
|
||||
MethodData() {}; // For ciMethodData
|
||||
MethodData() : _extra_data_lock(Monitor::leaf, "MDO extra data lock") {}; // For ciMethodData
|
||||
|
||||
bool is_methodData() const volatile { return true; }
|
||||
|
||||
@ -2155,7 +2151,7 @@ private:
|
||||
// What is the index of the first data entry?
|
||||
int first_di() const { return 0; }
|
||||
|
||||
ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp);
|
||||
ProfileData* bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent);
|
||||
// Find or create an extra ProfileData:
|
||||
ProfileData* bci_to_extra_data(int bci, Method* m, bool create_if_missing);
|
||||
|
||||
|
@ -452,7 +452,7 @@
|
||||
product(bool, EliminateAutoBox, true, \
|
||||
"Control optimizations for autobox elimination") \
|
||||
\
|
||||
experimental(bool, UseImplicitStableValues, false, \
|
||||
diagnostic(bool, UseImplicitStableValues, true, \
|
||||
"Mark well-known stable fields as such (e.g. String.value)") \
|
||||
\
|
||||
product(intx, AutoBoxCacheMax, 128, \
|
||||
@ -650,7 +650,7 @@
|
||||
experimental(bool, ReplaceInParentMaps, false, \
|
||||
"Propagate type improvements in callers of inlinee if possible") \
|
||||
\
|
||||
experimental(bool, UseTypeSpeculation, false, \
|
||||
product(bool, UseTypeSpeculation, true, \
|
||||
"Speculatively propagate types from profiles") \
|
||||
\
|
||||
diagnostic(bool, UseInlineDepthForSpeculativeTypes, true, \
|
||||
|
@ -3007,22 +3007,28 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
||||
}
|
||||
|
||||
Node* cast_obj = NULL;
|
||||
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
||||
// We may not have profiling here or it may not help us. If we have
|
||||
// a speculative type use it to perform an exact cast.
|
||||
ciKlass* spec_obj_type = obj_type->speculative_type();
|
||||
if (spec_obj_type != NULL ||
|
||||
(data != NULL &&
|
||||
// Counter has never been decremented (due to cast failure).
|
||||
// ...This is a reasonable thing to expect. It is true of
|
||||
// all casts inserted by javac to implement generic types.
|
||||
data->as_CounterData()->count() >= 0)) {
|
||||
cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
|
||||
if (cast_obj != NULL) {
|
||||
if (failure_control != NULL) // failure is now impossible
|
||||
(*failure_control) = top();
|
||||
// adjust the type of the phi to the exact klass:
|
||||
phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR));
|
||||
if (tk->klass_is_exact()) {
|
||||
// The following optimization tries to statically cast the speculative type of the object
|
||||
// (for example obtained during profiling) to the type of the superklass and then do a
|
||||
// dynamic check that the type of the object is what we expect. To work correctly
|
||||
// for checkcast and aastore the type of superklass should be exact.
|
||||
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
||||
// We may not have profiling here or it may not help us. If we have
|
||||
// a speculative type use it to perform an exact cast.
|
||||
ciKlass* spec_obj_type = obj_type->speculative_type();
|
||||
if (spec_obj_type != NULL ||
|
||||
(data != NULL &&
|
||||
// Counter has never been decremented (due to cast failure).
|
||||
// ...This is a reasonable thing to expect. It is true of
|
||||
// all casts inserted by javac to implement generic types.
|
||||
data->as_CounterData()->count() >= 0)) {
|
||||
cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
|
||||
if (cast_obj != NULL) {
|
||||
if (failure_control != NULL) // failure is now impossible
|
||||
(*failure_control) = top();
|
||||
// adjust the type of the phi to the exact klass:
|
||||
phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1593,35 +1593,33 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls,
|
||||
|
||||
// Try to constant-fold a stable array element.
|
||||
static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) {
|
||||
assert(ary->const_oop(), "array should be constant");
|
||||
assert(ary->is_stable(), "array should be stable");
|
||||
|
||||
if (ary->const_oop() != NULL) {
|
||||
// Decode the results of GraphKit::array_element_address.
|
||||
ciArray* aobj = ary->const_oop()->as_array();
|
||||
ciConstant con = aobj->element_value_by_offset(off);
|
||||
// Decode the results of GraphKit::array_element_address.
|
||||
ciArray* aobj = ary->const_oop()->as_array();
|
||||
ciConstant con = aobj->element_value_by_offset(off);
|
||||
|
||||
if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
|
||||
const Type* con_type = Type::make_from_constant(con);
|
||||
if (con_type != NULL) {
|
||||
if (con_type->isa_aryptr()) {
|
||||
// Join with the array element type, in case it is also stable.
|
||||
int dim = ary->stable_dimension();
|
||||
con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
|
||||
}
|
||||
if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
|
||||
con_type = con_type->make_narrowoop();
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
if (TraceIterativeGVN) {
|
||||
tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
|
||||
con_type->dump(); tty->cr();
|
||||
}
|
||||
#endif //PRODUCT
|
||||
return con_type;
|
||||
if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
|
||||
const Type* con_type = Type::make_from_constant(con);
|
||||
if (con_type != NULL) {
|
||||
if (con_type->isa_aryptr()) {
|
||||
// Join with the array element type, in case it is also stable.
|
||||
int dim = ary->stable_dimension();
|
||||
con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
|
||||
}
|
||||
if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
|
||||
con_type = con_type->make_narrowoop();
|
||||
}
|
||||
#ifndef PRODUCT
|
||||
if (TraceIterativeGVN) {
|
||||
tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
|
||||
con_type->dump(); tty->cr();
|
||||
}
|
||||
#endif //PRODUCT
|
||||
return con_type;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1641,7 +1639,7 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
||||
// Try to guess loaded type from pointer type
|
||||
if (tp->isa_aryptr()) {
|
||||
const TypeAryPtr* ary = tp->is_aryptr();
|
||||
const Type *t = ary->elem();
|
||||
const Type* t = ary->elem();
|
||||
|
||||
// Determine whether the reference is beyond the header or not, by comparing
|
||||
// the offset against the offset of the start of the array's data.
|
||||
@ -1653,10 +1651,9 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
||||
const bool off_beyond_header = ((uint)off >= (uint)min_base_off);
|
||||
|
||||
// Try to constant-fold a stable array element.
|
||||
if (FoldStableValues && ary->is_stable()) {
|
||||
// Make sure the reference is not into the header
|
||||
if (off_beyond_header && off != Type::OffsetBot) {
|
||||
assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant");
|
||||
if (FoldStableValues && ary->is_stable() && ary->const_oop() != NULL) {
|
||||
// Make sure the reference is not into the header and the offset is constant
|
||||
if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) {
|
||||
const Type* con_type = fold_stable_ary_elem(ary, off, memory_type());
|
||||
if (con_type != NULL) {
|
||||
return con_type;
|
||||
|
@ -338,6 +338,8 @@ class Parse : public GraphKit {
|
||||
GraphKit _exits; // Record all normal returns and throws here.
|
||||
bool _wrote_final; // Did we write a final field?
|
||||
bool _wrote_volatile; // Did we write a volatile field?
|
||||
bool _wrote_stable; // Did we write a @Stable field?
|
||||
bool _wrote_fields; // Did we write any field?
|
||||
bool _count_invocations; // update and test invocation counter
|
||||
bool _method_data_update; // update method data oop
|
||||
Node* _alloc_with_final; // An allocation node with final field
|
||||
@ -383,6 +385,10 @@ class Parse : public GraphKit {
|
||||
void set_wrote_final(bool z) { _wrote_final = z; }
|
||||
bool wrote_volatile() const { return _wrote_volatile; }
|
||||
void set_wrote_volatile(bool z) { _wrote_volatile = z; }
|
||||
bool wrote_stable() const { return _wrote_stable; }
|
||||
void set_wrote_stable(bool z) { _wrote_stable = z; }
|
||||
bool wrote_fields() const { return _wrote_fields; }
|
||||
void set_wrote_fields(bool z) { _wrote_fields = z; }
|
||||
bool count_invocations() const { return _count_invocations; }
|
||||
bool method_data_update() const { return _method_data_update; }
|
||||
Node* alloc_with_final() const { return _alloc_with_final; }
|
||||
|
@ -391,6 +391,8 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses, Pars
|
||||
_depth = 1 + (caller->has_method() ? caller->depth() : 0);
|
||||
_wrote_final = false;
|
||||
_wrote_volatile = false;
|
||||
_wrote_stable = false;
|
||||
_wrote_fields = false;
|
||||
_alloc_with_final = NULL;
|
||||
_entry_bci = InvocationEntryBci;
|
||||
_tf = NULL;
|
||||
@ -908,26 +910,35 @@ void Parse::do_exits() {
|
||||
Node* iophi = _exits.i_o();
|
||||
_exits.set_i_o(gvn().transform(iophi));
|
||||
|
||||
// On PPC64, also add MemBarRelease for constructors which write
|
||||
// volatile fields. As support_IRIW_for_not_multiple_copy_atomic_cpu
|
||||
// is set on PPC64, no sync instruction is issued after volatile
|
||||
// stores. We want to quarantee the same behaviour as on platforms
|
||||
// with total store order, although this is not required by the Java
|
||||
// memory model. So as with finals, we add a barrier here.
|
||||
if (wrote_final() PPC64_ONLY(|| (wrote_volatile() && method()->is_initializer()))) {
|
||||
// This method (which must be a constructor by the rules of Java)
|
||||
// wrote a final. The effects of all initializations must be
|
||||
// committed to memory before any code after the constructor
|
||||
// publishes the reference to the newly constructor object.
|
||||
// Rather than wait for the publication, we simply block the
|
||||
// writes here. Rather than put a barrier on only those writes
|
||||
// which are required to complete, we force all writes to complete.
|
||||
//
|
||||
// "All bets are off" unless the first publication occurs after a
|
||||
// normal return from the constructor. We do not attempt to detect
|
||||
// such unusual early publications. But no barrier is needed on
|
||||
// exceptional returns, since they cannot publish normally.
|
||||
//
|
||||
// Figure out if we need to emit the trailing barrier. The barrier is only
|
||||
// needed in the constructors, and only in three cases:
|
||||
//
|
||||
// 1. The constructor wrote a final. The effects of all initializations
|
||||
// must be committed to memory before any code after the constructor
|
||||
// publishes the reference to the newly constructed object. Rather
|
||||
// than wait for the publication, we simply block the writes here.
|
||||
// Rather than put a barrier on only those writes which are required
|
||||
// to complete, we force all writes to complete.
|
||||
//
|
||||
// 2. On PPC64, also add MemBarRelease for constructors which write
|
||||
// volatile fields. As support_IRIW_for_not_multiple_copy_atomic_cpu
|
||||
// is set on PPC64, no sync instruction is issued after volatile
|
||||
// stores. We want to guarantee the same behavior as on platforms
|
||||
// with total store order, although this is not required by the Java
|
||||
// memory model. So as with finals, we add a barrier here.
|
||||
//
|
||||
// 3. Experimental VM option is used to force the barrier if any field
|
||||
// was written out in the constructor.
|
||||
//
|
||||
// "All bets are off" unless the first publication occurs after a
|
||||
// normal return from the constructor. We do not attempt to detect
|
||||
// such unusual early publications. But no barrier is needed on
|
||||
// exceptional returns, since they cannot publish normally.
|
||||
//
|
||||
if (method()->is_initializer() &&
|
||||
(wrote_final() ||
|
||||
PPC64_ONLY(wrote_volatile() ||)
|
||||
(AlwaysSafeConstructors && wrote_fields()))) {
|
||||
_exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final());
|
||||
#ifndef PRODUCT
|
||||
if (PrintOpto && (Verbose || WizardMode)) {
|
||||
@ -937,6 +948,19 @@ void Parse::do_exits() {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Any method can write a @Stable field; insert memory barriers after
|
||||
// those also. If there is a predecessor allocation node, bind the
|
||||
// barrier there.
|
||||
if (wrote_stable()) {
|
||||
_exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final());
|
||||
#ifndef PRODUCT
|
||||
if (PrintOpto && (Verbose || WizardMode)) {
|
||||
method()->print_name();
|
||||
tty->print_cr(" writes @Stable and needs a memory barrier");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (MergeMemStream mms(_exits.merged_memory()); mms.next_non_empty(); ) {
|
||||
// transform each slice of the original memphi:
|
||||
mms.set_memory(_gvn.transform(mms.memory()));
|
||||
|
@ -233,7 +233,8 @@ void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
|
||||
// Build the load.
|
||||
//
|
||||
MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered;
|
||||
Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, is_vol);
|
||||
bool needs_atomic_access = is_vol || AlwaysAtomicAccesses;
|
||||
Node* ld = make_load(NULL, adr, type, bt, adr_type, mo, needs_atomic_access);
|
||||
|
||||
// Adjust Java stack
|
||||
if (type2size[bt] == 1)
|
||||
@ -314,7 +315,8 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
|
||||
}
|
||||
store = store_oop_to_object(control(), obj, adr, adr_type, val, field_type, bt, mo);
|
||||
} else {
|
||||
store = store_to_memory(control(), adr, val, bt, adr_type, mo, is_vol);
|
||||
bool needs_atomic_access = is_vol || AlwaysAtomicAccesses;
|
||||
store = store_to_memory(control(), adr, val, bt, adr_type, mo, needs_atomic_access);
|
||||
}
|
||||
|
||||
// If reference is volatile, prevent following volatiles ops from
|
||||
@ -332,13 +334,23 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_field) {
|
||||
set_wrote_fields(true);
|
||||
}
|
||||
|
||||
// If the field is final, the rules of Java say we are in <init> or <clinit>.
|
||||
// Note the presence of writes to final non-static fields, so that we
|
||||
// can insert a memory barrier later on to keep the writes from floating
|
||||
// out of the constructor.
|
||||
// Any method can write a @Stable field; insert memory barriers after those also.
|
||||
if (is_field && (field->is_final() || field->is_stable())) {
|
||||
set_wrote_final(true);
|
||||
if (field->is_final()) {
|
||||
set_wrote_final(true);
|
||||
}
|
||||
if (field->is_stable()) {
|
||||
set_wrote_stable(true);
|
||||
}
|
||||
|
||||
// Preserve allocation ptr to create precedent edge to it in membar
|
||||
// generated on exit from constructor.
|
||||
if (C->eliminate_boxing() &&
|
||||
|
@ -2407,9 +2407,11 @@ bool Arguments::check_vm_args_consistency() {
|
||||
|
||||
status &= verify_interval(NmethodSweepFraction, 1, ReservedCodeCacheSize/K, "NmethodSweepFraction");
|
||||
status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity");
|
||||
status &= verify_interval(CodeCacheMinBlockLength, 1, 100, "CodeCacheMinBlockLength");
|
||||
status &= verify_interval(CodeCacheSegmentSize, 1, 1024, "CodeCacheSegmentSize");
|
||||
|
||||
// TieredCompilation needs at least 2 compiler threads.
|
||||
const int num_min_compiler_threads = (TieredCompilation) ? 2 : 1;
|
||||
const int num_min_compiler_threads = (TieredCompilation && (TieredStopAtLevel >= CompLevel_full_optimization)) ? 2 : 1;
|
||||
status &=verify_min_value(CICompilerCount, num_min_compiler_threads, "CICompilerCount");
|
||||
|
||||
return status;
|
||||
|
@ -535,6 +535,9 @@ class CommandLineFlags {
|
||||
develop(bool, CleanChunkPoolAsync, falseInEmbedded, \
|
||||
"Clean the chunk pool asynchronously") \
|
||||
\
|
||||
experimental(bool, AlwaysSafeConstructors, false, \
|
||||
"Force safe construction, as if all fields are final.") \
|
||||
\
|
||||
/* Temporary: See 6948537 */ \
|
||||
experimental(bool, UseMemSetInBOT, true, \
|
||||
"(Unstable) uses memset in BOT updates in GC code") \
|
||||
@ -811,8 +814,8 @@ class CommandLineFlags {
|
||||
product(bool, PrintOopAddress, false, \
|
||||
"Always print the location of the oop") \
|
||||
\
|
||||
notproduct(bool, VerifyCodeCacheOften, false, \
|
||||
"Verify compiled-code cache often") \
|
||||
notproduct(bool, VerifyCodeCache, false, \
|
||||
"Verify code cache on memory allocation/deallocation") \
|
||||
\
|
||||
develop(bool, ZapDeadCompiledLocals, false, \
|
||||
"Zap dead locals in compiler frames") \
|
||||
@ -2984,7 +2987,8 @@ class CommandLineFlags {
|
||||
"maximum number of nested recursive calls that are inlined") \
|
||||
\
|
||||
develop(intx, MaxForceInlineLevel, 100, \
|
||||
"maximum number of nested @ForceInline calls that are inlined") \
|
||||
"maximum number of nested calls that are forced for inlining " \
|
||||
"(using CompilerOracle or marked w/ @ForceInline)") \
|
||||
\
|
||||
product_pd(intx, InlineSmallCode, \
|
||||
"Only inline already compiled methods if their code size is " \
|
||||
@ -3292,8 +3296,8 @@ class CommandLineFlags {
|
||||
"disable this feature") \
|
||||
\
|
||||
/* code cache parameters */ \
|
||||
/* ppc64 has large code-entry alignment. */ \
|
||||
develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64), \
|
||||
/* ppc64/tiered compilation has large code-entry alignment. */ \
|
||||
develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64) NOT_PPC64(TIERED_ONLY(+64)),\
|
||||
"Code cache segment size (in bytes) - smallest unit of " \
|
||||
"allocation") \
|
||||
\
|
||||
@ -3795,8 +3799,8 @@ class CommandLineFlags {
|
||||
experimental(bool, TrustFinalNonStaticFields, false, \
|
||||
"trust final non-static declarations for constant folding") \
|
||||
\
|
||||
experimental(bool, FoldStableValues, false, \
|
||||
"Private flag to control optimizations for stable variables") \
|
||||
diagnostic(bool, FoldStableValues, true, \
|
||||
"Optimize loads from stable fields (marked w/ @Stable)") \
|
||||
\
|
||||
develop(bool, TraceInvokeDynamic, false, \
|
||||
"trace internal invoke dynamic operations") \
|
||||
@ -3864,6 +3868,9 @@ class CommandLineFlags {
|
||||
"Allocation less than this value will be allocated " \
|
||||
"using malloc. Larger allocations will use mmap.") \
|
||||
\
|
||||
experimental(bool, AlwaysAtomicAccesses, false, \
|
||||
"Accesses to all variables should always be atomic") \
|
||||
\
|
||||
product(bool, EnableTracing, false, \
|
||||
"Enable event-based tracing") \
|
||||
\
|
||||
|
@ -910,7 +910,7 @@ void Thread::check_for_valid_safepoint_state(bool potential_vm_operation) {
|
||||
cur != VMOperationRequest_lock &&
|
||||
cur != VMOperationQueue_lock) ||
|
||||
cur->rank() == Mutex::special) {
|
||||
warning("Thread holding lock at safepoint that vm can block on: %s", cur->name());
|
||||
fatal(err_msg("Thread holding lock at safepoint that vm can block on: %s", cur->name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,21 +36,43 @@
|
||||
#endif
|
||||
|
||||
#include <llvm/Analysis/Verifier.h>
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
|
||||
// includes specific to each version
|
||||
#if SHARK_LLVM_VERSION <= 31
|
||||
#include <llvm/Support/IRBuilder.h>
|
||||
#include <llvm/Type.h>
|
||||
#include <llvm/Argument.h>
|
||||
#include <llvm/Constants.h>
|
||||
#include <llvm/DerivedTypes.h>
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/Instructions.h>
|
||||
#include <llvm/LLVMContext.h>
|
||||
#include <llvm/Module.h>
|
||||
#if SHARK_LLVM_VERSION <= 31
|
||||
#include <llvm/Support/IRBuilder.h>
|
||||
#else
|
||||
#elif SHARK_LLVM_VERSION <= 32
|
||||
#include <llvm/IRBuilder.h>
|
||||
#include <llvm/Type.h>
|
||||
#include <llvm/Argument.h>
|
||||
#include <llvm/Constants.h>
|
||||
#include <llvm/DerivedTypes.h>
|
||||
#include <llvm/Instructions.h>
|
||||
#include <llvm/LLVMContext.h>
|
||||
#include <llvm/Module.h>
|
||||
#else // SHARK_LLVM_VERSION <= 34
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Argument.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/DerivedTypes.h>
|
||||
#include <llvm/ExecutionEngine/ExecutionEngine.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/ADT/StringRef.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#endif
|
||||
|
||||
// common includes
|
||||
#include <llvm/Support/Threading.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Type.h>
|
||||
#include <llvm/ExecutionEngine/JITMemoryManager.h>
|
||||
#include <llvm/Support/CommandLine.h>
|
||||
#include <llvm/ExecutionEngine/MCJIT.h>
|
||||
|
@ -364,3 +364,7 @@ const char* SharkCompiler::methodname(const char* klass, const char* method) {
|
||||
*(dst++) = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
void SharkCompiler::print_timers() {
|
||||
// do nothing
|
||||
}
|
||||
|
@ -56,6 +56,9 @@ class SharkCompiler : public AbstractCompiler {
|
||||
// Compile a normal (bytecode) method and install it in the VM
|
||||
void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
|
||||
|
||||
// Print compilation timers and statistics
|
||||
void print_timers();
|
||||
|
||||
// Generate a wrapper for a native (JNI) method
|
||||
nmethod* generate_native_wrapper(MacroAssembler* masm,
|
||||
methodHandle target,
|
||||
|
@ -744,6 +744,10 @@ bool SharkInlinerHelper::do_field_access(bool is_get, bool is_field) {
|
||||
}
|
||||
|
||||
bool SharkInliner::attempt_inline(ciMethod *target, SharkState *state) {
|
||||
if (!Inline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SharkIntrinsics::is_intrinsic(target)) {
|
||||
SharkIntrinsics::inline_intrinsic(target, state);
|
||||
return true;
|
||||
|
@ -59,18 +59,6 @@ void SharkMemoryManager::endFunctionBody(const Function* F,
|
||||
entry->set_code_limit(FunctionEnd);
|
||||
}
|
||||
|
||||
unsigned char* SharkMemoryManager::startExceptionTable(const Function* F,
|
||||
uintptr_t& ActualSize) {
|
||||
return mm()->startExceptionTable(F, ActualSize);
|
||||
}
|
||||
|
||||
void SharkMemoryManager::endExceptionTable(const Function* F,
|
||||
unsigned char* TableStart,
|
||||
unsigned char* TableEnd,
|
||||
unsigned char* FrameRegister) {
|
||||
mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
|
||||
}
|
||||
|
||||
void SharkMemoryManager::setMemoryWritable() {
|
||||
mm()->setMemoryWritable();
|
||||
}
|
||||
@ -79,10 +67,6 @@ void SharkMemoryManager::setMemoryExecutable() {
|
||||
mm()->setMemoryExecutable();
|
||||
}
|
||||
|
||||
void SharkMemoryManager::deallocateExceptionTable(void *ptr) {
|
||||
mm()->deallocateExceptionTable(ptr);
|
||||
}
|
||||
|
||||
void SharkMemoryManager::deallocateFunctionBody(void *ptr) {
|
||||
mm()->deallocateFunctionBody(ptr);
|
||||
}
|
||||
@ -96,14 +80,6 @@ void* SharkMemoryManager::getPointerToNamedFunction(const std::string &Name, boo
|
||||
return mm()->getPointerToNamedFunction(Name, AbortOnFailure);
|
||||
}
|
||||
|
||||
uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
|
||||
return mm()->allocateCodeSection(Size, Alignment, SectionID);
|
||||
}
|
||||
|
||||
uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
|
||||
return mm()->allocateDataSection(Size, Alignment, SectionID);
|
||||
}
|
||||
|
||||
void SharkMemoryManager::setPoisonMemory(bool poison) {
|
||||
mm()->setPoisonMemory(poison);
|
||||
}
|
||||
@ -112,3 +88,45 @@ unsigned char *SharkMemoryManager::allocateSpace(intptr_t Size,
|
||||
unsigned int Alignment) {
|
||||
return mm()->allocateSpace(Size, Alignment);
|
||||
}
|
||||
|
||||
#if SHARK_LLVM_VERSION <= 32
|
||||
|
||||
uint8_t* SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
|
||||
return mm()->allocateCodeSection(Size, Alignment, SectionID);
|
||||
}
|
||||
|
||||
uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) {
|
||||
return mm()->allocateDataSection(Size, Alignment, SectionID);
|
||||
}
|
||||
|
||||
void SharkMemoryManager::deallocateExceptionTable(void *ptr) {
|
||||
mm()->deallocateExceptionTable(ptr);
|
||||
}
|
||||
|
||||
unsigned char* SharkMemoryManager::startExceptionTable(const Function* F,
|
||||
uintptr_t& ActualSize) {
|
||||
return mm()->startExceptionTable(F, ActualSize);
|
||||
}
|
||||
|
||||
void SharkMemoryManager::endExceptionTable(const Function* F,
|
||||
unsigned char* TableStart,
|
||||
unsigned char* TableEnd,
|
||||
unsigned char* FrameRegister) {
|
||||
mm()->endExceptionTable(F, TableStart, TableEnd, FrameRegister);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
uint8_t *SharkMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName) {
|
||||
return mm()->allocateCodeSection(Size, Alignment, SectionID, SectionName);
|
||||
}
|
||||
|
||||
uint8_t* SharkMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, StringRef SectionName, bool IsReadOnly) {
|
||||
return mm()->allocateDataSection(Size, Alignment, SectionID, SectionName, IsReadOnly);
|
||||
}
|
||||
|
||||
bool SharkMemoryManager::finalizeMemory(std::string *ErrMsg) {
|
||||
return mm()->finalizeMemory(ErrMsg);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -69,23 +69,32 @@ class SharkMemoryManager : public llvm::JITMemoryManager {
|
||||
void endFunctionBody(const llvm::Function* F,
|
||||
unsigned char* FunctionStart,
|
||||
unsigned char* FunctionEnd);
|
||||
unsigned char* startExceptionTable(const llvm::Function* F,
|
||||
uintptr_t& ActualSize);
|
||||
void endExceptionTable(const llvm::Function* F,
|
||||
unsigned char* TableStart,
|
||||
unsigned char* TableEnd,
|
||||
unsigned char* FrameRegister);
|
||||
|
||||
void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true);
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
|
||||
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
|
||||
void setPoisonMemory(bool);
|
||||
uint8_t* allocateGlobal(uintptr_t, unsigned int);
|
||||
void setMemoryWritable();
|
||||
void setMemoryExecutable();
|
||||
void deallocateExceptionTable(void *ptr);
|
||||
void deallocateFunctionBody(void *ptr);
|
||||
unsigned char *allocateSpace(intptr_t Size,
|
||||
unsigned int Alignment);
|
||||
|
||||
#if SHARK_LLVM_VERSION <= 32
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
|
||||
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID);
|
||||
unsigned char* startExceptionTable(const llvm::Function* F,
|
||||
uintptr_t& ActualSize);
|
||||
void deallocateExceptionTable(void *ptr);
|
||||
void endExceptionTable(const llvm::Function* F,
|
||||
unsigned char* TableStart,
|
||||
unsigned char* TableEnd,
|
||||
unsigned char* FrameRegister);
|
||||
#else
|
||||
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName);
|
||||
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, llvm::StringRef SectionName, bool IsReadOnly);
|
||||
bool finalizeMemory(std::string *ErrMsg = 0);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_SHARK_SHARKMEMORYMANAGER_HPP
|
||||
|
@ -140,7 +140,7 @@ bool ElfFile::load_tables() {
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PPC64)
|
||||
#if defined(PPC64) && !defined(ABI_ELFv2)
|
||||
// Now read the .opd section wich contains the PPC64 function descriptor table.
|
||||
// The .opd section is only available on PPC64 (see for example:
|
||||
// http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html)
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/altHashing.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "code/dependencies.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/filemap.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -353,116 +352,6 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load)
|
||||
#endif
|
||||
|
||||
|
||||
template<class T, class M> GenericHashtable<T, M>::GenericHashtable(int size, bool C_heap, MEMFLAGS memflag) {
|
||||
assert(size > 0, " Invalid hashtable size");
|
||||
_size = size;
|
||||
_C_heap = C_heap;
|
||||
_memflag = memflag;
|
||||
// Perform subtype-specific resource allocation
|
||||
_items = (C_heap) ? NEW_C_HEAP_ARRAY(T*, size, memflag) : NEW_RESOURCE_ARRAY(T*, size);
|
||||
memset(_items, 0, sizeof(T*) * size);
|
||||
|
||||
DEBUG_ONLY(_num_items = 0;)
|
||||
}
|
||||
|
||||
template<class T, class M> GenericHashtable<T, M>::~GenericHashtable() {
|
||||
if (on_C_heap()) {
|
||||
// Check backing array
|
||||
for (int i = 0; i < size(); i++) {
|
||||
T* item = head(i);
|
||||
// Delete all items in linked list
|
||||
while (item != NULL) {
|
||||
T* next_item = item->next();
|
||||
delete item;
|
||||
DEBUG_ONLY(_num_items--);
|
||||
item = next_item;
|
||||
}
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(T*, _items, _memflag);
|
||||
_items = NULL;
|
||||
assert (_num_items == 0, "Not all memory released");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a pointer to the item 'I' that is stored in the hashtable for
|
||||
* which match_item->equals(I) == true. If no such item is found, NULL
|
||||
* is returned.
|
||||
*/
|
||||
template<class T, class F> T* GenericHashtable<T, F>::contains(T* match_item) {
|
||||
if (match_item != NULL) {
|
||||
int idx = index(match_item);
|
||||
return contains_impl(match_item, idx);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item to the hashtable. Return 'true' if the item was added
|
||||
* and false otherwise.
|
||||
*/
|
||||
template<class T, class F> bool GenericHashtable<T, F>::add(T* item) {
|
||||
if (item != NULL) {
|
||||
int idx = index(item);
|
||||
T* found_item = contains_impl(item, idx);
|
||||
if (found_item == NULL) {
|
||||
T* list_head = head(idx);
|
||||
item->set_next(list_head);
|
||||
item->set_prev(NULL);
|
||||
|
||||
if (list_head != NULL) {
|
||||
list_head->set_prev(item);
|
||||
}
|
||||
set_head(item, idx);
|
||||
DEBUG_ONLY(_num_items++);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an item 'I' from the hashtable, if present. 'I' is removed, if
|
||||
* match_item->equals(I) == true. Removing an item from the hashtable does
|
||||
* not free memory.
|
||||
*/
|
||||
template<class T, class F> T* GenericHashtable<T, F>::remove(T* match_item) {
|
||||
if (match_item != NULL) {
|
||||
int idx = index(match_item);
|
||||
T* found_item = contains_impl(match_item, idx);
|
||||
if (found_item != NULL) {
|
||||
// Remove item from linked list
|
||||
T* prev = found_item->prev();
|
||||
T* next = found_item->next();
|
||||
if (prev != NULL) {
|
||||
prev->set_next(next);
|
||||
} else {
|
||||
set_head(next, idx);
|
||||
}
|
||||
if (next != NULL) {
|
||||
next->set_prev(prev);
|
||||
}
|
||||
|
||||
DEBUG_ONLY(_num_items--);
|
||||
return found_item;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
template<class T, class F> T* GenericHashtable<T, F>::contains_impl(T* item, int idx) {
|
||||
T* current_item = head(idx);
|
||||
while (current_item != NULL) {
|
||||
if (current_item->equals(item)) {
|
||||
return current_item;
|
||||
}
|
||||
current_item = current_item->next();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Explicitly instantiate these types
|
||||
template class Hashtable<ConstantPool*, mtClass>;
|
||||
template class Hashtable<Symbol*, mtSymbol>;
|
||||
@ -482,5 +371,3 @@ template class BasicHashtable<mtClass>;
|
||||
template class BasicHashtable<mtSymbol>;
|
||||
template class BasicHashtable<mtCode>;
|
||||
template class BasicHashtable<mtInternal>;
|
||||
|
||||
template class GenericHashtable<DependencySignature, ResourceObj>;
|
||||
|
@ -327,86 +327,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Usage of GenericHashtable:
|
||||
*
|
||||
* class X : public GenericHashtableEntry<X, ResourceObj> {
|
||||
*
|
||||
* // Implement virtual functions in class X
|
||||
* bool equals(X* sig) const;
|
||||
* uintptr_t hash() const;
|
||||
* };
|
||||
*
|
||||
* void foo() {
|
||||
* GenericHashtable<X, ResourceObj>* table = new GenericHashtable<X, ResourceObj>(11027, false);
|
||||
*
|
||||
* X* elem = new X();
|
||||
* table->add(elem);
|
||||
* table->contains(elem);
|
||||
* }
|
||||
*
|
||||
* You can choose other allocation types as well. For example, to store the hashtable to a
|
||||
* particular region (CHeapObj<type>) simply replace ResourceObj with the desired type:
|
||||
*
|
||||
* class X : public GenericHashtableEntry<X, CHeapObj<mtCode> > { ... };
|
||||
*
|
||||
* To make the destructor (and remove) of the hashtable work:
|
||||
* 1) override the delete operator of X
|
||||
* 2) provide a destructor of the X
|
||||
*
|
||||
* You may also find it convenient to override the new operator.
|
||||
*
|
||||
* If you use this templates do not forget to add an explicit initialization
|
||||
* (at the end of hashtable.cpp).
|
||||
*
|
||||
* template class GenericHashtable<X, ResourceObj>;
|
||||
*/
|
||||
template <class T, class M> class GenericHashtableEntry : public M {
|
||||
private:
|
||||
T* _next;
|
||||
T* _prev;
|
||||
public:
|
||||
// Must be implemented by subclass.
|
||||
virtual uintptr_t key() const = 0;
|
||||
virtual bool equals(T* other) const = 0;
|
||||
|
||||
T* next() const { return _next; }
|
||||
T* prev() const { return _prev; }
|
||||
void set_next(T* item) { _next = item; }
|
||||
void set_prev(T* item) { _prev = item; }
|
||||
|
||||
// Constructor and destructor
|
||||
GenericHashtableEntry() : _next(NULL), _prev(NULL) { };
|
||||
virtual ~GenericHashtableEntry() {};
|
||||
};
|
||||
|
||||
template <class T, class M> class GenericHashtable : public M {
|
||||
private:
|
||||
T** _items;
|
||||
int _size;
|
||||
bool _C_heap;
|
||||
MEMFLAGS _memflag;
|
||||
|
||||
// Accessor methods
|
||||
T* head (int idx) const { return _items[idx]; }
|
||||
void set_head(T* item, int idx) { _items[idx] = item; }
|
||||
int index (T* item) { assert(item != NULL, "missing null check"); return item->key() % size(); }
|
||||
|
||||
// Helper function
|
||||
T* contains_impl(T* item, int idx);
|
||||
|
||||
DEBUG_ONLY(int _num_items;)
|
||||
public:
|
||||
GenericHashtable(int size, bool C_heap = false, MEMFLAGS memflag = mtNone);
|
||||
~GenericHashtable();
|
||||
T* contains(T* match_item);
|
||||
T* remove (T* match_item);
|
||||
bool add (T* item);
|
||||
|
||||
|
||||
bool on_C_heap() const { return _C_heap; }
|
||||
int size() const { return _size; }
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_UTILITIES_HASHTABLE_HPP
|
||||
|
@ -105,14 +105,20 @@ class ResourceHashtable : public ResourceObj {
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts or replaces a value in the table
|
||||
void put(K const& key, V const& value) {
|
||||
/**
|
||||
* Inserts or replaces a value in the table.
|
||||
* @return: true: if a new item is added
|
||||
* false: if the item already existed and the value is updated
|
||||
*/
|
||||
bool put(K const& key, V const& value) {
|
||||
unsigned hv = HASH(key);
|
||||
Node** ptr = lookup_node(hv, key);
|
||||
if (*ptr != NULL) {
|
||||
(*ptr)->_value = value;
|
||||
return false;
|
||||
} else {
|
||||
*ptr = new Node(hv, key, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -592,13 +592,24 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
// Compiled code may use EBP register on x86 so it looks like
|
||||
// non-walkable C frame. Use frame.sender() for java frames.
|
||||
if (_thread && _thread->is_Java_thread() && fr.is_java_frame()) {
|
||||
RegisterMap map((JavaThread*)_thread, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
continue;
|
||||
if (_thread && _thread->is_Java_thread()) {
|
||||
// Catch very first native frame by using stack address.
|
||||
// For JavaThread stack_base and stack_size should be set.
|
||||
if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) {
|
||||
break;
|
||||
}
|
||||
if (fr.is_java_frame()) {
|
||||
RegisterMap map((JavaThread*)_thread, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
} else {
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
|
||||
if (count > StackPrintLimit) {
|
||||
|
@ -130,7 +130,9 @@ needs_compact3 = \
|
||||
gc/arguments/TestG1HeapRegionSize.java \
|
||||
gc/metaspace/TestMetaspaceMemoryPool.java \
|
||||
runtime/InternalApi/ThreadCpuTimesDeadlock.java \
|
||||
serviceability/threads/TestFalseDeadLock.java
|
||||
serviceability/threads/TestFalseDeadLock.java \
|
||||
compiler/tiered/NonTieredLevelsTest.java \
|
||||
compiler/tiered/TieredLevelsTest.java
|
||||
|
||||
# Compact 2 adds full VM tests
|
||||
compact2 = \
|
||||
|
@ -78,8 +78,8 @@ then
|
||||
positive_test `expr $stop_level + 50` "TIERED LEVEL $stop_level :: REPLAY" \
|
||||
"-XX:TieredStopAtLevel=$stop_level"
|
||||
stop_level=`expr $stop_level + 1`
|
||||
cleanup
|
||||
done
|
||||
cleanup
|
||||
fi
|
||||
|
||||
echo TEST PASSED
|
||||
|
@ -99,13 +99,12 @@ common_tests() {
|
||||
# $2 - non-tiered comp_level
|
||||
nontiered_tests() {
|
||||
level=`grep "^compile " $replay_data | awk '{print $6}'`
|
||||
# is level available in non-tiere
|
||||
# is level available in non-tiered
|
||||
if [ "$level" -eq $2 ]
|
||||
then
|
||||
positive_test $1 "NON-TIERED :: AVAILABLE COMP_LEVEL" \
|
||||
-XX:-TieredCompilation
|
||||
else
|
||||
negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \
|
||||
negative_test `expr $1 + 1` "NON-TIERED :: UNAVAILABLE COMP_LEVEL" \
|
||||
-XX:-TieredCompilation
|
||||
fi
|
||||
|
58
hotspot/test/compiler/inlining/InlineDefaultMethod1.java
Normal file
58
hotspot/test/compiler/inlining/InlineDefaultMethod1.java
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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 8036100
|
||||
* @summary Default method returns true for a while, and then returns false
|
||||
* @run main/othervm -Xcomp -XX:CompileOnly=InlineDefaultMethod1::test
|
||||
* -XX:CompileOnly=I1::m -XX:CompileOnly=I2::m
|
||||
* InlineDefaultMethod1
|
||||
*/
|
||||
interface I1 {
|
||||
default public int m() { return 0; }
|
||||
}
|
||||
|
||||
interface I2 extends I1 {
|
||||
default public int m() { return 1; }
|
||||
}
|
||||
|
||||
abstract class A implements I1 {
|
||||
}
|
||||
|
||||
class B extends A implements I2 {
|
||||
}
|
||||
|
||||
public class InlineDefaultMethod1 {
|
||||
public static void test(A obj) {
|
||||
int id = obj.m();
|
||||
if (id != 1) {
|
||||
throw new AssertionError("Called wrong method: 1 != "+id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
test(new B());
|
||||
System.out.println("TEST PASSED");
|
||||
}
|
||||
}
|
@ -25,9 +25,9 @@
|
||||
* @test
|
||||
* @bug 8007898
|
||||
* @summary Incorrect optimization of Memory Barriers in Matcher::post_store_load_barrier().
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:+StressGCM -XX:+StressLCM DekkerTest
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:CICompilerCount=1 -XX:-TieredCompilation -XX:+StressGCM -XX:+StressLCM DekkerTest
|
||||
* @author Martin Doerr martin DOT doerr AT sap DOT com
|
||||
*
|
||||
* Run 3 times since the failure is intermittent.
|
||||
|
627
hotspot/test/compiler/stable/TestStableBoolean.java
Normal file
627
hotspot/test/compiler/stable/TestStableBoolean.java
Normal file
@ -0,0 +1,627 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableBoolean
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableBoolean.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableBoolean
|
||||
* java/lang/invoke/TestStableBoolean$BooleanStable
|
||||
* java/lang/invoke/TestStableBoolean$StaticBooleanStable
|
||||
* java/lang/invoke/TestStableBoolean$VolatileBooleanStable
|
||||
* java/lang/invoke/TestStableBoolean$BooleanArrayDim1
|
||||
* java/lang/invoke/TestStableBoolean$BooleanArrayDim2
|
||||
* java/lang/invoke/TestStableBoolean$BooleanArrayDim3
|
||||
* java/lang/invoke/TestStableBoolean$BooleanArrayDim4
|
||||
* java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField$A
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField1
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField2
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField3
|
||||
* java/lang/invoke/TestStableBoolean$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableBoolean$DefaultValue
|
||||
* java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableBoolean
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableBoolean
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableBoolean
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableBoolean
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableBoolean {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(BooleanStable.class);
|
||||
run(StaticBooleanStable.class);
|
||||
run(VolatileBooleanStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(BooleanArrayDim1.class);
|
||||
run(BooleanArrayDim2.class);
|
||||
run(BooleanArrayDim3.class);
|
||||
run(BooleanArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable boolean v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static boolean get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
boolean val1 = get();
|
||||
c.v = true; boolean val2 = get();
|
||||
assertEquals(val1, false);
|
||||
assertEquals(val2, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class BooleanStable {
|
||||
public @Stable boolean v;
|
||||
|
||||
public static final BooleanStable c = new BooleanStable();
|
||||
public static boolean get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = true; boolean val1 = get();
|
||||
c.v = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticBooleanStable {
|
||||
public static @Stable boolean v;
|
||||
|
||||
public static final StaticBooleanStable c = new StaticBooleanStable();
|
||||
public static boolean get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = true; boolean val1 = get();
|
||||
c.v = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileBooleanStable {
|
||||
public @Stable volatile boolean v;
|
||||
|
||||
public static final VolatileBooleanStable c = new VolatileBooleanStable();
|
||||
public static boolean get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = true; boolean val1 = get();
|
||||
c.v = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class BooleanArrayDim1 {
|
||||
public @Stable boolean[] v;
|
||||
|
||||
public static final BooleanArrayDim1 c = new BooleanArrayDim1();
|
||||
public static boolean get() { return c.v[0]; }
|
||||
public static boolean get1() { return c.v[10]; }
|
||||
public static boolean[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1]; c.v[0] = true; boolean val1 = get();
|
||||
c.v[0] = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[20]; c.v[10] = true; boolean val1 = get1();
|
||||
c.v[10] = false; boolean val2 = get1();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1]; boolean[] val1 = get2();
|
||||
c.v = new boolean[1]; boolean[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class BooleanArrayDim2 {
|
||||
public @Stable boolean[][] v;
|
||||
|
||||
public static final BooleanArrayDim2 c = new BooleanArrayDim2();
|
||||
public static boolean get() { return c.v[0][0]; }
|
||||
public static boolean[] get1() { return c.v[0]; }
|
||||
public static boolean[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1][1]; c.v[0][0] = true; boolean val1 = get();
|
||||
c.v[0][0] = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
|
||||
c.v = new boolean[1][1]; c.v[0][0] = false; boolean val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
|
||||
c.v[0] = new boolean[1]; c.v[0][0] = false; boolean val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? true : false));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1]; boolean[] val1 = get1();
|
||||
c.v[0] = new boolean[1]; boolean[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1]; boolean[][] val1 = get2();
|
||||
c.v = new boolean[1][1]; boolean[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class BooleanArrayDim3 {
|
||||
public @Stable boolean[][][] v;
|
||||
|
||||
public static final BooleanArrayDim3 c = new BooleanArrayDim3();
|
||||
public static boolean get() { return c.v[0][0][0]; }
|
||||
public static boolean[] get1() { return c.v[0][0]; }
|
||||
public static boolean[][] get2() { return c.v[0]; }
|
||||
public static boolean[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1][1][1]; c.v[0][0][0] = true; boolean val1 = get();
|
||||
c.v[0][0][0] = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
|
||||
c.v = new boolean[1][1][1]; c.v[0][0][0] = false; boolean val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
|
||||
c.v[0] = new boolean[1][1]; c.v[0][0][0] = false; boolean val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? true : false));
|
||||
|
||||
c.v[0][0] = new boolean[1]; c.v[0][0][0] = false; boolean val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? true : false));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1]; boolean[] val1 = get1();
|
||||
c.v[0][0] = new boolean[1]; boolean[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1]; boolean[][] val1 = get2();
|
||||
c.v[0] = new boolean[1][1]; boolean[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1]; boolean[][][] val1 = get3();
|
||||
c.v = new boolean[1][1][1]; boolean[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class BooleanArrayDim4 {
|
||||
public @Stable boolean[][][][] v;
|
||||
|
||||
public static final BooleanArrayDim4 c = new BooleanArrayDim4();
|
||||
public static boolean get() { return c.v[0][0][0][0]; }
|
||||
public static boolean[] get1() { return c.v[0][0][0]; }
|
||||
public static boolean[][] get2() { return c.v[0][0]; }
|
||||
public static boolean[][][] get3() { return c.v[0]; }
|
||||
public static boolean[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = true; boolean val1 = get();
|
||||
c.v[0][0][0][0] = false; boolean val2 = get();
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
|
||||
c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = false; boolean val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
|
||||
c.v[0] = new boolean[1][1][1]; c.v[0][0][0][0] = false; boolean val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? true : false));
|
||||
|
||||
c.v[0][0] = new boolean[1][1]; c.v[0][0][0][0] = false; boolean val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? true : false));
|
||||
|
||||
c.v[0][0][0] = new boolean[1]; c.v[0][0][0][0] = false; boolean val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? true : false));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1][1]; boolean[] val1 = get1();
|
||||
c.v[0][0][0] = new boolean[1]; boolean[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1][1]; boolean[][] val1 = get2();
|
||||
c.v[0][0] = new boolean[1][1]; boolean[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1][1]; boolean[][][] val1 = get3();
|
||||
c.v[0] = new boolean[1][1][1]; boolean[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1][1]; boolean[][][][] val1 = get4();
|
||||
c.v = new boolean[1][1][1][1]; boolean[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static boolean get() { return ((boolean[])c.v)[0]; }
|
||||
public static boolean[] get1() { return (boolean[])c.v; }
|
||||
public static boolean[] get2() { return (boolean[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1]; ((boolean[])c.v)[0] = true; boolean val1 = get();
|
||||
((boolean[])c.v)[0] = false; boolean val2 = get();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, false);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1]; boolean[] val1 = get1();
|
||||
c.v = new boolean[1]; boolean[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static boolean get() { return ((boolean[][])c.v)[0][0]; }
|
||||
public static boolean[] get1() { return (boolean[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1][1]; ((boolean[][])c.v)[0][0] = true; boolean val1 = get();
|
||||
((boolean[][])c.v)[0][0] = false; boolean val2 = get();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, false);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1]; c.v[0] = new boolean[0]; boolean[] val1 = get1();
|
||||
c.v[0] = new boolean[0]; boolean[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[0][0]; Object[] val1 = get2();
|
||||
c.v = new boolean[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static boolean get() { return ((boolean[][][])c.v)[0][0][0]; }
|
||||
public static boolean[] get1() { return (boolean[])(c.v[0][0]); }
|
||||
public static boolean[][] get2() { return (boolean[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new boolean[1][1][1]; ((boolean[][][])c.v)[0][0][0] = true; boolean val1 = get();
|
||||
((boolean[][][])c.v)[0][0][0] = false; boolean val2 = get();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, false);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1]; c.v[0][0] = new boolean[0]; boolean[] val1 = get1();
|
||||
c.v[0][0] = new boolean[0]; boolean[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[1][1][1]; c.v[0] = new boolean[0][0]; boolean[][] val1 = get2();
|
||||
c.v[0] = new boolean[0][0]; boolean[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new boolean[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new boolean[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable boolean a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static boolean get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = true; A val1 = get();
|
||||
c.v.a = false; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, false);
|
||||
assertEquals(val2.a, false);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = true; boolean val1 = get1();
|
||||
c.v.a = false; boolean val2 = get1();
|
||||
c.v = new A(); c.v.a = false; boolean val3 = get1();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable boolean a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static boolean get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = true; c.v.next.a = true; A val1 = get();
|
||||
c.v.a = false; c.v.next.a = false; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, false);
|
||||
assertEquals(val2.a, false);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = true; boolean val1 = get1();
|
||||
c.v.a = false; boolean val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = false; boolean val3 = get1();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val2, (isStableEnabled ? true : false));
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable boolean a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static boolean get() { return c.v.left.left.left.a; }
|
||||
public static boolean get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = true; boolean val1 = get(); boolean val2 = get1();
|
||||
c.v.a = false; boolean val3 = get(); boolean val4 = get1();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
|
||||
assertEquals(val2, true);
|
||||
assertEquals(val4, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable boolean a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static boolean get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static boolean get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = true; boolean val1 = get(); boolean val2 = get1();
|
||||
elem.a = false; boolean val3 = get(); boolean val4 = get1();
|
||||
|
||||
assertEquals(val1, true);
|
||||
assertEquals(val3, (isStableEnabled ? true : false));
|
||||
|
||||
assertEquals(val2, true);
|
||||
assertEquals(val4, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(boolean i, boolean j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
632
hotspot/test/compiler/stable/TestStableByte.java
Normal file
632
hotspot/test/compiler/stable/TestStableByte.java
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableByte
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableByte.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableByte
|
||||
* java/lang/invoke/TestStableByte$ByteStable
|
||||
* java/lang/invoke/TestStableByte$StaticByteStable
|
||||
* java/lang/invoke/TestStableByte$VolatileByteStable
|
||||
* java/lang/invoke/TestStableByte$ByteArrayDim1
|
||||
* java/lang/invoke/TestStableByte$ByteArrayDim2
|
||||
* java/lang/invoke/TestStableByte$ByteArrayDim3
|
||||
* java/lang/invoke/TestStableByte$ByteArrayDim4
|
||||
* java/lang/invoke/TestStableByte$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableByte$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableByte$NestedStableField
|
||||
* java/lang/invoke/TestStableByte$NestedStableField$A
|
||||
* java/lang/invoke/TestStableByte$NestedStableField1
|
||||
* java/lang/invoke/TestStableByte$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableByte$NestedStableField2
|
||||
* java/lang/invoke/TestStableByte$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableByte$NestedStableField3
|
||||
* java/lang/invoke/TestStableByte$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableByte$DefaultValue
|
||||
* java/lang/invoke/TestStableByte$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableByte
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableByte
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableByte
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableByte
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableByte {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(ByteStable.class);
|
||||
run(StaticByteStable.class);
|
||||
run(VolatileByteStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(ByteArrayDim1.class);
|
||||
run(ByteArrayDim2.class);
|
||||
run(ByteArrayDim3.class);
|
||||
run(ByteArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable byte v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static byte get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
byte val1 = get();
|
||||
c.v = 1; byte val2 = get();
|
||||
assertEquals(val1, 0);
|
||||
assertEquals(val2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ByteStable {
|
||||
public @Stable byte v;
|
||||
|
||||
public static final ByteStable c = new ByteStable();
|
||||
public static byte get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 5; byte val1 = get();
|
||||
c.v = 127; byte val2 = get();
|
||||
assertEquals(val1, 5);
|
||||
assertEquals(val2, (isStableEnabled ? 5 : 127));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticByteStable {
|
||||
public static @Stable byte v;
|
||||
|
||||
public static final StaticByteStable c = new StaticByteStable();
|
||||
public static byte get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 5; byte val1 = get();
|
||||
c.v = 127; byte val2 = get();
|
||||
assertEquals(val1, 5);
|
||||
assertEquals(val2, (isStableEnabled ? 5 : 127));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileByteStable {
|
||||
public @Stable volatile byte v;
|
||||
|
||||
public static final VolatileByteStable c = new VolatileByteStable();
|
||||
public static byte get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 5; byte val1 = get();
|
||||
c.v = 127; byte val2 = get();
|
||||
assertEquals(val1, 5);
|
||||
assertEquals(val2, (isStableEnabled ? 5 : 127));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class ByteArrayDim1 {
|
||||
public @Stable byte[] v;
|
||||
|
||||
public static final ByteArrayDim1 c = new ByteArrayDim1();
|
||||
public static byte get() { return c.v[0]; }
|
||||
public static byte get1() { return c.v[10]; }
|
||||
public static byte[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1]; c.v[0] = 1; byte val1 = get();
|
||||
c.v[0] = 2; byte val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new byte[1]; c.v[0] = 3; byte val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[20]; c.v[10] = 1; byte val1 = get1();
|
||||
c.v[10] = 2; byte val2 = get1();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new byte[20]; c.v[10] = 3; byte val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1]; byte[] val1 = get2();
|
||||
c.v = new byte[1]; byte[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ByteArrayDim2 {
|
||||
public @Stable byte[][] v;
|
||||
|
||||
public static final ByteArrayDim2 c = new ByteArrayDim2();
|
||||
public static byte get() { return c.v[0][0]; }
|
||||
public static byte[] get1() { return c.v[0]; }
|
||||
public static byte[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1][1]; c.v[0][0] = 1; byte val1 = get();
|
||||
c.v[0][0] = 2; byte val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new byte[1][1]; c.v[0][0] = 3; byte val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new byte[1]; c.v[0][0] = 4; byte val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1]; byte[] val1 = get1();
|
||||
c.v[0] = new byte[1]; byte[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1]; byte[][] val1 = get2();
|
||||
c.v = new byte[1][1]; byte[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ByteArrayDim3 {
|
||||
public @Stable byte[][][] v;
|
||||
|
||||
public static final ByteArrayDim3 c = new ByteArrayDim3();
|
||||
public static byte get() { return c.v[0][0][0]; }
|
||||
public static byte[] get1() { return c.v[0][0]; }
|
||||
public static byte[][] get2() { return c.v[0]; }
|
||||
public static byte[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1][1][1]; c.v[0][0][0] = 1; byte val1 = get();
|
||||
c.v[0][0][0] = 2; byte val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new byte[1][1][1]; c.v[0][0][0] = 3; byte val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new byte[1][1]; c.v[0][0][0] = 4; byte val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new byte[1]; c.v[0][0][0] = 5; byte val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1]; byte[] val1 = get1();
|
||||
c.v[0][0] = new byte[1]; byte[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1]; byte[][] val1 = get2();
|
||||
c.v[0] = new byte[1][1]; byte[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1]; byte[][][] val1 = get3();
|
||||
c.v = new byte[1][1][1]; byte[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ByteArrayDim4 {
|
||||
public @Stable byte[][][][] v;
|
||||
|
||||
public static final ByteArrayDim4 c = new ByteArrayDim4();
|
||||
public static byte get() { return c.v[0][0][0][0]; }
|
||||
public static byte[] get1() { return c.v[0][0][0]; }
|
||||
public static byte[][] get2() { return c.v[0][0]; }
|
||||
public static byte[][][] get3() { return c.v[0]; }
|
||||
public static byte[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 1; byte val1 = get();
|
||||
c.v[0][0][0][0] = 2; byte val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 3; byte val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new byte[1][1][1]; c.v[0][0][0][0] = 4; byte val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new byte[1][1]; c.v[0][0][0][0] = 5; byte val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
|
||||
c.v[0][0][0] = new byte[1]; c.v[0][0][0][0] = 6; byte val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 1 : 6));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1][1]; byte[] val1 = get1();
|
||||
c.v[0][0][0] = new byte[1]; byte[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1][1]; byte[][] val1 = get2();
|
||||
c.v[0][0] = new byte[1][1]; byte[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1][1]; byte[][][] val1 = get3();
|
||||
c.v[0] = new byte[1][1][1]; byte[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1][1]; byte[][][][] val1 = get4();
|
||||
c.v = new byte[1][1][1][1]; byte[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static byte get() { return ((byte[])c.v)[0]; }
|
||||
public static byte[] get1() { return (byte[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1]; ((byte[])c.v)[0] = 1; byte val1 = get();
|
||||
((byte[])c.v)[0] = 2; byte val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1]; byte[] val1 = get1();
|
||||
c.v = new byte[1]; byte[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static byte get() { return ((byte[][])c.v)[0][0]; }
|
||||
public static byte[] get1() { return (byte[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1][1]; ((byte[][])c.v)[0][0] = 1; byte val1 = get();
|
||||
((byte[][])c.v)[0][0] = 2; byte val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1]; c.v[0] = new byte[0]; byte[] val1 = get1();
|
||||
c.v[0] = new byte[0]; byte[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[0][0]; Object[] val1 = get2();
|
||||
c.v = new byte[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static byte get() { return ((byte[][][])c.v)[0][0][0]; }
|
||||
public static byte[] get1() { return (byte[])(c.v[0][0]); }
|
||||
public static byte[][] get2() { return (byte[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new byte[1][1][1]; ((byte[][][])c.v)[0][0][0] = 1; byte val1 = get();
|
||||
((byte[][][])c.v)[0][0][0] = 2; byte val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1]; c.v[0][0] = new byte[0]; byte[] val1 = get1();
|
||||
c.v[0][0] = new byte[0]; byte[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[1][1][1]; c.v[0] = new byte[0][0]; byte[][] val1 = get2();
|
||||
c.v[0] = new byte[0][0]; byte[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new byte[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new byte[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable byte a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static byte get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; A val1 = get();
|
||||
c.v.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; byte val1 = get1();
|
||||
c.v.a = 2; byte val2 = get1();
|
||||
c.v = new A(); c.v.a = 3; byte val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable byte a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static byte get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 1; c.v.next.a = 1; A val1 = get();
|
||||
c.v.a = 2; c.v.next.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 1; byte val1 = get1();
|
||||
c.v.a = 2; byte val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 3; byte val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable byte a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static byte get() { return c.v.left.left.left.a; }
|
||||
public static byte get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 1; byte val1 = get(); byte val2 = get1();
|
||||
c.v.a = 2; byte val3 = get(); byte val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable byte a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static byte get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static byte get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 1; byte val1 = get(); byte val2 = get1();
|
||||
elem.a = 2; byte val3 = get(); byte val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
631
hotspot/test/compiler/stable/TestStableChar.java
Normal file
631
hotspot/test/compiler/stable/TestStableChar.java
Normal file
@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableChar
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableChar.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableChar
|
||||
* java/lang/invoke/TestStableChar$CharStable
|
||||
* java/lang/invoke/TestStableChar$StaticCharStable
|
||||
* java/lang/invoke/TestStableChar$VolatileCharStable
|
||||
* java/lang/invoke/TestStableChar$CharArrayDim1
|
||||
* java/lang/invoke/TestStableChar$CharArrayDim2
|
||||
* java/lang/invoke/TestStableChar$CharArrayDim3
|
||||
* java/lang/invoke/TestStableChar$CharArrayDim4
|
||||
* java/lang/invoke/TestStableChar$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableChar$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableChar$NestedStableField
|
||||
* java/lang/invoke/TestStableChar$NestedStableField$A
|
||||
* java/lang/invoke/TestStableChar$NestedStableField1
|
||||
* java/lang/invoke/TestStableChar$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableChar$NestedStableField2
|
||||
* java/lang/invoke/TestStableChar$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableChar$NestedStableField3
|
||||
* java/lang/invoke/TestStableChar$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableChar$DefaultValue
|
||||
* java/lang/invoke/TestStableChar$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableChar
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableChar
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableChar
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableChar
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableChar {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(CharStable.class);
|
||||
run(StaticCharStable.class);
|
||||
run(VolatileCharStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(CharArrayDim1.class);
|
||||
run(CharArrayDim2.class);
|
||||
run(CharArrayDim3.class);
|
||||
run(CharArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable char v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static char get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
char val1 = get();
|
||||
c.v = 'a'; char val2 = get();
|
||||
assertEquals(val1, 0);
|
||||
assertEquals(val2, 'a');
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class CharStable {
|
||||
public @Stable char v;
|
||||
|
||||
public static final CharStable c = new CharStable();
|
||||
public static char get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 'a'; char val1 = get();
|
||||
c.v = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticCharStable {
|
||||
public @Stable char v;
|
||||
|
||||
public static final StaticCharStable c = new StaticCharStable();
|
||||
public static char get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 'a'; char val1 = get();
|
||||
c.v = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileCharStable {
|
||||
public @Stable volatile char v;
|
||||
|
||||
public static final VolatileCharStable c = new VolatileCharStable();
|
||||
public static char get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 'a'; char val1 = get();
|
||||
c.v = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class CharArrayDim1 {
|
||||
public @Stable char[] v;
|
||||
|
||||
public static final CharArrayDim1 c = new CharArrayDim1();
|
||||
public static char get() { return c.v[0]; }
|
||||
public static char get1() { return c.v[10]; }
|
||||
public static char[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1]; c.v[0] = 'a'; char val1 = get();
|
||||
c.v[0] = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
c.v = new char[1]; c.v[0] = 'c'; char val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[20]; c.v[10] = 'a'; char val1 = get1();
|
||||
c.v[10] = 'b'; char val2 = get1();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
c.v = new char[20]; c.v[10] = 'c'; char val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1]; char[] val1 = get2();
|
||||
c.v = new char[1]; char[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class CharArrayDim2 {
|
||||
public @Stable char[][] v;
|
||||
|
||||
public static final CharArrayDim2 c = new CharArrayDim2();
|
||||
public static char get() { return c.v[0][0]; }
|
||||
public static char[] get1() { return c.v[0]; }
|
||||
public static char[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1][1]; c.v[0][0] = 'a'; char val1 = get();
|
||||
c.v[0][0] = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
c.v = new char[1][1]; c.v[0][0] = 'c'; char val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
|
||||
c.v[0] = new char[1]; c.v[0][0] = 'd'; char val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 'a' : 'd'));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1]; char[] val1 = get1();
|
||||
c.v[0] = new char[1]; char[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1]; char[][] val1 = get2();
|
||||
c.v = new char[1][1]; char[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class CharArrayDim3 {
|
||||
public @Stable char[][][] v;
|
||||
|
||||
public static final CharArrayDim3 c = new CharArrayDim3();
|
||||
public static char get() { return c.v[0][0][0]; }
|
||||
public static char[] get1() { return c.v[0][0]; }
|
||||
public static char[][] get2() { return c.v[0]; }
|
||||
public static char[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1][1][1]; c.v[0][0][0] = 'a'; char val1 = get();
|
||||
c.v[0][0][0] = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
c.v = new char[1][1][1]; c.v[0][0][0] = 'c'; char val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
|
||||
c.v[0] = new char[1][1]; c.v[0][0][0] = 'd'; char val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 'a' : 'd'));
|
||||
|
||||
c.v[0][0] = new char[1]; c.v[0][0][0] = 'e'; char val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 'a' : 'e'));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1]; char[] val1 = get1();
|
||||
c.v[0][0] = new char[1]; char[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1]; char[][] val1 = get2();
|
||||
c.v[0] = new char[1][1]; char[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1]; char[][][] val1 = get3();
|
||||
c.v = new char[1][1][1]; char[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class CharArrayDim4 {
|
||||
public @Stable char[][][][] v;
|
||||
|
||||
public static final CharArrayDim4 c = new CharArrayDim4();
|
||||
public static char get() { return c.v[0][0][0][0]; }
|
||||
public static char[] get1() { return c.v[0][0][0]; }
|
||||
public static char[][] get2() { return c.v[0][0]; }
|
||||
public static char[][][] get3() { return c.v[0]; }
|
||||
public static char[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'a'; char val1 = get();
|
||||
c.v[0][0][0][0] = 'b'; char val2 = get();
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'c'; char val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
|
||||
c.v[0] = new char[1][1][1]; c.v[0][0][0][0] = 'd'; char val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 'a' : 'd'));
|
||||
|
||||
c.v[0][0] = new char[1][1]; c.v[0][0][0][0] = 'e'; char val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 'a' : 'e'));
|
||||
|
||||
c.v[0][0][0] = new char[1]; c.v[0][0][0][0] = 'f'; char val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 'a' : 'f'));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1][1]; char[] val1 = get1();
|
||||
c.v[0][0][0] = new char[1]; char[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1][1]; char[][] val1 = get2();
|
||||
c.v[0][0] = new char[1][1]; char[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1][1]; char[][][] val1 = get3();
|
||||
c.v[0] = new char[1][1][1]; char[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1][1]; char[][][][] val1 = get4();
|
||||
c.v = new char[1][1][1][1]; char[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static char get() { return ((char[])c.v)[0]; }
|
||||
public static char[] get1() { return (char[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1]; ((char[])c.v)[0] = 'a'; char val1 = get();
|
||||
((char[])c.v)[0] = 'b'; char val2 = get();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, 'b');
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1]; char[] val1 = get1();
|
||||
c.v = new char[1]; char[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static char get() { return ((char[][])c.v)[0][0]; }
|
||||
public static char[] get1() { return (char[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1][1]; ((char[][])c.v)[0][0] = 'a'; char val1 = get();
|
||||
((char[][])c.v)[0][0] = 'b'; char val2 = get();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, 'b');
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1]; c.v[0] = new char[0]; char[] val1 = get1();
|
||||
c.v[0] = new char[0]; char[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[0][0]; Object[] val1 = get2();
|
||||
c.v = new char[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static char get() { return ((char[][][])c.v)[0][0][0]; }
|
||||
public static char[] get1() { return (char[])(c.v[0][0]); }
|
||||
public static char[][] get2() { return (char[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new char[1][1][1]; ((char[][][])c.v)[0][0][0] = 'a'; char val1 = get();
|
||||
((char[][][])c.v)[0][0][0] = 'b'; char val2 = get();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, 'b');
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1]; c.v[0][0] = new char[0]; char[] val1 = get1();
|
||||
c.v[0][0] = new char[0]; char[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[1][1][1]; c.v[0] = new char[0][0]; char[][] val1 = get2();
|
||||
c.v[0] = new char[0][0]; char[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new char[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new char[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable char a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static char get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 'a'; A val1 = get();
|
||||
c.v.a = 'b'; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 'b');
|
||||
assertEquals(val2.a, 'b');
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 'a'; char val1 = get1();
|
||||
c.v.a = 'b'; char val2 = get1();
|
||||
c.v = new A(); c.v.a = 'c'; char val3 = get1();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable char a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static char get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 'a'; c.v.next.a = 'a'; A val1 = get();
|
||||
c.v.a = 'b'; c.v.next.a = 'b'; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 'b');
|
||||
assertEquals(val2.a, 'b');
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 'a'; char val1 = get1();
|
||||
c.v.a = 'b'; char val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 'c'; char val3 = get1();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable char a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static char get() { return c.v.left.left.left.a; }
|
||||
public static char get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 'a'; char val1 = get(); char val2 = get1();
|
||||
c.v.a = 'b'; char val3 = get(); char val4 = get1();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
assertEquals(val2, 'a');
|
||||
assertEquals(val4, 'b');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable char a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static char get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static char get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 'a'; char val1 = get(); char val2 = get1();
|
||||
elem.a = 'b'; char val3 = get(); char val4 = get1();
|
||||
|
||||
assertEquals(val1, 'a');
|
||||
assertEquals(val3, (isStableEnabled ? 'a' : 'b'));
|
||||
|
||||
assertEquals(val2, 'a');
|
||||
assertEquals(val4, 'b');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
632
hotspot/test/compiler/stable/TestStableDouble.java
Normal file
632
hotspot/test/compiler/stable/TestStableDouble.java
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableDouble
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableDouble.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableDouble
|
||||
* java/lang/invoke/TestStableDouble$DoubleStable
|
||||
* java/lang/invoke/TestStableDouble$StaticDoubleStable
|
||||
* java/lang/invoke/TestStableDouble$VolatileDoubleStable
|
||||
* java/lang/invoke/TestStableDouble$DoubleArrayDim1
|
||||
* java/lang/invoke/TestStableDouble$DoubleArrayDim2
|
||||
* java/lang/invoke/TestStableDouble$DoubleArrayDim3
|
||||
* java/lang/invoke/TestStableDouble$DoubleArrayDim4
|
||||
* java/lang/invoke/TestStableDouble$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableDouble$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField$A
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField1
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField2
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField3
|
||||
* java/lang/invoke/TestStableDouble$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableDouble$DefaultValue
|
||||
* java/lang/invoke/TestStableDouble$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableDouble
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableDouble
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableDouble
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableDouble
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableDouble {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(DoubleStable.class);
|
||||
run(StaticDoubleStable.class);
|
||||
run(VolatileDoubleStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(DoubleArrayDim1.class);
|
||||
run(DoubleArrayDim2.class);
|
||||
run(DoubleArrayDim3.class);
|
||||
run(DoubleArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable double v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static double get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
double val1 = get();
|
||||
c.v = 1.0; double val2 = get();
|
||||
assertEquals(val1, 0);
|
||||
assertEquals(val2, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DoubleStable {
|
||||
public @Stable double v;
|
||||
|
||||
public static final DoubleStable c = new DoubleStable();
|
||||
public static double get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1.0; double val1 = get();
|
||||
c.v = Double.MAX_VALUE; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticDoubleStable {
|
||||
public static @Stable double v;
|
||||
|
||||
public static final StaticDoubleStable c = new StaticDoubleStable();
|
||||
public static double get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1.0; double val1 = get();
|
||||
c.v = Double.MAX_VALUE; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileDoubleStable {
|
||||
public @Stable double v;
|
||||
|
||||
public static final VolatileDoubleStable c = new VolatileDoubleStable();
|
||||
public static double get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1.0; double val1 = get();
|
||||
c.v = Double.MAX_VALUE; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : Double.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class DoubleArrayDim1 {
|
||||
public @Stable double[] v;
|
||||
|
||||
public static final DoubleArrayDim1 c = new DoubleArrayDim1();
|
||||
public static double get() { return c.v[0]; }
|
||||
public static double get1() { return c.v[10]; }
|
||||
public static double[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1]; c.v[0] = 1.0; double val1 = get();
|
||||
c.v[0] = 2.0; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
c.v = new double[1]; c.v[0] = 3.0; double val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[20]; c.v[10] = 1.0; double val1 = get1();
|
||||
c.v[10] = 2.0; double val2 = get1();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
c.v = new double[20]; c.v[10] = 3.0; double val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1]; double[] val1 = get2();
|
||||
c.v = new double[1]; double[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DoubleArrayDim2 {
|
||||
public @Stable double[][] v;
|
||||
|
||||
public static final DoubleArrayDim2 c = new DoubleArrayDim2();
|
||||
public static double get() { return c.v[0][0]; }
|
||||
public static double[] get1() { return c.v[0]; }
|
||||
public static double[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1][1]; c.v[0][0] = 1.0; double val1 = get();
|
||||
c.v[0][0] = 2.0; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
c.v = new double[1][1]; c.v[0][0] = 3.0; double val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
|
||||
c.v[0] = new double[1]; c.v[0][0] = 4.0; double val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1.0 : 4.0));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1]; double[] val1 = get1();
|
||||
c.v[0] = new double[1]; double[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1]; double[][] val1 = get2();
|
||||
c.v = new double[1][1]; double[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DoubleArrayDim3 {
|
||||
public @Stable double[][][] v;
|
||||
|
||||
public static final DoubleArrayDim3 c = new DoubleArrayDim3();
|
||||
public static double get() { return c.v[0][0][0]; }
|
||||
public static double[] get1() { return c.v[0][0]; }
|
||||
public static double[][] get2() { return c.v[0]; }
|
||||
public static double[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1][1][1]; c.v[0][0][0] = 1.0; double val1 = get();
|
||||
c.v[0][0][0] = 2.0; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
c.v = new double[1][1][1]; c.v[0][0][0] = 3.0; double val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
|
||||
c.v[0] = new double[1][1]; c.v[0][0][0] = 4.0; double val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1.0 : 4.0));
|
||||
|
||||
c.v[0][0] = new double[1]; c.v[0][0][0] = 5.0; double val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1.0 : 5.0));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1]; double[] val1 = get1();
|
||||
c.v[0][0] = new double[1]; double[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1]; double[][] val1 = get2();
|
||||
c.v[0] = new double[1][1]; double[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1]; double[][][] val1 = get3();
|
||||
c.v = new double[1][1][1]; double[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DoubleArrayDim4 {
|
||||
public @Stable double[][][][] v;
|
||||
|
||||
public static final DoubleArrayDim4 c = new DoubleArrayDim4();
|
||||
public static double get() { return c.v[0][0][0][0]; }
|
||||
public static double[] get1() { return c.v[0][0][0]; }
|
||||
public static double[][] get2() { return c.v[0][0]; }
|
||||
public static double[][][] get3() { return c.v[0]; }
|
||||
public static double[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 1.0; double val1 = get();
|
||||
c.v[0][0][0][0] = 2.0; double val2 = get();
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 3.0; double val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
|
||||
c.v[0] = new double[1][1][1]; c.v[0][0][0][0] = 4.0; double val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1.0 : 4.0));
|
||||
|
||||
c.v[0][0] = new double[1][1]; c.v[0][0][0][0] = 5.0; double val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1.0 : 5.0));
|
||||
|
||||
c.v[0][0][0] = new double[1]; c.v[0][0][0][0] = 6.0; double val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 1.0 : 6.0));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1][1]; double[] val1 = get1();
|
||||
c.v[0][0][0] = new double[1]; double[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1][1]; double[][] val1 = get2();
|
||||
c.v[0][0] = new double[1][1]; double[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1][1]; double[][][] val1 = get3();
|
||||
c.v[0] = new double[1][1][1]; double[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1][1]; double[][][][] val1 = get4();
|
||||
c.v = new double[1][1][1][1]; double[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static double get() { return ((double[])c.v)[0]; }
|
||||
public static double[] get1() { return (double[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1]; ((double[])c.v)[0] = 1.0; double val1 = get();
|
||||
((double[])c.v)[0] = 2.0; double val2 = get();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, 2.0);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1]; double[] val1 = get1();
|
||||
c.v = new double[1]; double[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static double get() { return ((double[][])c.v)[0][0]; }
|
||||
public static double[] get1() { return (double[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1][1]; ((double[][])c.v)[0][0] = 1.0; double val1 = get();
|
||||
((double[][])c.v)[0][0] = 2.0; double val2 = get();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, 2.0);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1]; c.v[0] = new double[0]; double[] val1 = get1();
|
||||
c.v[0] = new double[0]; double[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[0][0]; Object[] val1 = get2();
|
||||
c.v = new double[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static double get() { return ((double[][][])c.v)[0][0][0]; }
|
||||
public static double[] get1() { return (double[])(c.v[0][0]); }
|
||||
public static double[][] get2() { return (double[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new double[1][1][1]; ((double[][][])c.v)[0][0][0] = 1.0; double val1 = get();
|
||||
((double[][][])c.v)[0][0][0] = 2.0; double val2 = get();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, 2.0);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1]; c.v[0][0] = new double[0]; double[] val1 = get1();
|
||||
c.v[0][0] = new double[0]; double[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[1][1][1]; c.v[0] = new double[0][0]; double[][] val1 = get2();
|
||||
c.v[0] = new double[0][0]; double[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new double[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new double[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable double a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static double get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 1.0; A val1 = get();
|
||||
c.v.a = 2.0; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2.0);
|
||||
assertEquals(val2.a, 2.0);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 1.0; double val1 = get1();
|
||||
c.v.a = 2.0; double val2 = get1();
|
||||
c.v = new A(); c.v.a = 3.0; double val3 = get1();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable double a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static double get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 1.0; c.v.next.a = 1.0; A val1 = get();
|
||||
c.v.a = 2.0; c.v.next.a = 2.0; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2.0);
|
||||
assertEquals(val2.a, 2.0);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 1.0; double val1 = get1();
|
||||
c.v.a = 2.0; double val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 3.0; double val3 = get1();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0 : 2.0));
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 3.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable double a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static double get() { return c.v.left.left.left.a; }
|
||||
public static double get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 1.0; double val1 = get(); double val2 = get1();
|
||||
c.v.a = 2.0; double val3 = get(); double val4 = get1();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
assertEquals(val2, 1.0);
|
||||
assertEquals(val4, 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable double a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static double get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static double get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 1.0; double val1 = get(); double val2 = get1();
|
||||
elem.a = 2.0; double val3 = get(); double val4 = get1();
|
||||
|
||||
assertEquals(val1, 1.0);
|
||||
assertEquals(val3, (isStableEnabled ? 1.0 : 2.0));
|
||||
|
||||
assertEquals(val2, 1.0);
|
||||
assertEquals(val4, 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(double i, double j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
632
hotspot/test/compiler/stable/TestStableFloat.java
Normal file
632
hotspot/test/compiler/stable/TestStableFloat.java
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableFloat
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableFloat.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableFloat
|
||||
* java/lang/invoke/TestStableFloat$FloatStable
|
||||
* java/lang/invoke/TestStableFloat$StaticFloatStable
|
||||
* java/lang/invoke/TestStableFloat$VolatileFloatStable
|
||||
* java/lang/invoke/TestStableFloat$FloatArrayDim1
|
||||
* java/lang/invoke/TestStableFloat$FloatArrayDim2
|
||||
* java/lang/invoke/TestStableFloat$FloatArrayDim3
|
||||
* java/lang/invoke/TestStableFloat$FloatArrayDim4
|
||||
* java/lang/invoke/TestStableFloat$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableFloat$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField$A
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField1
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField2
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField3
|
||||
* java/lang/invoke/TestStableFloat$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableFloat$DefaultValue
|
||||
* java/lang/invoke/TestStableFloat$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableFloat
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableFloat
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableFloat
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableFloat
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableFloat {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(FloatStable.class);
|
||||
run(StaticFloatStable.class);
|
||||
run(VolatileFloatStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(FloatArrayDim1.class);
|
||||
run(FloatArrayDim2.class);
|
||||
run(FloatArrayDim3.class);
|
||||
run(FloatArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable float v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static float get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
float val1 = get();
|
||||
c.v = 1.0F; float val2 = get();
|
||||
assertEquals(val1, 0F);
|
||||
assertEquals(val2, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class FloatStable {
|
||||
public @Stable float v;
|
||||
|
||||
public static final FloatStable c = new FloatStable();
|
||||
public static float get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1.0F; float val1 = get();
|
||||
c.v = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticFloatStable {
|
||||
public static @Stable float v;
|
||||
|
||||
public static final StaticFloatStable c = new StaticFloatStable();
|
||||
public static float get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1.0F; float val1 = get();
|
||||
c.v = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileFloatStable {
|
||||
public @Stable volatile float v;
|
||||
|
||||
public static final VolatileFloatStable c = new VolatileFloatStable();
|
||||
public static float get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1.0F; float val1 = get();
|
||||
c.v = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class FloatArrayDim1 {
|
||||
public @Stable float[] v;
|
||||
|
||||
public static final FloatArrayDim1 c = new FloatArrayDim1();
|
||||
public static float get() { return c.v[0]; }
|
||||
public static float get1() { return c.v[10]; }
|
||||
public static float[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1]; c.v[0] = 1.0F; float val1 = get();
|
||||
c.v[0] = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
c.v = new float[1]; c.v[0] = 3.0F; float val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[20]; c.v[10] = 1.0F; float val1 = get1();
|
||||
c.v[10] = 2.0F; float val2 = get1();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
c.v = new float[20]; c.v[10] = 3.0F; float val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1]; float[] val1 = get2();
|
||||
c.v = new float[1]; float[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class FloatArrayDim2 {
|
||||
public @Stable float[][] v;
|
||||
|
||||
public static final FloatArrayDim2 c = new FloatArrayDim2();
|
||||
public static float get() { return c.v[0][0]; }
|
||||
public static float[] get1() { return c.v[0]; }
|
||||
public static float[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1][1]; c.v[0][0] = 1.0F; float val1 = get();
|
||||
c.v[0][0] = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
c.v = new float[1][1]; c.v[0][0] = 3.0F; float val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
|
||||
c.v[0] = new float[1]; c.v[0][0] = 4.0F; float val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1]; float[] val1 = get1();
|
||||
c.v[0] = new float[1]; float[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1]; float[][] val1 = get2();
|
||||
c.v = new float[1][1]; float[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class FloatArrayDim3 {
|
||||
public @Stable float[][][] v;
|
||||
|
||||
public static final FloatArrayDim3 c = new FloatArrayDim3();
|
||||
public static float get() { return c.v[0][0][0]; }
|
||||
public static float[] get1() { return c.v[0][0]; }
|
||||
public static float[][] get2() { return c.v[0]; }
|
||||
public static float[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1][1][1]; c.v[0][0][0] = 1.0F; float val1 = get();
|
||||
c.v[0][0][0] = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
c.v = new float[1][1][1]; c.v[0][0][0] = 3.0F; float val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
|
||||
c.v[0] = new float[1][1]; c.v[0][0][0] = 4.0F; float val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F));
|
||||
|
||||
c.v[0][0] = new float[1]; c.v[0][0][0] = 5.0F; float val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1.0F : 5.0F));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1]; float[] val1 = get1();
|
||||
c.v[0][0] = new float[1]; float[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1]; float[][] val1 = get2();
|
||||
c.v[0] = new float[1][1]; float[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1]; float[][][] val1 = get3();
|
||||
c.v = new float[1][1][1]; float[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class FloatArrayDim4 {
|
||||
public @Stable float[][][][] v;
|
||||
|
||||
public static final FloatArrayDim4 c = new FloatArrayDim4();
|
||||
public static float get() { return c.v[0][0][0][0]; }
|
||||
public static float[] get1() { return c.v[0][0][0]; }
|
||||
public static float[][] get2() { return c.v[0][0]; }
|
||||
public static float[][][] get3() { return c.v[0]; }
|
||||
public static float[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 1.0F; float val1 = get();
|
||||
c.v[0][0][0][0] = 2.0F; float val2 = get();
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 3.0F; float val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
|
||||
c.v[0] = new float[1][1][1]; c.v[0][0][0][0] = 4.0F; float val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1.0F : 4.0F));
|
||||
|
||||
c.v[0][0] = new float[1][1]; c.v[0][0][0][0] = 5.0F; float val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1.0F : 5.0F));
|
||||
|
||||
c.v[0][0][0] = new float[1]; c.v[0][0][0][0] = 6.0F; float val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 1.0F : 6.0F));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1][1]; float[] val1 = get1();
|
||||
c.v[0][0][0] = new float[1]; float[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1][1]; float[][] val1 = get2();
|
||||
c.v[0][0] = new float[1][1]; float[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1][1]; float[][][] val1 = get3();
|
||||
c.v[0] = new float[1][1][1]; float[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1][1]; float[][][][] val1 = get4();
|
||||
c.v = new float[1][1][1][1]; float[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static float get() { return ((float[])c.v)[0]; }
|
||||
public static float[] get1() { return (float[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1]; ((float[])c.v)[0] = 1.0F; float val1 = get();
|
||||
((float[])c.v)[0] = 2.0F; float val2 = get();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, 2.0F);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1]; float[] val1 = get1();
|
||||
c.v = new float[1]; float[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static float get() { return ((float[][])c.v)[0][0]; }
|
||||
public static float[] get1() { return (float[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1][1]; ((float[][])c.v)[0][0] = 1.0F; float val1 = get();
|
||||
((float[][])c.v)[0][0] = 2.0F; float val2 = get();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, 2.0F);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1]; c.v[0] = new float[0]; float[] val1 = get1();
|
||||
c.v[0] = new float[0]; float[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[0][0]; Object[] val1 = get2();
|
||||
c.v = new float[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static float get() { return ((float[][][])c.v)[0][0][0]; }
|
||||
public static float[] get1() { return (float[])(c.v[0][0]); }
|
||||
public static float[][] get2() { return (float[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new float[1][1][1]; ((float[][][])c.v)[0][0][0] = 1.0F; float val1 = get();
|
||||
((float[][][])c.v)[0][0][0] = 2.0F; float val2 = get();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, 2.0F);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1]; c.v[0][0] = new float[0]; float[] val1 = get1();
|
||||
c.v[0][0] = new float[0]; float[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[1][1][1]; c.v[0] = new float[0][0]; float[][] val1 = get2();
|
||||
c.v[0] = new float[0][0]; float[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new float[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new float[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable float a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static float get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 1.0F; A val1 = get();
|
||||
c.v.a = 2.0F; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2.0F);
|
||||
assertEquals(val2.a, 2.0F);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 1.0F; float val1 = get1();
|
||||
c.v.a = 2.0F; float val2 = get1();
|
||||
c.v = new A(); c.v.a = 3.0F; float val3 = get1();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable float a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static float get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 1.0F; c.v.next.a = 1.0F; A val1 = get();
|
||||
c.v.a = 2.0F; c.v.next.a = 2.0F; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2.0F);
|
||||
assertEquals(val2.a, 2.0F);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 1.0F; float val1 = get1();
|
||||
c.v.a = 2.0F; float val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 3.0F; float val3 = get1();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F));
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 3.0F));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable float a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static float get() { return c.v.left.left.left.a; }
|
||||
public static float get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 1.0F; float val1 = get(); float val2 = get1();
|
||||
c.v.a = 2.0F; float val3 = get(); float val4 = get1();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
assertEquals(val2, 1.0F);
|
||||
assertEquals(val4, 2.0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable float a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static float get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static float get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 1.0F; float val1 = get(); float val2 = get1();
|
||||
elem.a = 2.0F; float val3 = get(); float val4 = get1();
|
||||
|
||||
assertEquals(val1, 1.0F);
|
||||
assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F));
|
||||
|
||||
assertEquals(val2, 1.0F);
|
||||
assertEquals(val4, 2.0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(float i, float j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
632
hotspot/test/compiler/stable/TestStableInt.java
Normal file
632
hotspot/test/compiler/stable/TestStableInt.java
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableInt
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableInt.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableInt
|
||||
* java/lang/invoke/TestStableInt$IntStable
|
||||
* java/lang/invoke/TestStableInt$StaticIntStable
|
||||
* java/lang/invoke/TestStableInt$VolatileIntStable
|
||||
* java/lang/invoke/TestStableInt$IntArrayDim1
|
||||
* java/lang/invoke/TestStableInt$IntArrayDim2
|
||||
* java/lang/invoke/TestStableInt$IntArrayDim3
|
||||
* java/lang/invoke/TestStableInt$IntArrayDim4
|
||||
* java/lang/invoke/TestStableInt$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableInt$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableInt$NestedStableField
|
||||
* java/lang/invoke/TestStableInt$NestedStableField$A
|
||||
* java/lang/invoke/TestStableInt$NestedStableField1
|
||||
* java/lang/invoke/TestStableInt$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableInt$NestedStableField2
|
||||
* java/lang/invoke/TestStableInt$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableInt$NestedStableField3
|
||||
* java/lang/invoke/TestStableInt$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableInt$DefaultValue
|
||||
* java/lang/invoke/TestStableInt$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableInt
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableInt
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableInt
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableInt
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableInt {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(IntStable.class);
|
||||
run(StaticIntStable.class);
|
||||
run(VolatileIntStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(IntArrayDim1.class);
|
||||
run(IntArrayDim2.class);
|
||||
run(IntArrayDim3.class);
|
||||
run(IntArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable int v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static int get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
int val1 = get();
|
||||
c.v = 1; int val2 = get();
|
||||
assertEquals(val1, 0);
|
||||
assertEquals(val2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class IntStable {
|
||||
public @Stable int v;
|
||||
|
||||
public static final IntStable c = new IntStable();
|
||||
public static int get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1; int val1 = get();
|
||||
c.v = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticIntStable {
|
||||
public static @Stable int v;
|
||||
|
||||
public static final StaticIntStable c = new StaticIntStable();
|
||||
public static int get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1; int val1 = get();
|
||||
c.v = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileIntStable {
|
||||
public @Stable volatile int v;
|
||||
|
||||
public static final VolatileIntStable c = new VolatileIntStable();
|
||||
public static int get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1; int val1 = get();
|
||||
c.v = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class IntArrayDim1 {
|
||||
public @Stable int[] v;
|
||||
|
||||
public static final IntArrayDim1 c = new IntArrayDim1();
|
||||
public static int get() { return c.v[0]; }
|
||||
public static int get1() { return c.v[10]; }
|
||||
public static int[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1]; c.v[0] = 1; int val1 = get();
|
||||
c.v[0] = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new int[1]; c.v[0] = 3; int val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[20]; c.v[10] = 1; int val1 = get1();
|
||||
c.v[10] = 2; int val2 = get1();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new int[20]; c.v[10] = 3; int val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1]; int[] val1 = get2();
|
||||
c.v = new int[1]; int[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class IntArrayDim2 {
|
||||
public @Stable int[][] v;
|
||||
|
||||
public static final IntArrayDim2 c = new IntArrayDim2();
|
||||
public static int get() { return c.v[0][0]; }
|
||||
public static int[] get1() { return c.v[0]; }
|
||||
public static int[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1][1]; c.v[0][0] = 1; int val1 = get();
|
||||
c.v[0][0] = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new int[1][1]; c.v[0][0] = 3; int val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new int[1]; c.v[0][0] = 4; int val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1]; int[] val1 = get1();
|
||||
c.v[0] = new int[1]; int[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1]; int[][] val1 = get2();
|
||||
c.v = new int[1][1]; int[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class IntArrayDim3 {
|
||||
public @Stable int[][][] v;
|
||||
|
||||
public static final IntArrayDim3 c = new IntArrayDim3();
|
||||
public static int get() { return c.v[0][0][0]; }
|
||||
public static int[] get1() { return c.v[0][0]; }
|
||||
public static int[][] get2() { return c.v[0]; }
|
||||
public static int[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1][1][1]; c.v[0][0][0] = 1; int val1 = get();
|
||||
c.v[0][0][0] = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new int[1][1][1]; c.v[0][0][0] = 3; int val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new int[1][1]; c.v[0][0][0] = 4; int val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new int[1]; c.v[0][0][0] = 5; int val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1]; int[] val1 = get1();
|
||||
c.v[0][0] = new int[1]; int[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1]; int[][] val1 = get2();
|
||||
c.v[0] = new int[1][1]; int[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1]; int[][][] val1 = get3();
|
||||
c.v = new int[1][1][1]; int[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class IntArrayDim4 {
|
||||
public @Stable int[][][][] v;
|
||||
|
||||
public static final IntArrayDim4 c = new IntArrayDim4();
|
||||
public static int get() { return c.v[0][0][0][0]; }
|
||||
public static int[] get1() { return c.v[0][0][0]; }
|
||||
public static int[][] get2() { return c.v[0][0]; }
|
||||
public static int[][][] get3() { return c.v[0]; }
|
||||
public static int[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 1; int val1 = get();
|
||||
c.v[0][0][0][0] = 2; int val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 3; int val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new int[1][1][1]; c.v[0][0][0][0] = 4; int val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new int[1][1]; c.v[0][0][0][0] = 5; int val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
|
||||
c.v[0][0][0] = new int[1]; c.v[0][0][0][0] = 6; int val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 1 : 6));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1][1]; int[] val1 = get1();
|
||||
c.v[0][0][0] = new int[1]; int[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1][1]; int[][] val1 = get2();
|
||||
c.v[0][0] = new int[1][1]; int[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1][1]; int[][][] val1 = get3();
|
||||
c.v[0] = new int[1][1][1]; int[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1][1]; int[][][][] val1 = get4();
|
||||
c.v = new int[1][1][1][1]; int[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static int get() { return ((int[])c.v)[0]; }
|
||||
public static int[] get1() { return (int[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1]; ((int[])c.v)[0] = 1; int val1 = get();
|
||||
((int[])c.v)[0] = 2; int val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1]; int[] val1 = get1();
|
||||
c.v = new int[1]; int[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static int get() { return ((int[][])c.v)[0][0]; }
|
||||
public static int[] get1() { return (int[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1][1]; ((int[][])c.v)[0][0] = 1; int val1 = get();
|
||||
((int[][])c.v)[0][0] = 2; int val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1]; c.v[0] = new int[0]; int[] val1 = get1();
|
||||
c.v[0] = new int[0]; int[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[0][0]; Object[] val1 = get2();
|
||||
c.v = new int[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static int get() { return ((int[][][])c.v)[0][0][0]; }
|
||||
public static int[] get1() { return (int[])(c.v[0][0]); }
|
||||
public static int[][] get2() { return (int[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new int[1][1][1]; ((int[][][])c.v)[0][0][0] = 1; int val1 = get();
|
||||
((int[][][])c.v)[0][0][0] = 2; int val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1]; c.v[0][0] = new int[0]; int[] val1 = get1();
|
||||
c.v[0][0] = new int[0]; int[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[1][1][1]; c.v[0] = new int[0][0]; int[][] val1 = get2();
|
||||
c.v[0] = new int[0][0]; int[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new int[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new int[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable int a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static int get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; A val1 = get();
|
||||
c.v.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; int val1 = get1();
|
||||
c.v.a = 2; int val2 = get1();
|
||||
c.v = new A(); c.v.a = 3; int val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable int a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static int get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 1; c.v.next.a = 1; A val1 = get();
|
||||
c.v.a = 2; c.v.next.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 1; int val1 = get1();
|
||||
c.v.a = 2; int val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 3; int val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable int a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static int get() { return c.v.left.left.left.a; }
|
||||
public static int get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 1; int val1 = get(); int val2 = get1();
|
||||
c.v.a = 2; int val3 = get(); int val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable int a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static int get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static int get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 1; int val1 = get(); int val2 = get1();
|
||||
elem.a = 2; int val3 = get(); int val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
632
hotspot/test/compiler/stable/TestStableLong.java
Normal file
632
hotspot/test/compiler/stable/TestStableLong.java
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableLong
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableLong.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableLong
|
||||
* java/lang/invoke/TestStableLong$LongStable
|
||||
* java/lang/invoke/TestStableLong$StaticLongStable
|
||||
* java/lang/invoke/TestStableLong$VolatileLongStable
|
||||
* java/lang/invoke/TestStableLong$LongArrayDim1
|
||||
* java/lang/invoke/TestStableLong$LongArrayDim2
|
||||
* java/lang/invoke/TestStableLong$LongArrayDim3
|
||||
* java/lang/invoke/TestStableLong$LongArrayDim4
|
||||
* java/lang/invoke/TestStableLong$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableLong$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableLong$NestedStableField
|
||||
* java/lang/invoke/TestStableLong$NestedStableField$A
|
||||
* java/lang/invoke/TestStableLong$NestedStableField1
|
||||
* java/lang/invoke/TestStableLong$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableLong$NestedStableField2
|
||||
* java/lang/invoke/TestStableLong$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableLong$NestedStableField3
|
||||
* java/lang/invoke/TestStableLong$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableLong$DefaultValue
|
||||
* java/lang/invoke/TestStableLong$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableLong
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableLong
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableLong
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableLong
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableLong {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(LongStable.class);
|
||||
run(StaticLongStable.class);
|
||||
run(VolatileLongStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(LongArrayDim1.class);
|
||||
run(LongArrayDim2.class);
|
||||
run(LongArrayDim3.class);
|
||||
run(LongArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable long v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static long get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
long val1 = get();
|
||||
c.v = 1L; long val2 = get();
|
||||
assertEquals(val1, 0);
|
||||
assertEquals(val2, 1L);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class LongStable {
|
||||
public @Stable long v;
|
||||
|
||||
public static final LongStable c = new LongStable();
|
||||
public static long get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 5; long val1 = get();
|
||||
c.v = Long.MAX_VALUE; long val2 = get();
|
||||
assertEquals(val1, 5);
|
||||
assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticLongStable {
|
||||
public static @Stable long v;
|
||||
|
||||
public static final StaticLongStable c = new StaticLongStable();
|
||||
public static long get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 5; long val1 = get();
|
||||
c.v = Long.MAX_VALUE; long val2 = get();
|
||||
assertEquals(val1, 5);
|
||||
assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileLongStable {
|
||||
public @Stable volatile long v;
|
||||
|
||||
public static final VolatileLongStable c = new VolatileLongStable();
|
||||
public static long get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 5; long val1 = get();
|
||||
c.v = Long.MAX_VALUE; long val2 = get();
|
||||
assertEquals(val1, 5);
|
||||
assertEquals(val2, (isStableEnabled ? 5 : Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class LongArrayDim1 {
|
||||
public @Stable long[] v;
|
||||
|
||||
public static final LongArrayDim1 c = new LongArrayDim1();
|
||||
public static long get() { return c.v[0]; }
|
||||
public static long get1() { return c.v[10]; }
|
||||
public static long[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1]; c.v[0] = 1; long val1 = get();
|
||||
c.v[0] = 2; long val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new long[1]; c.v[0] = 3; long val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[20]; c.v[10] = 1; long val1 = get1();
|
||||
c.v[10] = 2; long val2 = get1();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new long[20]; c.v[10] = 3; long val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1]; long[] val1 = get2();
|
||||
c.v = new long[1]; long[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class LongArrayDim2 {
|
||||
public @Stable long[][] v;
|
||||
|
||||
public static final LongArrayDim2 c = new LongArrayDim2();
|
||||
public static long get() { return c.v[0][0]; }
|
||||
public static long[] get1() { return c.v[0]; }
|
||||
public static long[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1][1]; c.v[0][0] = 1; long val1 = get();
|
||||
c.v[0][0] = 2; long val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new long[1][1]; c.v[0][0] = 3; long val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new long[1]; c.v[0][0] = 4; long val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1]; long[] val1 = get1();
|
||||
c.v[0] = new long[1]; long[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1]; long[][] val1 = get2();
|
||||
c.v = new long[1][1]; long[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class LongArrayDim3 {
|
||||
public @Stable long[][][] v;
|
||||
|
||||
public static final LongArrayDim3 c = new LongArrayDim3();
|
||||
public static long get() { return c.v[0][0][0]; }
|
||||
public static long[] get1() { return c.v[0][0]; }
|
||||
public static long[][] get2() { return c.v[0]; }
|
||||
public static long[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1][1][1]; c.v[0][0][0] = 1; long val1 = get();
|
||||
c.v[0][0][0] = 2; long val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new long[1][1][1]; c.v[0][0][0] = 3; long val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new long[1][1]; c.v[0][0][0] = 4; long val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new long[1]; c.v[0][0][0] = 5; long val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1]; long[] val1 = get1();
|
||||
c.v[0][0] = new long[1]; long[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1]; long[][] val1 = get2();
|
||||
c.v[0] = new long[1][1]; long[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1]; long[][][] val1 = get3();
|
||||
c.v = new long[1][1][1]; long[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class LongArrayDim4 {
|
||||
public @Stable long[][][][] v;
|
||||
|
||||
public static final LongArrayDim4 c = new LongArrayDim4();
|
||||
public static long get() { return c.v[0][0][0][0]; }
|
||||
public static long[] get1() { return c.v[0][0][0]; }
|
||||
public static long[][] get2() { return c.v[0][0]; }
|
||||
public static long[][][] get3() { return c.v[0]; }
|
||||
public static long[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 1; long val1 = get();
|
||||
c.v[0][0][0][0] = 2; long val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 3; long val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new long[1][1][1]; c.v[0][0][0][0] = 4; long val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new long[1][1]; c.v[0][0][0][0] = 5; long val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
|
||||
c.v[0][0][0] = new long[1]; c.v[0][0][0][0] = 6; long val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 1 : 6));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1][1]; long[] val1 = get1();
|
||||
c.v[0][0][0] = new long[1]; long[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1][1]; long[][] val1 = get2();
|
||||
c.v[0][0] = new long[1][1]; long[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1][1]; long[][][] val1 = get3();
|
||||
c.v[0] = new long[1][1][1]; long[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1][1]; long[][][][] val1 = get4();
|
||||
c.v = new long[1][1][1][1]; long[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static long get() { return ((long[])c.v)[0]; }
|
||||
public static long[] get1() { return (long[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1]; ((long[])c.v)[0] = 1; long val1 = get();
|
||||
((long[])c.v)[0] = 2; long val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1]; long[] val1 = get1();
|
||||
c.v = new long[1]; long[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static long get() { return ((long[][])c.v)[0][0]; }
|
||||
public static long[] get1() { return (long[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1][1]; ((long[][])c.v)[0][0] = 1; long val1 = get();
|
||||
((long[][])c.v)[0][0] = 2; long val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1]; c.v[0] = new long[0]; long[] val1 = get1();
|
||||
c.v[0] = new long[0]; long[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[0][0]; Object[] val1 = get2();
|
||||
c.v = new long[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static long get() { return ((long[][][])c.v)[0][0][0]; }
|
||||
public static long[] get1() { return (long[])(c.v[0][0]); }
|
||||
public static long[][] get2() { return (long[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new long[1][1][1]; ((long[][][])c.v)[0][0][0] = 1L; long val1 = get();
|
||||
((long[][][])c.v)[0][0][0] = 2L; long val2 = get();
|
||||
|
||||
assertEquals(val1, 1L);
|
||||
assertEquals(val2, 2L);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1]; c.v[0][0] = new long[0]; long[] val1 = get1();
|
||||
c.v[0][0] = new long[0]; long[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[1][1][1]; c.v[0] = new long[0][0]; long[][] val1 = get2();
|
||||
c.v[0] = new long[0][0]; long[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new long[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new long[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable long a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static long get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; A val1 = get();
|
||||
c.v.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; long val1 = get1();
|
||||
c.v.a = 2; long val2 = get1();
|
||||
c.v = new A(); c.v.a = 3; long val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable long a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static long get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 1; c.v.next.a = 1; A val1 = get();
|
||||
c.v.a = 2; c.v.next.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 1; long val1 = get1();
|
||||
c.v.a = 2; long val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 3; long val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable long a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static long get() { return c.v.left.left.left.a; }
|
||||
public static long get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 1; long val1 = get(); long val2 = get1();
|
||||
c.v.a = 2; long val3 = get(); long val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable long a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static long get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static long get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 1; long val1 = get(); long val2 = get1();
|
||||
elem.a = 2; long val3 = get(); long val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(long i, long j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
635
hotspot/test/compiler/stable/TestStableObject.java
Normal file
635
hotspot/test/compiler/stable/TestStableObject.java
Normal file
@ -0,0 +1,635 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableObject
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableObject.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableObject
|
||||
* java/lang/invoke/TestStableObject$ObjectStable
|
||||
* java/lang/invoke/TestStableObject$StaticObjectStable
|
||||
* java/lang/invoke/TestStableObject$VolatileObjectStable
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayDim1
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayDim2
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayDim3
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayDim4
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableObject$NestedStableField
|
||||
* java/lang/invoke/TestStableObject$NestedStableField$A
|
||||
* java/lang/invoke/TestStableObject$NestedStableField1
|
||||
* java/lang/invoke/TestStableObject$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableObject$NestedStableField2
|
||||
* java/lang/invoke/TestStableObject$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableObject$NestedStableField3
|
||||
* java/lang/invoke/TestStableObject$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableObject$Values
|
||||
* java/lang/invoke/TestStableObject$DefaultValue
|
||||
* java/lang/invoke/TestStableObject$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableObject
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableObject
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableObject
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableObject
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableObject {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(ObjectStable.class);
|
||||
run(StaticObjectStable.class);
|
||||
run(VolatileObjectStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(ObjectArrayDim1.class);
|
||||
run(ObjectArrayDim2.class);
|
||||
run(ObjectArrayDim3.class);
|
||||
run(ObjectArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
enum Values {A, B, C, D, E, F}
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static Object get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
Object val1 = get();
|
||||
c.v = Values.A; Object val2 = get();
|
||||
assertEquals(val1, null);
|
||||
assertEquals(val2, Values.A);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectStable {
|
||||
public @Stable Values v;
|
||||
|
||||
public static final ObjectStable c = new ObjectStable ();
|
||||
public static Values get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = Values.A; Values val1 = get();
|
||||
c.v = Values.B; Values val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticObjectStable {
|
||||
public static @Stable Values v;
|
||||
|
||||
public static final ObjectStable c = new ObjectStable ();
|
||||
public static Values get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = Values.A; Values val1 = get();
|
||||
c.v = Values.B; Values val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileObjectStable {
|
||||
public @Stable volatile Values v;
|
||||
|
||||
public static final VolatileObjectStable c = new VolatileObjectStable ();
|
||||
public static Values get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = Values.A; Values val1 = get();
|
||||
c.v = Values.B; Values val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class ObjectArrayDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayDim1 c = new ObjectArrayDim1();
|
||||
public static Object get() { return c.v[0]; }
|
||||
public static Object get1() { return c.v[10]; }
|
||||
public static Object[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1]; c.v[0] = Values.A; Object val1 = get();
|
||||
c.v[0] = Values.B; Object val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
c.v = new Object[1]; c.v[0] = Values.C; Object val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[20]; c.v[10] = Values.A; Object val1 = get1();
|
||||
c.v[10] = Values.B; Object val2 = get1();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
c.v = new Object[20]; c.v[10] = Values.C; Object val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1]; Object[] val1 = get2();
|
||||
c.v = new Object[1]; Object[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayDim2 c = new ObjectArrayDim2();
|
||||
public static Object get() { return c.v[0][0]; }
|
||||
public static Object[] get1() { return c.v[0]; }
|
||||
public static Object[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1][1]; c.v[0][0] = Values.A; Object val1 = get();
|
||||
c.v[0][0] = Values.B; Object val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
c.v = new Object[1][1]; c.v[0][0] = Values.C; Object val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
|
||||
c.v[0] = new Object[1]; c.v[0][0] = Values.D; Object val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? Values.A : Values.D));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1]; Object[] val1 = get1();
|
||||
c.v[0] = new Object[1]; Object[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1]; Object[][] val1 = get2();
|
||||
c.v = new Object[1][1]; Object[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayDim3 {
|
||||
public @Stable Object[][][] v;
|
||||
|
||||
public static final ObjectArrayDim3 c = new ObjectArrayDim3();
|
||||
public static Object get() { return c.v[0][0][0]; }
|
||||
public static Object[] get1() { return c.v[0][0]; }
|
||||
public static Object[][] get2() { return c.v[0]; }
|
||||
public static Object[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1][1][1]; c.v[0][0][0] = Values.A; Object val1 = get();
|
||||
c.v[0][0][0] = Values.B; Object val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
c.v = new Object[1][1][1]; c.v[0][0][0] = Values.C; Object val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
|
||||
c.v[0] = new Object[1][1]; c.v[0][0][0] = Values.D; Object val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? Values.A : Values.D));
|
||||
|
||||
c.v[0][0] = new Object[1]; c.v[0][0][0] = Values.E; Object val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? Values.A : Values.E));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1]; Object[] val1 = get1();
|
||||
c.v[0][0] = new Object[1]; Object[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1]; Object[][] val1 = get2();
|
||||
c.v[0] = new Object[1][1]; Object[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1]; Object[][][] val1 = get3();
|
||||
c.v = new Object[1][1][1]; Object[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayDim4 {
|
||||
public @Stable Object[][][][] v;
|
||||
|
||||
public static final ObjectArrayDim4 c = new ObjectArrayDim4();
|
||||
public static Object get() { return c.v[0][0][0][0]; }
|
||||
public static Object[] get1() { return c.v[0][0][0]; }
|
||||
public static Object[][] get2() { return c.v[0][0]; }
|
||||
public static Object[][][] get3() { return c.v[0]; }
|
||||
public static Object[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.A; Object val1 = get();
|
||||
c.v[0][0][0][0] = Values.B; Object val2 = get();
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.C; Object val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
|
||||
c.v[0] = new Object[1][1][1]; c.v[0][0][0][0] = Values.D; Object val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? Values.A : Values.D));
|
||||
|
||||
c.v[0][0] = new Object[1][1]; c.v[0][0][0][0] = Values.E; Object val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? Values.A : Values.E));
|
||||
|
||||
c.v[0][0][0] = new Object[1]; c.v[0][0][0][0] = Values.F; Object val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? Values.A : Values.F));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1][1]; Object[] val1 = get1();
|
||||
c.v[0][0][0] = new Object[1]; Object[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1][1]; Object[][] val1 = get2();
|
||||
c.v[0][0] = new Object[1][1]; Object[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1][1]; Object[][][] val1 = get3();
|
||||
c.v[0] = new Object[1][1][1]; Object[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1][1]; Object[][][][] val1 = get4();
|
||||
c.v = new Object[1][1][1][1]; Object[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static Object get() { return ((Object[])c.v)[0]; }
|
||||
public static Object[] get1() { return (Object[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1]; ((Object[])c.v)[0] = Values.A; Object val1 = get();
|
||||
((Object[])c.v)[0] = Values.B; Object val2 = get();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, Values.B);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1]; Object[] val1 = get1();
|
||||
c.v = new Object[1]; Object[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static Object get() { return ((Object[][])c.v)[0][0]; }
|
||||
public static Object[] get1() { return (Object[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1][1]; ((Object[][])c.v)[0][0] = Values.A; Object val1 = get();
|
||||
((Object[][])c.v)[0][0] = Values.B; Object val2 = get();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, Values.B);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1]; c.v[0] = new Object[0]; Object[] val1 = get1();
|
||||
c.v[0] = new Object[0]; Object[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[0][0]; Object[] val1 = get2();
|
||||
c.v = new Object[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static Object get() { return ((Object[][][])c.v)[0][0][0]; }
|
||||
public static Object[] get1() { return (Object[])(c.v[0][0]); }
|
||||
public static Object[][] get2() { return (Object[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new Object[1][1][1]; ((Object[][][])c.v)[0][0][0] = Values.A; Object val1 = get();
|
||||
((Object[][][])c.v)[0][0][0] = Values.B; Object val2 = get();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, Values.B);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1]; c.v[0][0] = new Object[0]; Object[] val1 = get1();
|
||||
c.v[0][0] = new Object[0]; Object[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[1][1][1]; c.v[0] = new Object[0][0]; Object[][] val1 = get2();
|
||||
c.v[0] = new Object[0][0]; Object[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new Object[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new Object[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable Object a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static Object get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = Values.A; A val1 = get();
|
||||
c.v.a = Values.B; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, Values.B);
|
||||
assertEquals(val2.a, Values.B);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = Values.A; Object val1 = get1();
|
||||
c.v.a = Values.B; Object val2 = get1();
|
||||
c.v = new A(); c.v.a = Values.C; Object val3 = get1();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable Object a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static Object get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = Values.A; c.v.next.a = Values.A; A val1 = get();
|
||||
c.v.a = Values.B; c.v.next.a = Values.B; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, Values.B);
|
||||
assertEquals(val2.a, Values.B);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = Values.A; Object val1 = get1();
|
||||
c.v.a = Values.B; Object val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = Values.C; Object val3 = get1();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val2, (isStableEnabled ? Values.A : Values.B));
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.C));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable Object a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static Object get() { return c.v.left.left.left.a; }
|
||||
public static Object get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = Values.A; Object val1 = get(); Object val2 = get1();
|
||||
c.v.a = Values.B; Object val3 = get(); Object val4 = get1();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
assertEquals(val2, Values.A);
|
||||
assertEquals(val4, Values.B);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable Object a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static Object get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static Object get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = Values.A; Object val1 = get(); Object val2 = get1();
|
||||
elem.a = Values.B; Object val3 = get(); Object val4 = get1();
|
||||
|
||||
assertEquals(val1, Values.A);
|
||||
assertEquals(val3, (isStableEnabled ? Values.A : Values.B));
|
||||
|
||||
assertEquals(val2, Values.A);
|
||||
assertEquals(val4, Values.B);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(Object i, Object j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
632
hotspot/test/compiler/stable/TestStableShort.java
Normal file
632
hotspot/test/compiler/stable/TestStableShort.java
Normal file
@ -0,0 +1,632 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 TestStableShort
|
||||
* @summary tests on stable fields and arrays
|
||||
* @library /testlibrary
|
||||
* @compile -XDignore.symbol.file TestStableShort.java
|
||||
* @run main ClassFileInstaller
|
||||
* java/lang/invoke/TestStableShort
|
||||
* java/lang/invoke/TestStableShort$ShortStable
|
||||
* java/lang/invoke/TestStableShort$StaticShortStable
|
||||
* java/lang/invoke/TestStableShort$VolatileShortStable
|
||||
* java/lang/invoke/TestStableShort$ShortArrayDim1
|
||||
* java/lang/invoke/TestStableShort$ShortArrayDim2
|
||||
* java/lang/invoke/TestStableShort$ShortArrayDim3
|
||||
* java/lang/invoke/TestStableShort$ShortArrayDim4
|
||||
* java/lang/invoke/TestStableShort$ObjectArrayLowerDim0
|
||||
* java/lang/invoke/TestStableShort$ObjectArrayLowerDim1
|
||||
* java/lang/invoke/TestStableShort$NestedStableField
|
||||
* java/lang/invoke/TestStableShort$NestedStableField$A
|
||||
* java/lang/invoke/TestStableShort$NestedStableField1
|
||||
* java/lang/invoke/TestStableShort$NestedStableField1$A
|
||||
* java/lang/invoke/TestStableShort$NestedStableField2
|
||||
* java/lang/invoke/TestStableShort$NestedStableField2$A
|
||||
* java/lang/invoke/TestStableShort$NestedStableField3
|
||||
* java/lang/invoke/TestStableShort$NestedStableField3$A
|
||||
* java/lang/invoke/TestStableShort$DefaultValue
|
||||
* java/lang/invoke/TestStableShort$ObjectArrayLowerDim2
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableShort
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableShort
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:+UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableShort
|
||||
*
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:-FoldStableValues -XX:-UseCompressedOop
|
||||
* -server -XX:-TieredCompilation -Xcomp
|
||||
* -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
|
||||
* java.lang.invoke.TestStableShort
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
import com.sun.management.VMOption;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestStableShort {
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.out.println("@Stable enabled: "+isStableEnabled);
|
||||
System.out.println();
|
||||
|
||||
run(DefaultValue.class);
|
||||
run(ShortStable.class);
|
||||
run(StaticShortStable.class);
|
||||
run(VolatileShortStable.class);
|
||||
|
||||
// @Stable arrays: Dim 1-4
|
||||
run(ShortArrayDim1.class);
|
||||
run(ShortArrayDim2.class);
|
||||
run(ShortArrayDim3.class);
|
||||
run(ShortArrayDim4.class);
|
||||
|
||||
// @Stable Object field: dynamic arrays
|
||||
run(ObjectArrayLowerDim0.class);
|
||||
run(ObjectArrayLowerDim1.class);
|
||||
run(ObjectArrayLowerDim2.class);
|
||||
|
||||
// Nested @Stable fields
|
||||
run(NestedStableField.class);
|
||||
run(NestedStableField1.class);
|
||||
run(NestedStableField2.class);
|
||||
run(NestedStableField3.class);
|
||||
|
||||
if (failed) {
|
||||
throw new Error("TEST FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class DefaultValue {
|
||||
public @Stable short v;
|
||||
|
||||
public static final DefaultValue c = new DefaultValue();
|
||||
public static short get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
short val1 = get();
|
||||
c.v = 1; short val2 = get();
|
||||
assertEquals(val1, 0);
|
||||
assertEquals(val2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ShortStable {
|
||||
public @Stable short v;
|
||||
|
||||
public static final ShortStable c = new ShortStable();
|
||||
public static short get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1; short val1 = get();
|
||||
c.v = 32767; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 32767));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class StaticShortStable {
|
||||
public static @Stable short v;
|
||||
|
||||
public static final StaticShortStable c = new StaticShortStable();
|
||||
public static short get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1; short val1 = get();
|
||||
c.v = 32767; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 32767));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class VolatileShortStable {
|
||||
public @Stable volatile short v;
|
||||
|
||||
public static final VolatileShortStable c = new VolatileShortStable();
|
||||
public static short get() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
c.v = 1; short val1 = get();
|
||||
c.v = 32767; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 32767));
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// @Stable array == field && all components are stable
|
||||
|
||||
static class ShortArrayDim1 {
|
||||
public @Stable short[] v;
|
||||
|
||||
public static final ShortArrayDim1 c = new ShortArrayDim1();
|
||||
public static short get() { return c.v[0]; }
|
||||
public static short get1() { return c.v[10]; }
|
||||
public static short[] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1]; c.v[0] = 1; short val1 = get();
|
||||
c.v[0] = 2; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new short[1]; c.v[0] = 3; short val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[20]; c.v[10] = 1; short val1 = get1();
|
||||
c.v[10] = 2; short val2 = get1();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new short[20]; c.v[10] = 3; short val3 = get1();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1]; short[] val1 = get2();
|
||||
c.v = new short[1]; short[] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ShortArrayDim2 {
|
||||
public @Stable short[][] v;
|
||||
|
||||
public static final ShortArrayDim2 c = new ShortArrayDim2();
|
||||
public static short get() { return c.v[0][0]; }
|
||||
public static short[] get1() { return c.v[0]; }
|
||||
public static short[][] get2() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1][1]; c.v[0][0] = 1; short val1 = get();
|
||||
c.v[0][0] = 2; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new short[1][1]; c.v[0][0] = 3; short val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new short[1]; c.v[0][0] = 4; short val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1]; short[] val1 = get1();
|
||||
c.v[0] = new short[1]; short[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1]; short[][] val1 = get2();
|
||||
c.v = new short[1][1]; short[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ShortArrayDim3 {
|
||||
public @Stable short[][][] v;
|
||||
|
||||
public static final ShortArrayDim3 c = new ShortArrayDim3();
|
||||
public static short get() { return c.v[0][0][0]; }
|
||||
public static short[] get1() { return c.v[0][0]; }
|
||||
public static short[][] get2() { return c.v[0]; }
|
||||
public static short[][][] get3() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1][1][1]; c.v[0][0][0] = 1; short val1 = get();
|
||||
c.v[0][0][0] = 2; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new short[1][1][1]; c.v[0][0][0] = 3; short val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new short[1][1]; c.v[0][0][0] = 4; short val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new short[1]; c.v[0][0][0] = 5; short val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1]; short[] val1 = get1();
|
||||
c.v[0][0] = new short[1]; short[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1]; short[][] val1 = get2();
|
||||
c.v[0] = new short[1][1]; short[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1]; short[][][] val1 = get3();
|
||||
c.v = new short[1][1][1]; short[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ShortArrayDim4 {
|
||||
public @Stable short[][][][] v;
|
||||
|
||||
public static final ShortArrayDim4 c = new ShortArrayDim4();
|
||||
public static short get() { return c.v[0][0][0][0]; }
|
||||
public static short[] get1() { return c.v[0][0][0]; }
|
||||
public static short[][] get2() { return c.v[0][0]; }
|
||||
public static short[][][] get3() { return c.v[0]; }
|
||||
public static short[][][][] get4() { return c.v; }
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 1; short val1 = get();
|
||||
c.v[0][0][0][0] = 2; short val2 = get();
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
|
||||
c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 3; short val3 = get();
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
|
||||
c.v[0] = new short[1][1][1]; c.v[0][0][0][0] = 4; short val4 = get();
|
||||
assertEquals(val4, (isStableEnabled ? 1 : 4));
|
||||
|
||||
c.v[0][0] = new short[1][1]; c.v[0][0][0][0] = 5; short val5 = get();
|
||||
assertEquals(val5, (isStableEnabled ? 1 : 5));
|
||||
|
||||
c.v[0][0][0] = new short[1]; c.v[0][0][0][0] = 6; short val6 = get();
|
||||
assertEquals(val6, (isStableEnabled ? 1 : 6));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1][1]; short[] val1 = get1();
|
||||
c.v[0][0][0] = new short[1]; short[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1][1]; short[][] val1 = get2();
|
||||
c.v[0][0] = new short[1][1]; short[][] val2 = get2();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1][1]; short[][][] val1 = get3();
|
||||
c.v[0] = new short[1][1][1]; short[][][] val2 = get3();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1][1]; short[][][][] val1 = get4();
|
||||
c.v = new short[1][1][1][1]; short[][][][] val2 = get4();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Dynamic Dim is higher than static
|
||||
|
||||
static class ObjectArrayLowerDim0 {
|
||||
public @Stable Object v;
|
||||
|
||||
public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
|
||||
public static short get() { return ((short[])c.v)[0]; }
|
||||
public static short[] get1() { return (short[])c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1]; ((short[])c.v)[0] = 1; short val1 = get();
|
||||
((short[])c.v)[0] = 2; short val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1]; short[] val1 = get1();
|
||||
c.v = new short[1]; short[] val2 = get1();
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim1 {
|
||||
public @Stable Object[] v;
|
||||
|
||||
public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
|
||||
public static short get() { return ((short[][])c.v)[0][0]; }
|
||||
public static short[] get1() { return (short[])(c.v[0]); }
|
||||
public static Object[] get2() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1][1]; ((short[][])c.v)[0][0] = 1; short val1 = get();
|
||||
((short[][])c.v)[0][0] = 2; short val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1]; c.v[0] = new short[0]; short[] val1 = get1();
|
||||
c.v[0] = new short[0]; short[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[0][0]; Object[] val1 = get2();
|
||||
c.v = new short[0][0]; Object[] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class ObjectArrayLowerDim2 {
|
||||
public @Stable Object[][] v;
|
||||
|
||||
public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
|
||||
public static short get() { return ((short[][][])c.v)[0][0][0]; }
|
||||
public static short[] get1() { return (short[])(c.v[0][0]); }
|
||||
public static short[][] get2() { return (short[][])(c.v[0]); }
|
||||
public static Object[][] get3() { return c.v; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new short[1][1][1]; ((short[][][])c.v)[0][0][0] = 1; short val1 = get();
|
||||
((short[][][])c.v)[0][0][0] = 2; short val2 = get();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1]; c.v[0][0] = new short[0]; short[] val1 = get1();
|
||||
c.v[0][0] = new short[0]; short[] val2 = get1();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[1][1][1]; c.v[0] = new short[0][0]; short[][] val1 = get2();
|
||||
c.v[0] = new short[0][0]; short[][] val2 = get2();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new short[0][0][0]; Object[][] val1 = get3();
|
||||
c.v = new short[0][0][0]; Object[][] val2 = get3();
|
||||
|
||||
assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField {
|
||||
static class A {
|
||||
public @Stable short a;
|
||||
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField c = new NestedStableField();
|
||||
public static A get() { return c.v; }
|
||||
public static short get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; A val1 = get();
|
||||
c.v.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.a = 1; short val1 = get1();
|
||||
c.v.a = 2; short val2 = get1();
|
||||
c.v = new A(); c.v.a = 3; short val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField1 {
|
||||
static class A {
|
||||
public @Stable short a;
|
||||
public @Stable A next;
|
||||
}
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField1 c = new NestedStableField1();
|
||||
public static A get() { return c.v.next.next.next.next.next.next.next; }
|
||||
public static short get1() { return get().a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.next = new A(); c.v.next.next = c.v;
|
||||
c.v.a = 1; c.v.next.a = 1; A val1 = get();
|
||||
c.v.a = 2; c.v.next.a = 2; A val2 = get();
|
||||
|
||||
assertEquals(val1.a, 2);
|
||||
assertEquals(val2.a, 2);
|
||||
}
|
||||
|
||||
{
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 1; short val1 = get1();
|
||||
c.v.a = 2; short val2 = get1();
|
||||
c.v = new A(); c.v.next = c.v;
|
||||
c.v.a = 3; short val3 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val2, (isStableEnabled ? 1 : 2));
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField2 {
|
||||
static class A {
|
||||
public @Stable short a;
|
||||
public @Stable A left;
|
||||
public A right;
|
||||
}
|
||||
|
||||
public @Stable A v;
|
||||
|
||||
public static final NestedStableField2 c = new NestedStableField2();
|
||||
public static short get() { return c.v.left.left.left.a; }
|
||||
public static short get1() { return c.v.left.left.right.left.a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
c.v = new A(); c.v.left = c.v.right = c.v;
|
||||
c.v.a = 1; short val1 = get(); short val2 = get1();
|
||||
c.v.a = 2; short val3 = get(); short val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
|
||||
static class NestedStableField3 {
|
||||
static class A {
|
||||
public @Stable short a;
|
||||
public @Stable A[] left;
|
||||
public A[] right;
|
||||
}
|
||||
|
||||
public @Stable A[] v;
|
||||
|
||||
public static final NestedStableField3 c = new NestedStableField3();
|
||||
public static short get() { return c.v[0].left[1].left[0].left[1].a; }
|
||||
public static short get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
|
||||
|
||||
public static void test() throws Exception {
|
||||
{
|
||||
A elem = new A();
|
||||
c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
|
||||
elem.a = 1; short val1 = get(); short val2 = get1();
|
||||
elem.a = 2; short val3 = get(); short val4 = get1();
|
||||
|
||||
assertEquals(val1, 1);
|
||||
assertEquals(val3, (isStableEnabled ? 1 : 2));
|
||||
|
||||
assertEquals(val2, 1);
|
||||
assertEquals(val4, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ==================================================== */
|
||||
// Auxiliary methods
|
||||
static void assertEquals(int i, int j) { if (i != j) throw new AssertionError(i + " != " + j); }
|
||||
static void assertTrue(boolean b) { if (!b) throw new AssertionError(); }
|
||||
|
||||
static boolean failed = false;
|
||||
|
||||
public static void run(Class<?> test) {
|
||||
Throwable ex = null;
|
||||
System.out.print(test.getName()+": ");
|
||||
try {
|
||||
test.getMethod("test").invoke(null);
|
||||
} catch (InvocationTargetException e) {
|
||||
ex = e.getCause();
|
||||
} catch (Throwable e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
if (ex == null) {
|
||||
System.out.println("PASSED");
|
||||
} else {
|
||||
failed = true;
|
||||
System.out.println("FAILED");
|
||||
ex.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static final boolean isStableEnabled;
|
||||
static {
|
||||
HotSpotDiagnosticMXBean diagnostic
|
||||
= ManagementFactoryHelper.getDiagnosticMXBean();
|
||||
VMOption tmp;
|
||||
try {
|
||||
tmp = diagnostic.getVMOption("FoldStableValues");
|
||||
} catch (IllegalArgumentException e) {
|
||||
tmp = null;
|
||||
}
|
||||
isStableEnabled = (tmp == null ? false : Boolean.parseBoolean(tmp.getValue()));
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -70,6 +70,9 @@ public class NonTieredLevelsTest extends CompLevelsTest {
|
||||
|
||||
@Override
|
||||
protected void test() throws Exception {
|
||||
if (skipXcompOSR()) {
|
||||
return;
|
||||
}
|
||||
checkNotCompiled();
|
||||
compile();
|
||||
checkCompiled();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -51,6 +51,9 @@ public class TieredLevelsTest extends CompLevelsTest {
|
||||
|
||||
@Override
|
||||
protected void test() throws Exception {
|
||||
if (skipXcompOSR()) {
|
||||
return;
|
||||
}
|
||||
checkNotCompiled();
|
||||
compile();
|
||||
checkCompiled();
|
||||
|
@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @bug 8027571
|
||||
* @summary meet of TopPTR exact array with constant array is not symmetric
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestMeetTopArrayExactConstantArray
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestMeetTopArrayExactConstantArray
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @bug 8027422
|
||||
* @summary type methods shouldn't always operate on speculative part
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -XX:-BackgroundCompilation TestSpeculationFailedHigherEqual
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @bug 8024070
|
||||
* @summary Test that type speculation doesn't cause incorrect execution
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation TypeSpeculation
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation TypeSpeculation
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @bug 8031752
|
||||
* @summary speculative traps need to be cleaned up at GC
|
||||
* @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UseTypeSpeculation -XX:TypeProfileLevel=222 -XX:CompileCommand=exclude,java.lang.reflect.Method::invoke -XX:CompileCommand=exclude,sun.reflect.DelegatingMethodAccessorImpl::invoke -Xmx1M TestSpecTrapClassUnloading
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -195,6 +195,29 @@ public abstract class CompilerWhiteBoxTest {
|
||||
printInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, that {@linkplain #method} is not compiled at the given compilation
|
||||
* level or above.
|
||||
*
|
||||
* @param compLevel
|
||||
*
|
||||
* @throws RuntimeException if {@linkplain #method} is in compiler queue or
|
||||
* is compiled, or if {@linkplain #method} has zero
|
||||
* compilation level.
|
||||
*/
|
||||
|
||||
protected final void checkNotCompiled(int compLevel) {
|
||||
if (WHITE_BOX.isMethodQueuedForCompilation(method)) {
|
||||
throw new RuntimeException(method + " must not be in queue");
|
||||
}
|
||||
if (WHITE_BOX.getMethodCompilationLevel(method, false) >= compLevel) {
|
||||
throw new RuntimeException(method + " comp_level must be >= maxCompLevel");
|
||||
}
|
||||
if (WHITE_BOX.getMethodCompilationLevel(method, true) >= compLevel) {
|
||||
throw new RuntimeException(method + " osr_comp_level must be >= maxCompLevel");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, that {@linkplain #method} is not compiled.
|
||||
*
|
||||
@ -380,6 +403,20 @@ public abstract class CompilerWhiteBoxTest {
|
||||
/** flag for OSR test case */
|
||||
boolean isOsr();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the current test case is OSR and the mode is
|
||||
* Xcomp, otherwise {@code false}
|
||||
*/
|
||||
protected boolean skipXcompOSR() {
|
||||
boolean result = testCase.isOsr()
|
||||
&& CompilerWhiteBoxTest.MODE.startsWith("compiled ");
|
||||
if (result && IS_VERBOSE) {
|
||||
System.err.printf("Warning: %s is not applicable in %s%n",
|
||||
testCase.name(), CompilerWhiteBoxTest.MODE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
enum SimpleTestCase implements CompilerWhiteBoxTest.TestCase {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -51,11 +51,8 @@ public class DeoptimizeAllTest extends CompilerWhiteBoxTest {
|
||||
*/
|
||||
@Override
|
||||
protected void test() throws Exception {
|
||||
if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
|
||||
"compiled ")) {
|
||||
System.err.printf("Warning: %s is not applicable in %s%n",
|
||||
testCase.name(), CompilerWhiteBoxTest.MODE);
|
||||
return;
|
||||
if (skipXcompOSR()) {
|
||||
return;
|
||||
}
|
||||
compile();
|
||||
checkCompiled();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -51,11 +51,8 @@ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest {
|
||||
*/
|
||||
@Override
|
||||
protected void test() throws Exception {
|
||||
if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
|
||||
"compiled ")) {
|
||||
System.err.printf("Warning: %s is not applicable in %s%n",
|
||||
testCase.name(), CompilerWhiteBoxTest.MODE);
|
||||
return;
|
||||
if (skipXcompOSR()) {
|
||||
return;
|
||||
}
|
||||
compile();
|
||||
checkCompiled();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -24,13 +24,17 @@
|
||||
/*
|
||||
* @test IsMethodCompilableTest
|
||||
* @bug 8007270 8006683 8007288 8022832
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @library /testlibrary /testlibrary/whitebox /testlibrary/com/oracle/java/testlibrary
|
||||
* @build IsMethodCompilableTest
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
|
||||
* @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
|
||||
* @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
|
||||
* @summary testing of WB::isMethodCompilable()
|
||||
* @author igor.ignatyev@oracle.com
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.Platform;
|
||||
|
||||
public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
|
||||
/**
|
||||
* Value of {@code -XX:PerMethodRecompilationCutoff}
|
||||
@ -43,7 +47,7 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
|
||||
if (tmp == -1) {
|
||||
PER_METHOD_RECOMPILATION_CUTOFF = -1 /* Inf */;
|
||||
} else {
|
||||
PER_METHOD_RECOMPILATION_CUTOFF = 1 + (0xFFFFFFFFL & tmp);
|
||||
PER_METHOD_RECOMPILATION_CUTOFF = (0xFFFFFFFFL & tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,19 +64,23 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
|
||||
/**
|
||||
* Tests {@code WB::isMethodCompilable()} by recompilation of tested method
|
||||
* 'PerMethodRecompilationCutoff' times and checks compilation status. Also
|
||||
* checks that WB::clearMethodState() clears no-compilable flags.
|
||||
* checks that WB::clearMethodState() clears no-compilable flags. Only
|
||||
* applicable to c2 compiled methods.
|
||||
*
|
||||
* @throws Exception if one of the checks fails.
|
||||
*/
|
||||
@Override
|
||||
protected void test() throws Exception {
|
||||
if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
|
||||
"compiled ")) {
|
||||
System.err.printf("Warning: %s is not applicable in %s%n",
|
||||
testCase.name(), CompilerWhiteBoxTest.MODE);
|
||||
return;
|
||||
|
||||
// Only c2 compilations can be disabled through PerMethodRecompilationCutoff
|
||||
if (!Platform.isServer()) {
|
||||
return;
|
||||
}
|
||||
if (!isCompilable()) {
|
||||
|
||||
if (skipXcompOSR()) {
|
||||
return;
|
||||
}
|
||||
if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
|
||||
throw new RuntimeException(method + " must be compilable");
|
||||
}
|
||||
System.out.println("PerMethodRecompilationCutoff = "
|
||||
@ -83,39 +91,37 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
|
||||
return;
|
||||
}
|
||||
|
||||
// deoptimize 'PerMethodRecompilationCutoff' times and clear state
|
||||
for (long i = 0L, n = PER_METHOD_RECOMPILATION_CUTOFF - 1; i < n; ++i) {
|
||||
compileAndDeoptimize();
|
||||
// deoptimize 'PerMethodRecompilationCutoff' times
|
||||
for (long attempts = 0, successes = 0;
|
||||
(successes < PER_METHOD_RECOMPILATION_CUTOFF) &&
|
||||
(attempts < PER_METHOD_RECOMPILATION_CUTOFF*2) &&
|
||||
isCompilable(COMP_LEVEL_FULL_OPTIMIZATION); attempts++) {
|
||||
if (compileAndDeoptimize() == COMP_LEVEL_FULL_OPTIMIZATION) {
|
||||
successes++;
|
||||
}
|
||||
}
|
||||
if (!testCase.isOsr() && !isCompilable()) {
|
||||
// in osr test case count of deopt maybe more than iterations
|
||||
throw new RuntimeException(method + " is not compilable after "
|
||||
+ (PER_METHOD_RECOMPILATION_CUTOFF - 1) + " iterations");
|
||||
}
|
||||
WHITE_BOX.clearMethodState(method);
|
||||
|
||||
// deoptimize 'PerMethodRecompilationCutoff' + 1 times
|
||||
long i;
|
||||
for (i = 0L; i < PER_METHOD_RECOMPILATION_CUTOFF
|
||||
&& isCompilable(); ++i) {
|
||||
compileAndDeoptimize();
|
||||
}
|
||||
if (!testCase.isOsr() && i != PER_METHOD_RECOMPILATION_CUTOFF) {
|
||||
if (!testCase.isOsr() && !isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
|
||||
// in osr test case count of deopt maybe more than iterations
|
||||
throw new RuntimeException(method + " is not compilable after "
|
||||
+ i + " iterations, but must only after "
|
||||
+ PER_METHOD_RECOMPILATION_CUTOFF);
|
||||
+ PER_METHOD_RECOMPILATION_CUTOFF + " iterations");
|
||||
}
|
||||
if (isCompilable()) {
|
||||
|
||||
// Now compile once more
|
||||
compileAndDeoptimize();
|
||||
|
||||
if (isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
|
||||
throw new RuntimeException(method + " is still compilable after "
|
||||
+ PER_METHOD_RECOMPILATION_CUTOFF + " iterations");
|
||||
}
|
||||
compile();
|
||||
checkNotCompiled();
|
||||
compile();
|
||||
waitBackgroundCompilation();
|
||||
checkNotCompiled(COMP_LEVEL_FULL_OPTIMIZATION);
|
||||
|
||||
// WB.clearMethodState() must reset no-compilable flags
|
||||
WHITE_BOX.clearMethodState(method);
|
||||
if (!isCompilable()) {
|
||||
if (!isCompilable(COMP_LEVEL_FULL_OPTIMIZATION)) {
|
||||
throw new RuntimeException(method
|
||||
+ " is not compilable after clearMethodState()");
|
||||
}
|
||||
@ -123,9 +129,11 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest {
|
||||
checkCompiled();
|
||||
}
|
||||
|
||||
private void compileAndDeoptimize() throws Exception {
|
||||
private int compileAndDeoptimize() throws Exception {
|
||||
compile();
|
||||
waitBackgroundCompilation();
|
||||
int compLevel = getCompLevel();
|
||||
deoptimize();
|
||||
return compLevel;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2014, 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
|
||||
@ -53,11 +53,8 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest {
|
||||
*/
|
||||
@Override
|
||||
protected void test() throws Exception {
|
||||
if (testCase.isOsr() && CompilerWhiteBoxTest.MODE.startsWith(
|
||||
"compiled ")) {
|
||||
System.err.printf("Warning: %s is not applicable in %s%n",
|
||||
testCase.name(), CompilerWhiteBoxTest.MODE);
|
||||
return;
|
||||
if (skipXcompOSR()) {
|
||||
return;
|
||||
}
|
||||
checkNotCompiled();
|
||||
if (!isCompilable()) {
|
||||
|
@ -28,6 +28,15 @@ public class Platform {
|
||||
private static final String dataModel = System.getProperty("sun.arch.data.model");
|
||||
private static final String vmVersion = System.getProperty("java.vm.version");
|
||||
private static final String osArch = System.getProperty("os.arch");
|
||||
private static final String vmName = System.getProperty("java.vm.name");
|
||||
|
||||
public static boolean isClient() {
|
||||
return vmName.endsWith(" Client VM");
|
||||
}
|
||||
|
||||
public static boolean isServer() {
|
||||
return vmName.endsWith(" Server VM");
|
||||
}
|
||||
|
||||
public static boolean is32bit() {
|
||||
return dataModel.equals("32");
|
||||
|
Loading…
Reference in New Issue
Block a user