提交 498daef4 编写于 作者: A asaha

Merge

......@@ -1075,29 +1075,30 @@ static bool find_vma(address addr, address* vma_low, address* vma_high) {
// Locate initial thread stack. This special handling of initial thread stack
// is needed because pthread_getattr_np() on most (all?) Linux distros returns
// bogus value for initial thread.
// bogus value for the primordial process thread. While the launcher has created
// the VM in a new thread since JDK 6, we still have to allow for the use of the
// JNI invocation API from a primordial thread.
void os::Linux::capture_initial_stack(size_t max_size) {
// stack size is the easy part, get it from RLIMIT_STACK
size_t stack_size;
// max_size is either 0 (which means accept OS default for thread stacks) or
// a user-specified value known to be at least the minimum needed. If we
// are actually on the primordial thread we can make it appear that we have a
// smaller max_size stack by inserting the guard pages at that location. But we
// cannot do anything to emulate a larger stack than what has been provided by
// the OS or threading library. In fact if we try to use a stack greater than
// what is set by rlimit then we will crash the hosting process.
// Maximum stack size is the easy part, get it from RLIMIT_STACK.
// If this is "unlimited" then it will be a huge value.
struct rlimit rlim;
getrlimit(RLIMIT_STACK, &rlim);
stack_size = rlim.rlim_cur;
size_t stack_size = rlim.rlim_cur;
// 6308388: a bug in ld.so will relocate its own .data section to the
// lower end of primordial stack; reduce ulimit -s value a little bit
// so we won't install guard page on ld.so's data section.
stack_size -= 2 * page_size();
// 4441425: avoid crash with "unlimited" stack size on SuSE 7.1 or Redhat
// 7.1, in both cases we will get 2G in return value.
// 4466587: glibc 2.2.x compiled w/o "--enable-kernel=2.4.0" (RH 7.0,
// SuSE 7.2, Debian) can not handle alternate signal stack correctly
// for initial thread if its stack size exceeds 6M. Cap it at 2M,
// in case other parts in glibc still assumes 2M max stack size.
// FIXME: alt signal stack is gone, maybe we can relax this constraint?
// Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small
if (stack_size > 2 * K * K IA64_ONLY(*2))
stack_size = 2 * K * K IA64_ONLY(*2);
// Try to figure out where the stack base (top) is. This is harder.
//
// When an application is started, glibc saves the initial stack pointer in
......@@ -1257,14 +1258,18 @@ void os::Linux::capture_initial_stack(size_t max_size) {
// stack_top could be partially down the page so align it
stack_top = align_size_up(stack_top, page_size());
if (max_size && stack_size > max_size) {
_initial_thread_stack_size = max_size;
// Allowed stack value is minimum of max_size and what we derived from rlimit
if (max_size > 0) {
_initial_thread_stack_size = MIN2(max_size, stack_size);
} else {
_initial_thread_stack_size = stack_size;
// Accept the rlimit max, but if stack is unlimited then it will be huge, so
// clamp it at 8MB as we do on Solaris
_initial_thread_stack_size = MIN2(stack_size, 8*M);
}
_initial_thread_stack_size = align_size_down(_initial_thread_stack_size, page_size());
_initial_thread_stack_bottom = (address)stack_top - _initial_thread_stack_size;
assert(_initial_thread_stack_bottom < (address)stack_top, "overflow!");
}
////////////////////////////////////////////////////////////////////////////////
......
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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
......@@ -1747,8 +1747,7 @@ void os::win32::print_windows_version(outputStream* st) {
if (is_workstation) {
st->print("10");
} else {
// The server version name of Windows 10 is not known at this time
st->print("%d.%d", major_version, minor_version);
st->print("Server 2016");
}
break;
......
......@@ -648,6 +648,7 @@ bool InstructForm::is_wide_memory_kill(FormDict &globals) const {
if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true;
if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true;
if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true;
if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true;
if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true;
if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true;
......
......@@ -1485,6 +1485,21 @@ void GraphBuilder::method_return(Value x) {
// Check to see whether we are inlining. If so, Return
// instructions become Gotos to the continuation point.
if (continuation() != NULL) {
int invoke_bci = state()->caller_state()->bci();
if (x != NULL) {
ciMethod* caller = state()->scope()->caller()->method();
Bytecodes::Code invoke_raw_bc = caller->raw_code_at_bci(invoke_bci);
if (invoke_raw_bc == Bytecodes::_invokehandle || invoke_raw_bc == Bytecodes::_invokedynamic) {
ciType* declared_ret_type = caller->get_declared_signature_at_bci(invoke_bci)->return_type();
if (declared_ret_type->is_klass() && x->exact_type() == NULL &&
x->declared_type() != declared_ret_type && declared_ret_type != compilation()->env()->Object_klass()) {
x = append(new TypeCast(declared_ret_type->as_klass(), x, copy_state_before()));
}
}
}
assert(!method()->is_synchronized() || InlineSynchronizedMethods, "can not inline synchronized methods yet");
if (compilation()->env()->dtrace_method_probes()) {
......@@ -1508,7 +1523,6 @@ void GraphBuilder::method_return(Value x) {
// State at end of inlined method is the state of the caller
// without the method parameters on stack, including the
// return value, if any, of the inlined method on operand stack.
int invoke_bci = state()->caller_state()->bci();
set_state(state()->caller_state()->copy_for_parsing());
if (x != NULL) {
state()->push(x->type(), x);
......
......@@ -360,7 +360,8 @@ void Invoke::state_values_do(ValueVisitor* f) {
}
ciType* Invoke::declared_type() const {
ciType *t = _target->signature()->return_type();
ciSignature* declared_signature = state()->scope()->method()->get_declared_signature_at_bci(state()->bci());
ciType *t = declared_signature->return_type();
assert(t->basic_type() != T_VOID, "need return value of void method?");
return t;
}
......
......@@ -3191,14 +3191,14 @@ void LIRGenerator::profile_arguments(ProfileCall* x) {
Bytecodes::Code bc = x->method()->java_code_at_bci(bci);
int start = 0;
int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->number_of_arguments();
if (x->inlined() && x->callee()->is_static() && Bytecodes::has_receiver(bc)) {
if (x->callee()->is_loaded() && x->callee()->is_static() && Bytecodes::has_receiver(bc)) {
// first argument is not profiled at call (method handle invoke)
assert(x->method()->raw_code_at_bci(bci) == Bytecodes::_invokehandle, "invokehandle expected");
start = 1;
}
ciSignature* callee_signature = x->callee()->signature();
// method handle call to virtual method
bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc);
bool has_receiver = x->callee()->is_loaded() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc);
ciSignatureStream callee_signature_stream(callee_signature, has_receiver ? x->callee()->holder() : NULL);
bool ignored_will_link;
......
......@@ -207,7 +207,7 @@ void ciField::initialize_from(fieldDescriptor* fd) {
// Check to see if the field is constant.
bool is_final = this->is_final();
bool is_stable = FoldStableValues && this->is_stable();
if (_holder->is_initialized() && (is_final || is_stable)) {
if (_holder->is_initialized() && ((is_final && !has_initialized_final_update()) || is_stable)) {
if (!this->is_static()) {
// A field can be constant if it's a final static field or if
// it's a final non-static field of a trusted class (classes in
......
......@@ -124,22 +124,8 @@ public:
return _holder->is_shared() && !is_static();
}
// Is this field a constant?
//
// Clarification: A field is considered constant if:
// 1. The field is both static and final
// 2. The canonical holder of the field has undergone
// static initialization.
// 3. If the field is an object or array, then the oop
// in question is allocated in perm space.
// 4. The field is not one of the special static/final
// non-constant fields. These are java.lang.System.in
// and java.lang.System.out. Abomination.
//
// A field is also considered constant if it is marked @Stable
// and is non-null (or non-zero, if a primitive).
// For non-static fields, the null/zero check must be
// arranged by the user, as constant_value().is_null_or_zero().
// Is this field a constant? See ciField::initialize_from() for details
// about how a field is determined to be constant.
bool is_constant() { return _is_constant; }
// Get the constant value of this field.
......@@ -176,6 +162,9 @@ public:
bool is_stable () { return flags().is_stable(); }
bool is_volatile () { return flags().is_volatile(); }
bool is_transient () { return flags().is_transient(); }
// The field is modified outside of instance initializer methods
// (or class/initializer methods if the field is static).
bool has_initialized_final_update() { return flags().has_initialized_final_update(); }
bool is_call_site_target() {
ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass();
......
......@@ -46,20 +46,25 @@ private:
public:
// Java access flags
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; }
bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; }
bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; }
bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; }
bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; }
bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; }
bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; }
bool is_synchronized () const { return (_flags & JVM_ACC_SYNCHRONIZED ) != 0; }
bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE ) != 0; }
// In case the current object represents a field, return true if
// the field is modified outside of instance initializer methods
// (or class/initializer methods if the field is static) and false
// otherwise.
bool has_initialized_final_update() const { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; };
// Conversion
jint as_int() { return _flags; }
......
......@@ -243,6 +243,21 @@ class ciMethod : public ciMetadata {
ciField* get_field_at_bci( int bci, bool &will_link);
ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
ciSignature* get_declared_signature_at_bci(int bci) {
bool ignored_will_link;
ciSignature* declared_signature;
get_method_at_bci(bci, ignored_will_link, &declared_signature);
assert(declared_signature != NULL, "cannot be null");
return declared_signature;
}
ciMethod* get_method_at_bci(int bci) {
bool ignored_will_link;
ciSignature* ignored_declared_signature;
return get_method_at_bci(bci, ignored_will_link, &ignored_declared_signature);
}
// Given a certain calling environment, find the monomorphic target
// for the call. Return NULL if the call is not monomorphic in
// its calling environment.
......
/*
* Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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
......@@ -631,11 +631,10 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev
double overall_cm_overhead =
(double) MaxGCPauseMillis * marking_overhead /
(double) GCPauseIntervalMillis;
double cpu_ratio = 1.0 / (double) os::processor_count();
double cpu_ratio = 1.0 / os::initial_active_processor_count();
double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio);
double marking_task_overhead =
overall_cm_overhead / marking_thread_num *
(double) os::processor_count();
overall_cm_overhead / marking_thread_num * os::initial_active_processor_count();
double sleep_factor =
(1.0 - marking_task_overhead) / marking_task_overhead;
......
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, 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
......@@ -80,7 +80,7 @@ DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :
// Determines how many mutator threads can process the buffers in parallel.
uint DirtyCardQueueSet::num_par_ids() {
return (uint)os::processor_count();
return (uint)os::initial_active_processor_count();
}
void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock,
......
......@@ -452,9 +452,13 @@ get_LNC_array_for_space(Space* sp,
// event lock and do the read again in case some other thread had already
// succeeded and done the resize.
int cur_collection = Universe::heap()->total_collections();
if (_last_LNC_resizing_collection[i] != cur_collection) {
// Updated _last_LNC_resizing_collection[i] must not be visible before
// _lowest_non_clean and friends are visible. Therefore use acquire/release
// to guarantee this on non TSO architecures.
if (OrderAccess::load_acquire(&_last_LNC_resizing_collection[i]) != cur_collection) {
MutexLocker x(ParGCRareEvent_lock);
if (_last_LNC_resizing_collection[i] != cur_collection) {
// This load_acquire is here for clarity only. The MutexLocker already fences.
if (OrderAccess::load_acquire(&_last_LNC_resizing_collection[i]) != cur_collection) {
if (_lowest_non_clean[i] == NULL ||
n_chunks != _lowest_non_clean_chunk_size[i]) {
......@@ -474,7 +478,8 @@ get_LNC_array_for_space(Space* sp,
_lowest_non_clean[i][j] = NULL;
}
}
_last_LNC_resizing_collection[i] = cur_collection;
// Make sure this gets visible only after _lowest_non_clean* was initialized
OrderAccess::release_store(&_last_LNC_resizing_collection[i], cur_collection);
}
}
// In any case, now do the initialization.
......
......@@ -396,10 +396,45 @@ void Rewriter::scan_method(Method* method, bool reverse, bool* invokespecial_err
break;
}
case Bytecodes::_putstatic :
case Bytecodes::_putfield : {
if (!reverse) {
// Check if any final field of the class given as parameter is modified
// outside of initializer methods of the class. Fields that are modified
// are marked with a flag. For marked fields, the compilers do not perform
// constant folding (as the field can be changed after initialization).
//
// The check is performed after verification and only if verification has
// succeeded. Therefore, the class is guaranteed to be well-formed.
InstanceKlass* klass = method->method_holder();
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
constantPoolHandle cp(method->constants());
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
if (klass->name() == ref_class_name) {
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
fieldDescriptor fd;
if (klass->find_field(field_name, field_sig, &fd) != NULL) {
if (fd.access_flags().is_final()) {
if (fd.access_flags().is_static()) {
if (!method->is_static_initializer()) {
fd.set_has_initialized_final_update(true);
}
} else {
if (!method->is_object_initializer()) {
fd.set_has_initialized_final_update(true);
}
}
}
}
}
}
}
// fall through
case Bytecodes::_getstatic : // fall through
case Bytecodes::_putstatic : // fall through
case Bytecodes::_getfield : // fall through
case Bytecodes::_putfield : // fall through
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokestatic :
case Bytecodes::_invokeinterface:
......
......@@ -217,7 +217,7 @@ class CardTableModRefBS: public ModRefBarrierSet {
CardArr* _lowest_non_clean;
size_t* _lowest_non_clean_chunk_size;
uintptr_t* _lowest_non_clean_base_chunk_index;
int* _last_LNC_resizing_collection;
volatile int* _last_LNC_resizing_collection;
// Initializes "lowest_non_clean" to point to the array for the region
// covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
......
......@@ -590,7 +590,7 @@ bool Method::is_constant_getter() const {
}
bool Method::is_initializer() const {
return name() == vmSymbols::object_initializer_name() || is_static_initializer();
return is_object_initializer() || is_static_initializer();
}
bool Method::has_valid_initializer_flags() const {
......@@ -606,6 +606,9 @@ bool Method::is_static_initializer() const {
has_valid_initializer_flags();
}
bool Method::is_object_initializer() const {
return name() == vmSymbols::object_initializer_name();
}
objArrayHandle Method::resolved_checked_exceptions_impl(Method* this_oop, TRAPS) {
int length = this_oop->checked_exceptions_length();
......
......@@ -627,6 +627,9 @@ class Method : public Metadata {
// valid static initializer flags.
bool is_static_initializer() const;
// returns true if the method name is <init>
bool is_object_initializer() const;
// compiled code support
// NOTE: code() is inherently racy as deopt can be clearing code
// simultaneously. Use with caution.
......
......@@ -188,7 +188,10 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) {
// the call instruction will have a seemingly deficient out-count.
// (The bailout says something misleading about an "infinite loop".)
if (kit.gvn().type(receiver)->higher_equal(TypePtr::NULL_PTR)) {
kit.inc_sp(method()->arg_size()); // restore arguments
assert(Bytecodes::is_invoke(kit.java_bc()), err_msg("%d: %s", kit.java_bc(), Bytecodes::name(kit.java_bc())));
ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci());
int arg_size = declared_method->signature()->arg_size_for_bc(kit.java_bc());
kit.inc_sp(arg_size); // restore arguments
kit.uncommon_trap(Deoptimization::Reason_null_check,
Deoptimization::Action_none,
NULL, "null receiver");
......@@ -1119,7 +1122,10 @@ CallGenerator::for_uncommon_trap(ciMethod* m,
JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms) {
GraphKit kit(jvms);
// Take the trap with arguments pushed on the stack. (Cf. null_check_receiver).
int nargs = method()->arg_size();
// Callsite signature can be different from actual method being called (i.e _linkTo* sites).
// Use callsite signature always.
ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci());
int nargs = declared_method->arg_size();
kit.inc_sp(nargs);
assert(nargs <= kit.sp() && kit.sp() <= jvms->stk_size(), "sane sp w/ args pushed");
if (_reason == Deoptimization::Reason_class_check &&
......
......@@ -1595,6 +1595,17 @@ void Compile::AliasType::Init(int i, const TypePtr* at) {
}
}
BasicType Compile::AliasType::basic_type() const {
if (element() != NULL) {
const Type* element = adr_type()->is_aryptr()->elem();
return element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type();
} if (field() != NULL) {
return field()->layout_type();
} else {
return T_ILLEGAL; // unknown
}
}
//---------------------------------print_on------------------------------------
#ifndef PRODUCT
void Compile::AliasType::print_on(outputStream* st) {
......
......@@ -152,6 +152,8 @@ class Compile : public Phase {
_element = e;
}
BasicType basic_type() const;
void print_on(outputStream* st) PRODUCT_RETURN;
};
......
......@@ -1452,7 +1452,11 @@ void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
// factory methods in "int adr_idx"
Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
int adr_idx,
MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) {
MemNode::MemOrd mo,
LoadNode::ControlDependency control_dependency,
bool require_atomic_access,
bool unaligned,
bool mismatched) {
assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" );
const TypePtr* adr_type = NULL; // debug-mode-only argument
debug_only(adr_type = C->get_adr_type(adr_idx));
......@@ -1465,6 +1469,12 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
} else {
ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency);
}
if (unaligned) {
ld->as_Load()->set_unaligned_access();
}
if (mismatched) {
ld->as_Load()->set_mismatched_access();
}
ld = _gvn.transform(ld);
if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
// Improve graph before escape analysis and boxing elimination.
......@@ -1476,7 +1486,9 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
int adr_idx,
MemNode::MemOrd mo,
bool require_atomic_access) {
bool require_atomic_access,
bool unaligned,
bool mismatched) {
assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
const TypePtr* adr_type = NULL;
debug_only(adr_type = C->get_adr_type(adr_idx));
......@@ -1489,6 +1501,12 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
} else {
st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo);
}
if (unaligned) {
st->as_Store()->set_unaligned_access();
}
if (mismatched) {
st->as_Store()->set_mismatched_access();
}
st = _gvn.transform(st);
set_memory(st, adr_idx);
// Back-to-back stores can only remove intermediate store with DU info
......@@ -1588,7 +1606,8 @@ Node* GraphKit::store_oop(Node* ctl,
const TypeOopPtr* val_type,
BasicType bt,
bool use_precise,
MemNode::MemOrd mo) {
MemNode::MemOrd mo,
bool mismatched) {
// Transformation of a value which could be NULL pointer (CastPP #NULL)
// could be delayed during Parse (for example, in adjust_map_after_if()).
// Execute transformation here to avoid barrier generation in such case.
......@@ -1608,7 +1627,7 @@ Node* GraphKit::store_oop(Node* ctl,
NULL /* pre_val */,
bt);
Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo);
Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo, mismatched);
post_barrier(control(), store, obj, adr, adr_idx, val, bt, use_precise);
return store;
}
......@@ -1620,7 +1639,8 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl,
const TypePtr* adr_type,
Node* val,
BasicType bt,
MemNode::MemOrd mo) {
MemNode::MemOrd mo,
bool mismatched) {
Compile::AliasType* at = C->alias_type(adr_type);
const TypeOopPtr* val_type = NULL;
if (adr_type->isa_instptr()) {
......@@ -1639,7 +1659,7 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl,
if (val_type == NULL) {
val_type = TypeInstPtr::BOTTOM;
}
return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo);
return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo, mismatched);
}
......
......@@ -517,23 +517,28 @@ class GraphKit : public Phase {
// of volatile fields.
Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest,
bool require_atomic_access = false) {
bool require_atomic_access = false, bool unaligned = false,
bool mismatched = false) {
// This version computes alias_index from bottom_type
return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(),
mo, control_dependency, require_atomic_access);
mo, control_dependency, require_atomic_access,
unaligned, mismatched);
}
Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type,
MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest,
bool require_atomic_access = false) {
bool require_atomic_access = false, bool unaligned = false,
bool mismatched = false) {
// This version computes alias_index from an address type
assert(adr_type != NULL, "use other make_load factory");
return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type),
mo, control_dependency, require_atomic_access);
mo, control_dependency, require_atomic_access,
unaligned, mismatched);
}
// This is the base version which is given an alias index.
Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx,
MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest,
bool require_atomic_access = false);
bool require_atomic_access = false, bool unaligned = false,
bool mismatched = false);
// Create & transform a StoreNode and store the effect into the
// parser's memory state.
......@@ -546,19 +551,24 @@ class GraphKit : public Phase {
Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt,
const TypePtr* adr_type,
MemNode::MemOrd mo,
bool require_atomic_access = false) {
bool require_atomic_access = false,
bool unaligned = false,
bool mismatched = false) {
// This version computes alias_index from an address type
assert(adr_type != NULL, "use other store_to_memory factory");
return store_to_memory(ctl, adr, val, bt,
C->get_alias_index(adr_type),
mo, require_atomic_access);
mo, require_atomic_access,
unaligned, mismatched);
}
// This is the base version which is given alias index
// Return the new StoreXNode
Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt,
int adr_idx,
MemNode::MemOrd,
bool require_atomic_access = false);
bool require_atomic_access = false,
bool unaligned = false,
bool mismatched = false);
// All in one pre-barrier, store, post_barrier
......@@ -581,7 +591,8 @@ class GraphKit : public Phase {
const TypeOopPtr* val_type,
BasicType bt,
bool use_precise,
MemNode::MemOrd mo);
MemNode::MemOrd mo,
bool mismatched = false);
Node* store_oop_to_object(Node* ctl,
Node* obj, // containing obj
......@@ -612,7 +623,8 @@ class GraphKit : public Phase {
const TypePtr* adr_type,
Node* val,
BasicType bt,
MemNode::MemOrd mo);
MemNode::MemOrd mo,
bool mismatched = false);
// For the few case where the barriers need special help
void pre_barrier(bool do_load, Node* ctl,
......@@ -656,7 +668,10 @@ class GraphKit : public Phase {
// callee (with all arguments still on the stack).
Node* null_check_receiver_before_call(ciMethod* callee) {
assert(!callee->is_static(), "must be a virtual method");
const int nargs = callee->arg_size();
// Callsite signature can be different from actual method being called (i.e _linkTo* sites).
// Use callsite signature always.
ciMethod* declared_method = method()->get_method_at_bci(bci());
const int nargs = declared_method->arg_size();
inc_sp(nargs);
Node* n = null_check_receiver();
dec_sp(nargs);
......
......@@ -368,7 +368,8 @@ Node* IdealKit::load(Node* ctl,
Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt,
int adr_idx,
MemNode::MemOrd mo, bool require_atomic_access) {
MemNode::MemOrd mo, bool require_atomic_access,
bool mismatched) {
assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory");
const TypePtr* adr_type = NULL;
debug_only(adr_type = C->get_adr_type(adr_idx));
......@@ -379,6 +380,9 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt,
} else {
st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo);
}
if (mismatched) {
st->as_Store()->set_mismatched_access();
}
st = transform(st);
set_memory(st, adr_idx);
......
......@@ -227,7 +227,9 @@ class IdealKit: public StackObj {
BasicType bt,
int adr_idx,
MemNode::MemOrd mo,
bool require_atomic_access = false);
bool require_atomic_access = false,
bool mismatched = false
);
// Store a card mark ordered after store_oop
Node* storeCM(Node* ctl,
......
此差异已折叠。
......@@ -67,8 +67,15 @@ void MemNode::dump_spec(outputStream *st) const {
dump_adr_type(this, _adr_type, st);
Compile* C = Compile::current();
if( C->alias_type(_adr_type)->is_volatile() )
if (C->alias_type(_adr_type)->is_volatile()) {
st->print(" Volatile!");
}
if (_unaligned_access) {
st->print(" unaligned");
}
if (_mismatched_access) {
st->print(" mismatched");
}
}
void MemNode::dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st) {
......@@ -3322,6 +3329,9 @@ bool InitializeNode::detect_init_independence(Node* n, int& count) {
// within the initialized memory.
intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase, bool can_reshape) {
const int FAIL = 0;
if (st->is_unaligned_access()) {
return FAIL;
}
if (st->req() != MemNode::ValueIn + 1)
return FAIL; // an inscrutable StoreNode (card mark?)
Node* ctl = st->in(MemNode::Control);
......
......@@ -39,11 +39,14 @@ class PhaseTransform;
//------------------------------MemNode----------------------------------------
// Load or Store, possibly throwing a NULL pointer exception
class MemNode : public Node {
private:
bool _unaligned_access; // Unaligned access from unsafe
bool _mismatched_access; // Mismatched access from unsafe: byte read in integer array for instance
protected:
#ifdef ASSERT
const TypePtr* _adr_type; // What kind of memory is being addressed?
#endif
virtual uint size_of() const; // Size is bigger (ASSERT only)
virtual uint size_of() const;
public:
enum { Control, // When is it safe to do this load?
Memory, // Chunk of memory is being loaded from
......@@ -57,17 +60,17 @@ public:
} MemOrd;
protected:
MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at )
: Node(c0,c1,c2 ) {
: Node(c0,c1,c2 ), _unaligned_access(false), _mismatched_access(false) {
init_class_id(Class_Mem);
debug_only(_adr_type=at; adr_type();)
}
MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3 )
: Node(c0,c1,c2,c3) {
: Node(c0,c1,c2,c3), _unaligned_access(false), _mismatched_access(false) {
init_class_id(Class_Mem);
debug_only(_adr_type=at; adr_type();)
}
MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3, Node *c4)
: Node(c0,c1,c2,c3,c4) {
: Node(c0,c1,c2,c3,c4), _unaligned_access(false), _mismatched_access(false) {
init_class_id(Class_Mem);
debug_only(_adr_type=at; adr_type();)
}
......@@ -129,6 +132,11 @@ public:
// the given memory state? (The state may or may not be in(Memory).)
Node* can_see_stored_value(Node* st, PhaseTransform* phase) const;
void set_unaligned_access() { _unaligned_access = true; }
bool is_unaligned_access() const { return _unaligned_access; }
void set_mismatched_access() { _mismatched_access = true; }
bool is_mismatched_access() const { return _mismatched_access; }
#ifndef PRODUCT
static void dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st);
virtual void dump_spec(outputStream *st) const;
......
......@@ -209,11 +209,11 @@ public:
static int cmp( const Type *const t1, const Type *const t2 );
// Test for higher or equal in lattice
// Variant that drops the speculative part of the types
int higher_equal(const Type *t) const {
bool higher_equal(const Type *t) const {
return !cmp(meet(t),t->remove_speculative());
}
// Variant that keeps the speculative part of the types
int higher_equal_speculative(const Type *t) const {
bool higher_equal_speculative(const Type *t) const {
return !cmp(meet_speculative(t),t);
}
......
......@@ -106,6 +106,7 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
bool is_field_access_watched() const { return access_flags().is_field_access_watched(); }
bool is_field_modification_watched() const
{ return access_flags().is_field_modification_watched(); }
bool has_initialized_final_update() const { return access_flags().has_field_initialized_final_update(); }
bool has_generic_signature() const { return access_flags().field_has_generic_signature(); }
void set_is_field_access_watched(const bool value) {
......@@ -118,6 +119,11 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
update_klass_field_access_flag();
}
void set_has_initialized_final_update(const bool value) {
_access_flags.set_has_field_initialized_final_update(value);
update_klass_field_access_flag();
}
// Initialization
void reinitialize(InstanceKlass* ik, int index);
......
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, 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
......@@ -78,6 +78,7 @@ volatile int32_t* os::_mem_serialize_page = NULL;
uintptr_t os::_serialize_page_mask = 0;
long os::_rand_seed = 1;
int os::_processor_count = 0;
int os::_initial_active_processor_count = 0;
size_t os::_page_sizes[os::page_sizes_max];
#ifndef PRODUCT
......@@ -322,6 +323,7 @@ static void signal_thread_entry(JavaThread* thread, TRAPS) {
}
void os::init_before_ergo() {
initialize_initial_active_processor_count();
// We need to initialize large page support here because ergonomics takes some
// decisions depending on large page support and the calculated large page size.
large_page_init();
......@@ -835,7 +837,11 @@ void os::print_cpu_info(outputStream* st) {
st->print("CPU:");
st->print("total %d", os::processor_count());
// It's not safe to query number of active processors after crash
// st->print("(active %d)", os::active_processor_count());
// st->print("(active %d)", os::active_processor_count()); but we can
// print the initial number of active processors.
// We access the raw value here because the assert in the accessor will
// fail if the crash occurs before initialization of this value.
st->print(" (initial active %d)", _initial_active_processor_count);
st->print(" %s", VM_Version::cpu_features());
st->cr();
pd_print_cpu_info(st);
......@@ -1418,6 +1424,11 @@ bool os::is_server_class_machine() {
return result;
}
void os::initialize_initial_active_processor_count() {
assert(_initial_active_processor_count == 0, "Initial active processor count already set.");
_initial_active_processor_count = active_processor_count();
}
void os::SuspendedThreadTask::run() {
assert(Threads_lock->owned_by_self() || (_thread == VMThread::vm_thread()), "must have threads lock to call this");
internal_do_task();
......
......@@ -151,6 +151,7 @@ class os: AllStatic {
static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned);
static void initialize_initial_active_processor_count();
public:
static void init(void); // Called before command line parsing
static void init_before_ergo(void); // Called after command line parsing
......@@ -238,6 +239,13 @@ class os: AllStatic {
// Note that on some OSes this can change dynamically.
static int active_processor_count();
// At startup the number of active CPUs this process is allowed to run on.
// This value does not change dynamically. May be different from active_processor_count().
static int initial_active_processor_count() {
assert(_initial_active_processor_count > 0, "Initial active processor count not set yet.");
return _initial_active_processor_count;
}
// Bind processes to processors.
// This is a two step procedure:
// first you generate a distribution of processes to processors,
......@@ -975,8 +983,9 @@ class os: AllStatic {
protected:
static long _rand_seed; // seed for random number generator
static int _processor_count; // number of processors
static long _rand_seed; // seed for random number generator
static int _processor_count; // number of processors
static int _initial_active_processor_count; // number of active processors during initialization.
static char* format_boot_path(const char* format_string,
const char* home,
......
/*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2016, 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
......@@ -296,7 +296,7 @@ unsigned int Abstract_VM_Version::nof_parallel_worker_threads(
// processor after the first 8. For example, on a 72 cpu machine
// and a chosen fraction of 5/8
// use 8 + (72 - 8) * (5/8) == 48 worker threads.
unsigned int ncpus = (unsigned int) os::active_processor_count();
unsigned int ncpus = (unsigned int) os::initial_active_processor_count();
return (ncpus <= switch_pt) ?
ncpus :
(switch_pt + ((ncpus - switch_pt) * num) / den);
......
/*
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2016, 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
......@@ -271,13 +271,17 @@ static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* o
// set a uintx global flag using value from AttachOperation
static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
uintx value;
const char* arg1;
if ((arg1 = op->arg(1)) != NULL) {
int n = sscanf(arg1, UINTX_FORMAT, &value);
if (n != 1) {
out->print_cr("flag value must be an unsigned integer");
return JNI_ERR;
}
const char* arg1 = op->arg(1);
if (arg1 == NULL) {
out->print_cr("flag value must be specified");
return JNI_ERR;
}
int n = sscanf(arg1, UINTX_FORMAT, &value);
if (n != 1) {
out->print_cr("flag value must be an unsigned integer");
return JNI_ERR;
}
if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) {
......
......@@ -76,11 +76,12 @@ enum {
// These bits must not conflict with any other field-related access flags
// (e.g., ACC_ENUM).
// Note that the class-related ACC_ANNOTATION bit conflicts with these flags.
JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT
JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED
JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT
JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED and JVM_ACC_SUPER
JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE = 0x00000100, // (static) final field updated outside (class) initializer, same as JVM_ACC_NATIVE
JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED |
JVM_ACC_FIELD_MODIFICATION_WATCHED |
......@@ -150,6 +151,8 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; }
bool is_field_modification_watched() const
{ return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
bool has_field_initialized_final_update() const
{ return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; }
bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; }
bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
......@@ -229,6 +232,15 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED);
}
}
void set_has_field_initialized_final_update(const bool value) {
if (value) {
atomic_set_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE);
} else {
atomic_clear_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE);
}
}
void set_field_has_generic_signature()
{
atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);
......
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
......@@ -23,8 +23,11 @@
/**
* @test
* @bug 8059556
* @bug 8059556 8158639 8164508
*
* @run main/othervm -Xbatch NullConstantReceiver
* @run main/othervm -Xbatch -XX:CompileCommand=exclude,*::run NullConstantReceiver
* @run main/othervm -Xbatch -XX:CompileCommand=compileonly,*::run NullConstantReceiver
*/
import java.lang.invoke.MethodHandle;
......
/*
* Copyright (c) 2016, 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 8134918
* @modules java.base/jdk.internal.misc
* @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:TypeProfileLevel=222 -XX:+UseTypeSpeculation -Xbatch
* -XX:CompileCommand=dontinline,UnsafeAccess::test*
* UnsafeAccess
*/
import sun.misc.Unsafe;
public class UnsafeAccess {
private static final Unsafe U = Unsafe.getUnsafe();
static Class cls = Object.class;
static long off = U.ARRAY_OBJECT_BASE_OFFSET;
static Object testUnsafeAccess(Object o, boolean isObjArray) {
if (o != null && cls.isInstance(o)) { // speculates "o" type to int[]
return helperUnsafeAccess(o, isObjArray);
}
return null;
}
static Object helperUnsafeAccess(Object o, boolean isObjArray) {
if (isObjArray) {
U.putObject(o, off, new Object());
}
return o;
}
static Object testUnsafeLoadStore(Object o, boolean isObjArray) {
if (o != null && cls.isInstance(o)) { // speculates "o" type to int[]
return helperUnsafeLoadStore(o, isObjArray);
}
return null;
}
static Object helperUnsafeLoadStore(Object o, boolean isObjArray) {
if (isObjArray) {
Object o1 = U.getObject(o, off);
U.compareAndSwapObject(o, off, o1, new Object());
}
return o;
}
public static void main(String[] args) {
Object[] objArray = new Object[10];
int[] intArray = new int[10];
for (int i = 0; i < 20_000; i++) {
helperUnsafeAccess(objArray, true);
}
for (int i = 0; i < 20_000; i++) {
testUnsafeAccess(intArray, false);
}
for (int i = 0; i < 20_000; i++) {
helperUnsafeLoadStore(objArray, true);
}
for (int i = 0; i < 20_000; i++) {
testUnsafeLoadStore(intArray, false);
}
System.out.println("TEST PASSED");
}
}
/*
* Copyright (c) 2016, 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
* @bug 8155781
* @modules java.base/jdk.internal.misc
*
* @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
* -XX:-TieredCompilation -Xbatch
* -XX:+UseCompressedOops -XX:+UseCompressedClassPointers
* -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*
* compiler.unsafe.OpaqueAccesses
* @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
* -XX:-TieredCompilation -Xbatch
* -XX:+UseCompressedOops -XX:-UseCompressedClassPointers
* -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*
* compiler.unsafe.OpaqueAccesses
* @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
* -XX:-TieredCompilation -Xbatch
* -XX:-UseCompressedOops -XX:+UseCompressedClassPointers
* -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*
* compiler.unsafe.OpaqueAccesses
* @run main/bootclasspath/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
* -XX:-TieredCompilation -Xbatch
* -XX:-UseCompressedOops -XX:-UseCompressedClassPointers
* -XX:CompileCommand=dontinline,compiler.unsafe.OpaqueAccesses::test*
* compiler.unsafe.OpaqueAccesses
*/
package compiler.unsafe;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class OpaqueAccesses {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
private static final Object INSTANCE = new OpaqueAccesses();
private static final Object[] ARRAY = new Object[10];
private static final long F_OFFSET;
private static final long E_OFFSET;
static {
try {
Field field = OpaqueAccesses.class.getDeclaredField("f");
F_OFFSET = UNSAFE.objectFieldOffset(field);
E_OFFSET = UNSAFE.arrayBaseOffset(ARRAY.getClass());
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
private Object f = new Object();
private long l1, l2;
static Object testFixedOffsetField(Object o) {
return UNSAFE.getObject(o, F_OFFSET);
}
static int testFixedOffsetHeader0(Object o) {
return UNSAFE.getInt(o, 0);
}
static int testFixedOffsetHeader4(Object o) {
return UNSAFE.getInt(o, 4);
}
static int testFixedOffsetHeader8(Object o) {
return UNSAFE.getInt(o, 8);
}
static int testFixedOffsetHeader12(Object o) {
return UNSAFE.getInt(o, 12);
}
static int testFixedOffsetHeader16(Object o) {
return UNSAFE.getInt(o, 16);
}
static Object testFixedBase(long off) {
return UNSAFE.getObject(INSTANCE, off);
}
static Object testOpaque(Object o, long off) {
return UNSAFE.getObject(o, off);
}
static int testFixedOffsetHeaderArray0(Object[] arr) {
return UNSAFE.getInt(arr, 0);
}
static int testFixedOffsetHeaderArray4(Object[] arr) {
return UNSAFE.getInt(arr, 4);
}
static int testFixedOffsetHeaderArray8(Object[] arr) {
return UNSAFE.getInt(arr, 8);
}
static int testFixedOffsetHeaderArray12(Object[] arr) {
return UNSAFE.getInt(arr, 12);
}
static int testFixedOffsetHeaderArray16(Object[] arr) {
return UNSAFE.getInt(arr, 16);
}
static Object testFixedOffsetArray(Object[] arr) {
return UNSAFE.getObject(arr, E_OFFSET);
}
static Object testFixedBaseArray(long off) {
return UNSAFE.getObject(ARRAY, off);
}
static Object testOpaqueArray(Object[] o, long off) {
return UNSAFE.getObject(o, off);
}
static final long ADDR = UNSAFE.allocateMemory(10);
static boolean flag;
static int testMixedAccess() {
flag = !flag;
Object o = (flag ? INSTANCE : null);
long off = (flag ? F_OFFSET : ADDR);
return UNSAFE.getInt(o, off);
}
public static void main(String[] args) {
for (int i = 0; i < 20_000; i++) {
// Instance
testFixedOffsetField(INSTANCE);
testFixedOffsetHeader0(INSTANCE);
testFixedOffsetHeader4(INSTANCE);
testFixedOffsetHeader8(INSTANCE);
testFixedOffsetHeader12(INSTANCE);
testFixedOffsetHeader16(INSTANCE);
testFixedBase(F_OFFSET);
testOpaque(INSTANCE, F_OFFSET);
testMixedAccess();
// Array
testFixedOffsetHeaderArray0(ARRAY);
testFixedOffsetHeaderArray4(ARRAY);
testFixedOffsetHeaderArray8(ARRAY);
testFixedOffsetHeaderArray12(ARRAY);
testFixedOffsetHeaderArray16(ARRAY);
testFixedOffsetArray(ARRAY);
testFixedBaseArray(E_OFFSET);
testOpaqueArray(ARRAY, E_OFFSET);
}
System.out.println("TEST PASSED");
}
}
/*
* Copyright (c) 2016, 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.
*/
/* Recoded in jasm to provoke an ICCE assigning a non-static final field with putstatic.
class Bad {
public static final int i; //rewritten
//rewritten to: public final int i;
static { i = 5; } // putstatic instruction
}
*/
super class Bad
version 53:0
{
// Remove 'static' keyword
public final Field i:I;
Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
static Method "<clinit>":"()V"
stack 1 locals 0
{
iconst_5;
putstatic Field i:"I";
return;
}
} // end Class Bad
/*
* Copyright (c) 2016, 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 PutfieldError
* @bug 8160551
* @summary Throw ICCE rather than crashing for nonstatic final field in static initializer
* @compile Bad.jasm
* @run main PutfieldError
*/
public class PutfieldError {
public static void main(java.lang.String[] unused) {
try {
Bad b = new Bad();
System.out.println("Bad.i = " + 5);
throw new RuntimeException("ICCE NOT thrown as expected");
} catch (IncompatibleClassChangeError icce) {
System.out.println("ICCE thrown as expected");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册