Merge
This commit is contained in:
commit
1b03f22dff
@ -387,7 +387,7 @@ else # $(HAS_SPEC)=true
|
||||
fi
|
||||
# Re-run configure with the same arguments (and possibly some additional),
|
||||
# must be done after patching.
|
||||
( cd $(OUTPUTDIR) && PATH="$(ORIGINAL_PATH)" \
|
||||
( cd $(CONFIGURE_START_DIR) && PATH="$(ORIGINAL_PATH)" \
|
||||
$(BASH) $(topdir)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
|
||||
endef
|
||||
|
||||
|
@ -219,7 +219,7 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
|
||||
-Wunused-function -Wundef -Wunused-value -Woverloaded-virtual"
|
||||
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL"
|
||||
|
||||
DISABLED_WARNINGS="unused-parameter unused"
|
||||
DISABLED_WARNINGS="unknown-warning-option unused-parameter unused"
|
||||
|
||||
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
|
||||
# missing-method-return-type triggers in JavaNativeFoundation framework
|
||||
|
@ -76,7 +76,8 @@ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \
|
||||
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \
|
||||
undef, \
|
||||
DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang) \
|
||||
undef switch format-nonliteral tautological-undefined-compare, \
|
||||
undef switch format-nonliteral tautological-undefined-compare \
|
||||
self-assign-overloaded, \
|
||||
DISABLED_WARNINGS_solstudio := $(DISABLED_WARNINGS_solstudio) \
|
||||
identexpected, \
|
||||
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@ -346,17 +346,26 @@ public class CLDRConverter {
|
||||
if (sb.indexOf("root") == -1) {
|
||||
sb.append("root");
|
||||
}
|
||||
Bundle b = new Bundle(id, sb.toString(), null, null);
|
||||
// Insert the bundle for root at the top so that it will get
|
||||
// processed first.
|
||||
if ("root".equals(id)) {
|
||||
retList.add(0, b);
|
||||
} else {
|
||||
retList.add(b);
|
||||
}
|
||||
retList.add(new Bundle(id, sb.toString(), null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the bundles based on id. This will make sure all the parent bundles are
|
||||
// processed first, e.g., for en_GB bundle, en_001, and "root" comes before
|
||||
// en_GB. In order for "root" to come at the beginning, "root" is replaced with
|
||||
// empty string on comparison.
|
||||
retList.sort((o1, o2) -> {
|
||||
String id1 = o1.getID();
|
||||
String id2 = o2.getID();
|
||||
if(id1.equals("root")) {
|
||||
id1 = "";
|
||||
}
|
||||
if(id2.equals("root")) {
|
||||
id2 = "";
|
||||
}
|
||||
return id1.compareTo(id2);
|
||||
});
|
||||
return retList;
|
||||
}
|
||||
|
||||
|
@ -46,12 +46,14 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
|
||||
// Apply storeval barrier to newval.
|
||||
ShenandoahBarrierSet::assembler()->storeval_barrier(masm->masm(), newval, tmp1);
|
||||
|
||||
#ifdef _LP64
|
||||
if (UseCompressedOops) {
|
||||
__ encode_heap_oop(cmpval);
|
||||
__ mov(rscratch1, newval);
|
||||
__ encode_heap_oop(rscratch1);
|
||||
newval = rscratch1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), result, Address(addr, 0), cmpval, newval, false, tmp1, tmp2);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2014 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2012, 2019 SAP SE. 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
|
||||
@ -65,9 +65,7 @@
|
||||
#define inlasm_eieio() __asm__ __volatile__ ("eieio" : : : "memory");
|
||||
#define inlasm_isync() __asm__ __volatile__ ("isync" : : : "memory");
|
||||
// Use twi-isync for load_acquire (faster than lwsync).
|
||||
// ATTENTION: seems like xlC 10.1 has problems with this inline assembler macro (VerifyMethodHandles found "bad vminfo in AMH.conv"):
|
||||
// #define inlasm_acquire_reg(X) __asm__ __volatile__ ("twi 0,%0,0\n isync\n" : : "r" (X) : "memory");
|
||||
#define inlasm_acquire_reg(X) inlasm_lwsync();
|
||||
#define inlasm_acquire_reg(X) __asm__ __volatile__ ("twi 0,%0,0\n isync\n" : : "r" (X) : "memory");
|
||||
|
||||
inline void OrderAccess::loadload() { inlasm_lwsync(); }
|
||||
inline void OrderAccess::storestore() { inlasm_lwsync(); }
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019 SAP SE. 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
|
||||
@ -302,7 +302,6 @@ JVM_handle_linux_signal(int sig,
|
||||
address stub = NULL;
|
||||
address pc = NULL;
|
||||
|
||||
//%note os_trap_1
|
||||
if (info != NULL && uc != NULL && thread != NULL) {
|
||||
pc = (address) os::Linux::ucontext_get_pc(uc);
|
||||
|
||||
@ -311,17 +310,17 @@ JVM_handle_linux_signal(int sig,
|
||||
// si_addr may not be valid due to a bug in the linux-ppc64 kernel (see
|
||||
// comment below). Use get_stack_bang_address instead of si_addr.
|
||||
// If SIGSEGV is caused due to a branch to an invalid address an
|
||||
// "Instruction Storage" interruption is generated and 'pc' (NIP) already
|
||||
// "Instruction Storage Interrupt" is generated and 'pc' (NIP) already
|
||||
// contains the invalid address. Otherwise, the SIGSEGV is caused due to
|
||||
// load/store instruction trying to load/store from/to an invalid address
|
||||
// and causing a "Data Storage" interruption, so we inspect the intruction
|
||||
// and causing a "Data Storage Interrupt", so we inspect the intruction
|
||||
// in order to extract the faulty data addresss.
|
||||
address addr;
|
||||
if ((ucontext_get_trap(uc) & 0x0F00 /* no IRQ reply bits */) == 0x0400) {
|
||||
// Instruction interruption
|
||||
// Instruction Storage Interrupt (ISI)
|
||||
addr = pc;
|
||||
} else {
|
||||
// Data interruption (0x0300): extract faulty data address
|
||||
// Data Storage Interrupt (DSI), i.e. 0x0300: extract faulty data address
|
||||
addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc);
|
||||
}
|
||||
|
||||
|
@ -1988,8 +1988,9 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
}
|
||||
|
||||
if (cha_monomorphic_target != NULL) {
|
||||
assert(!target->can_be_statically_bound() || target == cha_monomorphic_target, "");
|
||||
assert(!cha_monomorphic_target->is_abstract(), "");
|
||||
if (!target->is_final_method() && !target->is_private()) {
|
||||
if (!cha_monomorphic_target->can_be_statically_bound(actual_recv)) {
|
||||
// If we inlined because CHA revealed only a single target method,
|
||||
// then we are dependent on that target method not getting overridden
|
||||
// by dynamic class loading. Be sure to test the "static" receiver
|
||||
|
@ -764,6 +764,14 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
|
||||
return CURRENT_THREAD_ENV->get_method(target());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::can_be_statically_bound
|
||||
//
|
||||
// Tries to determine whether a method can be statically bound in some context.
|
||||
bool ciMethod::can_be_statically_bound(ciInstanceKlass* context) const {
|
||||
return (holder() == context) && can_be_statically_bound();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciMethod::resolve_invoke
|
||||
//
|
||||
|
@ -352,6 +352,8 @@ class ciMethod : public ciMetadata {
|
||||
bool is_unboxing_method() const;
|
||||
bool is_object_initializer() const;
|
||||
|
||||
bool can_be_statically_bound(ciInstanceKlass* context) const;
|
||||
|
||||
// Replay data methods
|
||||
void dump_name_as_ascii(outputStream* st);
|
||||
void dump_replay_data(outputStream* st);
|
||||
|
@ -108,6 +108,7 @@ void Dependencies::assert_concrete_with_no_concrete_subtype(ciKlass* ctxk) {
|
||||
|
||||
void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm) {
|
||||
check_ctxk(ctxk);
|
||||
check_unique_method(ctxk, uniqm);
|
||||
assert_common_2(unique_concrete_method, ctxk, uniqm);
|
||||
}
|
||||
|
||||
@ -180,6 +181,7 @@ void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Kla
|
||||
|
||||
void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) {
|
||||
check_ctxk(ctxk);
|
||||
check_unique_method(ctxk, uniqm);
|
||||
assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm));
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "ci/ciCallSite.hpp"
|
||||
#include "ci/ciKlass.hpp"
|
||||
#include "ci/ciMethod.hpp"
|
||||
#include "ci/ciMethodHandle.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/compressedStream.hpp"
|
||||
@ -341,6 +342,9 @@ class Dependencies: public ResourceObj {
|
||||
check_ctxk(ctxk);
|
||||
assert(!is_concrete_klass(ctxk->as_instance_klass()), "must be abstract");
|
||||
}
|
||||
static void check_unique_method(ciKlass* ctxk, ciMethod* m) {
|
||||
assert(!m->can_be_statically_bound(ctxk->as_instance_klass()), "redundant");
|
||||
}
|
||||
|
||||
void assert_common_1(DepType dept, ciBaseObject* x);
|
||||
void assert_common_2(DepType dept, ciBaseObject* x0, ciBaseObject* x1);
|
||||
@ -368,6 +372,11 @@ class Dependencies: public ResourceObj {
|
||||
check_ctxk(ctxk);
|
||||
assert(ctxk->is_abstract(), "must be abstract");
|
||||
}
|
||||
static void check_unique_method(Klass* ctxk, Method* m) {
|
||||
// Graal can register redundant dependencies
|
||||
assert(UseJVMCICompiler || !m->can_be_statically_bound(InstanceKlass::cast(ctxk)), "redundant");
|
||||
}
|
||||
|
||||
void assert_common_1(DepType dept, DepValue x);
|
||||
void assert_common_2(DepType dept, DepValue x0, DepValue x1);
|
||||
|
||||
|
@ -70,7 +70,6 @@
|
||||
#if INCLUDE_JVMCI
|
||||
#include "jvmci/jvmciEnv.hpp"
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
#include "runtime/vframe.hpp"
|
||||
#endif
|
||||
#ifdef COMPILER2
|
||||
#include "opto/c2compiler.hpp"
|
||||
@ -1063,20 +1062,22 @@ void CompileBroker::compile_method_base(const methodHandle& method,
|
||||
}
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (UseJVMCICompiler && blocking && !UseJVMCINativeLibrary) {
|
||||
if (UseJVMCICompiler && blocking) {
|
||||
// Don't allow blocking compiles for requests triggered by JVMCI.
|
||||
if (thread->is_Compiler_thread()) {
|
||||
blocking = false;
|
||||
}
|
||||
|
||||
// Don't allow blocking compiles if inside a class initializer or while performing class loading
|
||||
vframeStream vfst((JavaThread*) thread);
|
||||
for (; !vfst.at_end(); vfst.next()) {
|
||||
if (vfst.method()->is_static_initializer() ||
|
||||
(vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
|
||||
vfst.method()->name() == vmSymbols::loadClass_name())) {
|
||||
blocking = false;
|
||||
break;
|
||||
if (!UseJVMCINativeLibrary) {
|
||||
// Don't allow blocking compiles if inside a class initializer or while performing class loading
|
||||
vframeStream vfst((JavaThread*) thread);
|
||||
for (; !vfst.at_end(); vfst.next()) {
|
||||
if (vfst.method()->is_static_initializer() ||
|
||||
(vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
|
||||
vfst.method()->name() == vmSymbols::loadClass_name())) {
|
||||
blocking = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2063,7 +2064,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
||||
compilable = ciEnv::MethodCompilable_never;
|
||||
} else {
|
||||
JVMCICompileState compile_state(task, system_dictionary_modification_counter);
|
||||
JVMCIEnv env(&compile_state, __FILE__, __LINE__);
|
||||
JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__);
|
||||
methodHandle method(thread, target_handle);
|
||||
env.runtime()->compile_method(&env, jvmci, method, osr_bci);
|
||||
|
||||
|
@ -229,7 +229,6 @@ class CompileBroker: AllStatic {
|
||||
static JavaThread* make_thread(jobject thread_oop, CompileQueue* queue, AbstractCompiler* comp, TRAPS);
|
||||
static void init_compiler_sweeper_threads();
|
||||
static void possibly_add_compiler_threads();
|
||||
static bool compilation_is_complete (const methodHandle& method, int osr_bci, int comp_level);
|
||||
static bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded);
|
||||
static void preload_classes (const methodHandle& method, TRAPS);
|
||||
|
||||
@ -285,6 +284,7 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool compilation_is_complete(const methodHandle& method, int osr_bci, int comp_level);
|
||||
static bool compilation_is_in_queue(const methodHandle& method);
|
||||
static void print_compile_queues(outputStream* st);
|
||||
static void print_directives(outputStream* st);
|
||||
|
@ -1036,7 +1036,7 @@ void G1CollectedHeap::prepare_heap_for_full_collection() {
|
||||
|
||||
void G1CollectedHeap::verify_before_full_collection(bool explicit_gc) {
|
||||
assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant");
|
||||
assert(used() == recalculate_used(), "Should be equal");
|
||||
assert_used_and_recalculate_used_equal(this);
|
||||
_verifier->verify_region_sets_optional();
|
||||
_verifier->verify_before_gc(G1HeapVerifier::G1VerifyFull);
|
||||
_verifier->check_bitmaps("Full GC Start");
|
||||
@ -1092,7 +1092,7 @@ void G1CollectedHeap::verify_after_full_collection() {
|
||||
// the full GC has compacted objects and updated TAMS but not updated
|
||||
// the prev bitmap.
|
||||
if (G1VerifyBitmaps) {
|
||||
GCTraceTime(Debug, gc)("Clear Prev Bitmap for Verification");
|
||||
GCTraceTime(Debug, gc) tm("Clear Prev Bitmap for Verification");
|
||||
_cm->clear_prev_bitmap(workers());
|
||||
}
|
||||
// This call implicitly verifies that the next bitmap is clear after Full GC.
|
||||
@ -4539,9 +4539,7 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
|
||||
_archive_allocator->clear_used();
|
||||
}
|
||||
}
|
||||
assert(used() == recalculate_used(),
|
||||
"inconsistent used(), value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT,
|
||||
used(), recalculate_used());
|
||||
assert_used_and_recalculate_used_equal(this);
|
||||
}
|
||||
|
||||
// Methods for the mutator alloc region
|
||||
|
@ -354,6 +354,15 @@ private:
|
||||
assert(Thread::current()->is_VM_thread(), "current thread is not VM thread"); \
|
||||
} while (0)
|
||||
|
||||
#define assert_used_and_recalculate_used_equal(g1h) \
|
||||
do { \
|
||||
size_t cur_used_bytes = g1h->used(); \
|
||||
size_t recal_used_bytes = g1h->recalculate_used(); \
|
||||
assert(cur_used_bytes == recal_used_bytes, "Used(" SIZE_FORMAT ") is not" \
|
||||
" same as recalculated used(" SIZE_FORMAT ").", \
|
||||
cur_used_bytes, recal_used_bytes); \
|
||||
} while (0)
|
||||
|
||||
const char* young_gc_name() const;
|
||||
|
||||
// The young region list.
|
||||
|
@ -289,6 +289,6 @@ void G1FullCollector::verify_after_marking() {
|
||||
// fail. At the end of the GC, the original mark word values
|
||||
// (including hash values) are restored to the appropriate
|
||||
// objects.
|
||||
GCTraceTime(Info, gc, verify)("Verifying During GC (full)");
|
||||
GCTraceTime(Info, gc, verify) tm("Verifying During GC (full)");
|
||||
_heap->verify(VerifyOption_G1UseFullMarking);
|
||||
}
|
||||
|
@ -65,7 +65,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
_gc_par_phases[CMRefRoots] = new WorkerDataArray<double>(max_gc_threads, "CM RefProcessor Roots (ms):");
|
||||
_gc_par_phases[WaitForStrongCLD] = new WorkerDataArray<double>(max_gc_threads, "Wait For Strong CLD (ms):");
|
||||
_gc_par_phases[WeakCLDRoots] = new WorkerDataArray<double>(max_gc_threads, "Weak CLD Roots (ms):");
|
||||
_gc_par_phases[SATBFiltering] = new WorkerDataArray<double>(max_gc_threads, "SATB Filtering (ms):");
|
||||
|
||||
_gc_par_phases[UpdateRS] = new WorkerDataArray<double>(max_gc_threads, "Update RS (ms):");
|
||||
if (G1HotCardCache::default_use_cache()) {
|
||||
@ -406,7 +405,7 @@ double G1GCPhaseTimes::print_evacuate_collection_set() const {
|
||||
|
||||
trace_phase(_gc_par_phases[GCWorkerStart], false);
|
||||
debug_phase(_gc_par_phases[ExtRootScan]);
|
||||
for (int i = ExtRootScanSubPhasesStart; i <= ExtRootScanSubPhasesEnd; i++) {
|
||||
for (int i = ExtRootScanSubPhasesFirst; i <= ExtRootScanSubPhasesLast; i++) {
|
||||
trace_phase(_gc_par_phases[i]);
|
||||
}
|
||||
if (G1HotCardCache::default_use_cache()) {
|
||||
@ -531,7 +530,6 @@ const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
|
||||
"CMRefRoots",
|
||||
"WaitForStrongCLD",
|
||||
"WeakCLDRoots",
|
||||
"SATBFiltering",
|
||||
"UpdateRS",
|
||||
"ScanHCC",
|
||||
"ScanRS",
|
||||
|
@ -60,7 +60,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
CMRefRoots,
|
||||
WaitForStrongCLD,
|
||||
WeakCLDRoots,
|
||||
SATBFiltering,
|
||||
UpdateRS,
|
||||
ScanHCC,
|
||||
ScanRS,
|
||||
@ -82,8 +81,8 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
GCParPhasesSentinel
|
||||
};
|
||||
|
||||
static const GCParPhases ExtRootScanSubPhasesStart = ThreadRoots;
|
||||
static const GCParPhases ExtRootScanSubPhasesEnd = SATBFiltering;
|
||||
static const GCParPhases ExtRootScanSubPhasesFirst = ThreadRoots;
|
||||
static const GCParPhases ExtRootScanSubPhasesLast = WeakCLDRoots;
|
||||
|
||||
enum GCScanRSWorkItems {
|
||||
ScanRSScannedCards,
|
||||
|
@ -487,10 +487,7 @@ void G1Policy::record_collection_pause_start(double start_time_sec) {
|
||||
assert(max_survivor_regions() + _g1h->num_used_regions() <= _g1h->max_regions(),
|
||||
"Maximum survivor regions %u plus used regions %u exceeds max regions %u",
|
||||
max_survivor_regions(), _g1h->num_used_regions(), _g1h->max_regions());
|
||||
|
||||
assert(_g1h->used() == _g1h->recalculate_used(),
|
||||
"sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT,
|
||||
_g1h->used(), _g1h->recalculate_used());
|
||||
assert_used_and_recalculate_used_equal(_g1h);
|
||||
|
||||
phase_times()->record_cur_collection_start_sec(start_time_sec);
|
||||
_pending_cards = _g1h->pending_card_num();
|
||||
@ -581,8 +578,8 @@ bool G1Policy::need_to_start_conc_mark(const char* source, size_t alloc_word_siz
|
||||
void G1Policy::record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc) {
|
||||
double end_time_sec = os::elapsedTime();
|
||||
|
||||
assert_used_and_recalculate_used_equal(_g1h);
|
||||
size_t cur_used_bytes = _g1h->used();
|
||||
assert(cur_used_bytes == _g1h->recalculate_used(), "It should!");
|
||||
bool this_pause_included_initial_mark = false;
|
||||
bool this_pause_was_young_only = collector_state()->in_young_only_phase();
|
||||
|
||||
|
@ -122,16 +122,6 @@ void G1RootProcessor::evacuate_roots(G1ParScanThreadState* pss, uint worker_i) {
|
||||
assert(closures->second_pass_weak_clds() == NULL, "Should be null if not tracing metadata.");
|
||||
}
|
||||
|
||||
// During conc marking we have to filter the per-thread SATB buffers
|
||||
// to make sure we remove any oops into the CSet (which will show up
|
||||
// as implicitly live).
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i);
|
||||
if (_process_strong_tasks.try_claim_task(G1RP_PS_filter_satb_buffers) && _g1h->collector_state()->mark_or_rebuild_in_progress()) {
|
||||
G1BarrierSet::satb_mark_queue_set().filter_thread_buffers();
|
||||
}
|
||||
}
|
||||
|
||||
_process_strong_tasks.all_tasks_completed(n_workers());
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,6 @@ class G1RootProcessor : public StackObj {
|
||||
G1RP_PS_CodeCache_oops_do,
|
||||
AOT_ONLY(G1RP_PS_aot_oops_do COMMA)
|
||||
JVMCI_ONLY(G1RP_PS_JVMCI_oops_do COMMA)
|
||||
G1RP_PS_filter_satb_buffers,
|
||||
G1RP_PS_refProcessor_oops_do,
|
||||
// Leave this one last.
|
||||
G1RP_PS_NumElements
|
||||
|
@ -189,18 +189,6 @@ void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active)
|
||||
Threads::threads_do(&closure);
|
||||
}
|
||||
|
||||
void SATBMarkQueueSet::filter_thread_buffers() {
|
||||
class FilterThreadBufferClosure : public ThreadClosure {
|
||||
SATBMarkQueueSet* _qset;
|
||||
public:
|
||||
FilterThreadBufferClosure(SATBMarkQueueSet* qset) : _qset(qset) {}
|
||||
virtual void do_thread(Thread* t) {
|
||||
_qset->satb_queue_for_thread(t).filter();
|
||||
}
|
||||
} closure(this);
|
||||
Threads::threads_do(&closure);
|
||||
}
|
||||
|
||||
bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) {
|
||||
BufferNode* nd = get_completed_buffer();
|
||||
if (nd != NULL) {
|
||||
|
@ -125,9 +125,6 @@ public:
|
||||
size_t buffer_enqueue_threshold() const { return _buffer_enqueue_threshold; }
|
||||
virtual void filter(SATBMarkQueue* queue) = 0;
|
||||
|
||||
// Filter all the currently-active SATB buffers.
|
||||
void filter_thread_buffers();
|
||||
|
||||
// If there exists some completed buffer, pop and process it, and
|
||||
// return true. Otherwise return false. Processing a buffer
|
||||
// consists of applying the closure to the active range of the
|
||||
|
@ -1333,8 +1333,8 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) {
|
||||
CallNode* call = ctrl->in(0)->as_CallJava();
|
||||
if ((ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) || ctrl->is_CallJava()) {
|
||||
CallNode* call = ctrl->is_Proj() ? ctrl->in(0)->as_CallJava() : ctrl->as_CallJava();
|
||||
CallProjections projs;
|
||||
call->extract_projections(&projs, false, false);
|
||||
|
||||
@ -1362,7 +1362,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
|
||||
if (idx < n->outcnt()) {
|
||||
Node* u = n->raw_out(idx);
|
||||
Node* c = phase->ctrl_or_self(u);
|
||||
if (c == ctrl) {
|
||||
if (phase->is_dominator(call, c) && phase->is_dominator(c, projs.fallthrough_proj)) {
|
||||
stack.set_index(idx+1);
|
||||
assert(!u->is_CFG(), "");
|
||||
stack.push(u, 0);
|
||||
@ -1404,14 +1404,11 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// assert(n_clone->outcnt() > 0, "");
|
||||
// assert(n->outcnt() > 0, "");
|
||||
stack.pop();
|
||||
clones.pop();
|
||||
}
|
||||
} while (stack.size() > 0);
|
||||
assert(stack.size() == 0 && clones.size() == 0, "");
|
||||
ctrl = projs.fallthrough_catchproj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1950,6 +1947,9 @@ void ShenandoahBarrierC2Support::optimize_after_expansion(VectorSet &visited, No
|
||||
head->verify_strip_mined(0);
|
||||
}
|
||||
move_heap_stable_test_out_of_loop(iff, phase);
|
||||
|
||||
AutoNodeBudget node_budget(phase);
|
||||
|
||||
if (loop->policy_unswitching(phase)) {
|
||||
if (head->is_strip_mined()) {
|
||||
OuterStripMinedLoopNode* outer = head->as_CountedLoop()->outer_loop();
|
||||
|
@ -45,10 +45,13 @@ void ShenandoahArguments::initialize() {
|
||||
FLAG_SET_DEFAULT(ShenandoahGCHeuristics, "passive");
|
||||
|
||||
FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false);
|
||||
FLAG_SET_DEFAULT(ShenandoahLoadRefBarrier, false);
|
||||
FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false);
|
||||
FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, false);
|
||||
FLAG_SET_DEFAULT(ShenandoahCASBarrier, false);
|
||||
FLAG_SET_DEFAULT(ShenandoahCloneBarrier, false);
|
||||
|
||||
FLAG_SET_DEFAULT(ShenandoahVerifyOptoBarriers, false);
|
||||
#endif
|
||||
|
||||
#ifdef _LP64
|
||||
@ -106,6 +109,7 @@ void ShenandoahArguments::initialize() {
|
||||
// C2 barrier verification is only reliable when all default barriers are enabled
|
||||
if (ShenandoahVerifyOptoBarriers &&
|
||||
(!FLAG_IS_DEFAULT(ShenandoahSATBBarrier) ||
|
||||
!FLAG_IS_DEFAULT(ShenandoahLoadRefBarrier) ||
|
||||
!FLAG_IS_DEFAULT(ShenandoahKeepAliveBarrier) ||
|
||||
!FLAG_IS_DEFAULT(ShenandoahStoreValEnqueueBarrier) ||
|
||||
!FLAG_IS_DEFAULT(ShenandoahCASBarrier) ||
|
||||
|
@ -89,7 +89,6 @@ void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) {
|
||||
|
||||
AlwaysTrueClosure always_true;
|
||||
WeakProcessor::weak_oops_do(&always_true, oops);
|
||||
JvmtiExport::weak_oops_do(&always_true, oops);
|
||||
|
||||
if (ShenandoahStringDedup::is_enabled()) {
|
||||
ShenandoahStringDedup::oops_do_slow(oops);
|
||||
|
@ -35,10 +35,10 @@ class ZGranuleMap {
|
||||
friend class ZGranuleMapIterator<T>;
|
||||
|
||||
private:
|
||||
T* const _map;
|
||||
const size_t _size;
|
||||
T* const _map;
|
||||
|
||||
size_t index_for_addr(uintptr_t addr) const;
|
||||
size_t size() const;
|
||||
|
||||
public:
|
||||
ZGranuleMap();
|
||||
|
@ -31,11 +31,12 @@
|
||||
|
||||
template <typename T>
|
||||
inline ZGranuleMap<T>::ZGranuleMap() :
|
||||
_map(MmapArrayAllocator<T>::allocate(size(), mtGC)) {}
|
||||
_size(ZAddressOffsetMax >> ZGranuleSizeShift),
|
||||
_map(MmapArrayAllocator<T>::allocate(_size, mtGC)) {}
|
||||
|
||||
template <typename T>
|
||||
inline ZGranuleMap<T>::~ZGranuleMap() {
|
||||
MmapArrayAllocator<T>::free(_map, size());
|
||||
MmapArrayAllocator<T>::free(_map, _size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -43,16 +44,11 @@ inline size_t ZGranuleMap<T>::index_for_addr(uintptr_t addr) const {
|
||||
assert(!ZAddress::is_null(addr), "Invalid address");
|
||||
|
||||
const size_t index = ZAddress::offset(addr) >> ZGranuleSizeShift;
|
||||
assert(index < size(), "Invalid index");
|
||||
assert(index < _size, "Invalid index");
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t ZGranuleMap<T>::size() const {
|
||||
return ZAddressOffsetMax >> ZGranuleSizeShift;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ZGranuleMap<T>::get(uintptr_t addr) const {
|
||||
const size_t index = index_for_addr(addr);
|
||||
@ -83,7 +79,7 @@ inline ZGranuleMapIterator<T>::ZGranuleMapIterator(const ZGranuleMap<T>* map) :
|
||||
|
||||
template <typename T>
|
||||
inline bool ZGranuleMapIterator<T>::next(T* value) {
|
||||
if (_next < _map->size()) {
|
||||
if (_next < _map->_size) {
|
||||
*value = _map->_map[_next++];
|
||||
return true;
|
||||
}
|
||||
@ -94,7 +90,7 @@ inline bool ZGranuleMapIterator<T>::next(T* value) {
|
||||
|
||||
template <typename T>
|
||||
inline bool ZGranuleMapIterator<T>::next(T** value) {
|
||||
if (_next < _map->size()) {
|
||||
if (_next < _map->_size) {
|
||||
*value = _map->_map + _next++;
|
||||
return true;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "interpreter/bytecodeHistogram.hpp"
|
||||
#include "interpreter/bytecodeInterpreter.hpp"
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
#include "interpreter/interp_masm.hpp"
|
||||
@ -36,6 +37,8 @@
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/arrayOop.hpp"
|
||||
#include "oops/constantPool.hpp"
|
||||
#include "oops/cpCache.inline.hpp"
|
||||
#include "oops/methodData.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -240,9 +243,36 @@ void AbstractInterpreter::set_entry_for_kind(AbstractInterpreter::MethodKind kin
|
||||
// Return true if the interpreter can prove that the given bytecode has
|
||||
// not yet been executed (in Java semantics, not in actual operation).
|
||||
bool AbstractInterpreter::is_not_reached(const methodHandle& method, int bci) {
|
||||
Bytecodes::Code code = method()->code_at(bci);
|
||||
BytecodeStream s(method, bci);
|
||||
Bytecodes::Code code = s.next();
|
||||
|
||||
if (!Bytecodes::must_rewrite(code)) {
|
||||
if (Bytecodes::is_invoke(code)) {
|
||||
assert(!Bytecodes::must_rewrite(code), "invokes aren't rewritten");
|
||||
ConstantPool* cpool = method()->constants();
|
||||
|
||||
Bytecode invoke_bc(s.bytecode());
|
||||
|
||||
switch (code) {
|
||||
case Bytecodes::_invokedynamic: {
|
||||
assert(invoke_bc.has_index_u4(code), "sanity");
|
||||
int method_index = invoke_bc.get_index_u4(code);
|
||||
return cpool->invokedynamic_cp_cache_entry_at(method_index)->is_f1_null();
|
||||
}
|
||||
case Bytecodes::_invokevirtual: // fall-through
|
||||
case Bytecodes::_invokeinterface: // fall-through
|
||||
case Bytecodes::_invokespecial: // fall-through
|
||||
case Bytecodes::_invokestatic: {
|
||||
if (cpool->has_preresolution()) {
|
||||
return false; // might have been reached
|
||||
}
|
||||
assert(!invoke_bc.has_index_u4(code), "sanity");
|
||||
int method_index = invoke_bc.get_index_u2_cpcache(code);
|
||||
Method* resolved_method = ConstantPool::method_at_if_loaded(cpool, method_index);
|
||||
return (resolved_method == NULL);
|
||||
}
|
||||
default: ShouldNotReachHere();
|
||||
}
|
||||
} else if (!Bytecodes::must_rewrite(code)) {
|
||||
// might have been reached
|
||||
return false;
|
||||
}
|
||||
|
@ -170,6 +170,10 @@ class BytecodeStream: public BaseBytecodeStream {
|
||||
// Construction
|
||||
BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { }
|
||||
|
||||
BytecodeStream(const methodHandle& method, int bci) : BaseBytecodeStream(method) {
|
||||
set_start(bci);
|
||||
}
|
||||
|
||||
// Iteration
|
||||
Bytecodes::Code next() {
|
||||
Bytecodes::Code raw_code, code;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -160,13 +160,14 @@ class JavaArgumentUnboxer : public SignatureIterator {
|
||||
};
|
||||
|
||||
class JNIHandleMark : public StackObj {
|
||||
JavaThread* _thread;
|
||||
public:
|
||||
JNIHandleMark() { push_jni_handle_block(); }
|
||||
~JNIHandleMark() { pop_jni_handle_block(); }
|
||||
JNIHandleMark(JavaThread* thread) : _thread(thread) { push_jni_handle_block(thread); }
|
||||
~JNIHandleMark() { pop_jni_handle_block(_thread); }
|
||||
|
||||
private:
|
||||
static void push_jni_handle_block();
|
||||
static void pop_jni_handle_block();
|
||||
static void push_jni_handle_block(JavaThread* thread);
|
||||
static void pop_jni_handle_block(JavaThread* thread);
|
||||
};
|
||||
|
||||
#endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP
|
||||
|
@ -129,11 +129,10 @@ void JVMCIEnv::copy_saved_properties() {
|
||||
}
|
||||
}
|
||||
|
||||
JNIEnv* JVMCIEnv::attach_shared_library() {
|
||||
JNIEnv* JVMCIEnv::init_shared_library(JavaThread* thread) {
|
||||
if (_shared_library_javavm == NULL) {
|
||||
MutexLocker locker(JVMCI_lock);
|
||||
if (_shared_library_javavm == NULL) {
|
||||
|
||||
char path[JVM_MAXPATHLEN];
|
||||
char ebuf[1024];
|
||||
if (JVMCILibPath != NULL) {
|
||||
@ -179,85 +178,107 @@ JNIEnv* JVMCIEnv::attach_shared_library() {
|
||||
}
|
||||
}
|
||||
}
|
||||
JNIEnv* env;
|
||||
if (_shared_library_javavm->AttachCurrentThread((void**)&env, NULL) == JNI_OK) {
|
||||
guarantee(env != NULL, "missing env");
|
||||
return env;
|
||||
}
|
||||
fatal("Error attaching current thread to JVMCI shared library JNI interface");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void JVMCIEnv::init_env_mode_runtime(JNIEnv* parent_env) {
|
||||
void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
|
||||
assert(thread != NULL, "npe");
|
||||
// By default there is only one runtime which is the compiler runtime.
|
||||
_runtime = JVMCI::compiler_runtime();
|
||||
_env = NULL;
|
||||
_pop_frame_on_close = false;
|
||||
_detach_on_close = false;
|
||||
if (!UseJVMCINativeLibrary) {
|
||||
// In HotSpot mode, JNI isn't used at all.
|
||||
_is_hotspot = true;
|
||||
_env = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent_env != NULL) {
|
||||
// If the parent JNI environment is non-null then figure out whether it
|
||||
// is a HotSpot or shared library JNIEnv and set the state appropriately.
|
||||
JavaThread* thread = JavaThread::current();
|
||||
if (thread->jni_environment() == parent_env) {
|
||||
_is_hotspot = thread->jni_environment() == parent_env;
|
||||
if (_is_hotspot) {
|
||||
// Select the Java runtime
|
||||
_runtime = JVMCI::java_runtime();
|
||||
_is_hotspot = true;
|
||||
_env = NULL;
|
||||
return;
|
||||
}
|
||||
_env = parent_env;
|
||||
return;
|
||||
}
|
||||
|
||||
// Running in JVMCI shared library mode so get a shared library JNIEnv
|
||||
// Running in JVMCI shared library mode so ensure the shared library
|
||||
// is loaded and initialized and get a shared library JNIEnv
|
||||
_is_hotspot = false;
|
||||
_env = attach_shared_library();
|
||||
assert(parent_env == NULL || _env == parent_env, "must be");
|
||||
_env = init_shared_library(thread);
|
||||
|
||||
if (parent_env == NULL) {
|
||||
// There is no parent shared library JNI env so push
|
||||
// a JNI local frame to release all local handles in
|
||||
// this JVMCIEnv scope when it's closed.
|
||||
assert(_throw_to_caller == false, "must be");
|
||||
JNIAccessMark jni(this);
|
||||
jint result = _env->PushLocalFrame(32);
|
||||
if (result != JNI_OK) {
|
||||
char message[256];
|
||||
jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line);
|
||||
JVMCIRuntime::exit_on_pending_exception(this, message);
|
||||
if (_env != NULL) {
|
||||
// Creating the JVMCI shared library VM also attaches the current thread
|
||||
_detach_on_close = true;
|
||||
} else {
|
||||
_shared_library_javavm->GetEnv((void**)&parent_env, JNI_VERSION_1_2);
|
||||
if (parent_env != NULL) {
|
||||
// Even though there's a parent JNI env, there's no guarantee
|
||||
// it was opened by a JVMCIEnv scope and thus may not have
|
||||
// pushed a local JNI frame. As such, we use a new JNI local
|
||||
// frame in this scope to ensure local JNI refs are collected
|
||||
// in a timely manner after leaving this scope.
|
||||
_env = parent_env;
|
||||
} else {
|
||||
ResourceMark rm; // Thread name is resource allocated
|
||||
JavaVMAttachArgs attach_args;
|
||||
attach_args.version = JNI_VERSION_1_2;
|
||||
attach_args.name = thread->name();
|
||||
attach_args.group = NULL;
|
||||
if (_shared_library_javavm->AttachCurrentThread((void**)&_env, &attach_args) != JNI_OK) {
|
||||
fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name);
|
||||
}
|
||||
_detach_on_close = true;
|
||||
}
|
||||
}
|
||||
|
||||
assert(_env != NULL, "missing env");
|
||||
assert(_throw_to_caller == false, "must be");
|
||||
|
||||
JNIAccessMark jni(this);
|
||||
jint result = _env->PushLocalFrame(32);
|
||||
if (result != JNI_OK) {
|
||||
char message[256];
|
||||
jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line);
|
||||
JVMCIRuntime::exit_on_pending_exception(this, message);
|
||||
}
|
||||
_pop_frame_on_close = true;
|
||||
}
|
||||
|
||||
JVMCIEnv::JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line):
|
||||
JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line):
|
||||
_throw_to_caller(false), _file(file), _line(line), _compile_state(compile_state) {
|
||||
init_env_mode_runtime(NULL);
|
||||
init_env_mode_runtime(thread, NULL);
|
||||
}
|
||||
|
||||
JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line):
|
||||
_throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) {
|
||||
init_env_mode_runtime(NULL);
|
||||
init_env_mode_runtime(thread, NULL);
|
||||
}
|
||||
|
||||
JVMCIEnv::JVMCIEnv(JNIEnv* parent_env, const char* file, int line):
|
||||
JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line):
|
||||
_throw_to_caller(true), _file(file), _line(line), _compile_state(NULL) {
|
||||
init_env_mode_runtime(parent_env);
|
||||
init_env_mode_runtime(thread, parent_env);
|
||||
assert(_env == NULL || parent_env == _env, "mismatched JNIEnvironment");
|
||||
}
|
||||
|
||||
void JVMCIEnv::init(bool is_hotspot, const char* file, int line) {
|
||||
void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int line) {
|
||||
_compile_state = NULL;
|
||||
_throw_to_caller = false;
|
||||
_file = file;
|
||||
_line = line;
|
||||
if (is_hotspot) {
|
||||
_env = NULL;
|
||||
_pop_frame_on_close = false;
|
||||
_detach_on_close = false;
|
||||
_is_hotspot = true;
|
||||
_runtime = JVMCI::java_runtime();
|
||||
} else {
|
||||
init_env_mode_runtime(NULL);
|
||||
init_env_mode_runtime(thread, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,7 +345,7 @@ JVMCIEnv::~JVMCIEnv() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!is_hotspot()) {
|
||||
if (_pop_frame_on_close) {
|
||||
// Pop the JNI local frame that was pushed when entering this JVMCIEnv scope.
|
||||
JNIAccessMark jni(this);
|
||||
jni()->PopLocalFrame(NULL);
|
||||
@ -335,6 +356,10 @@ JVMCIEnv::~JVMCIEnv() {
|
||||
jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line);
|
||||
JVMCIRuntime::exit_on_pending_exception(this, message);
|
||||
}
|
||||
|
||||
if (_detach_on_close) {
|
||||
get_shared_library_javavm()->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,26 +488,38 @@ void JVMCIEnv::put_long_at(JVMCIPrimitiveArray array, int index, jlong value) {
|
||||
}
|
||||
}
|
||||
|
||||
void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes) {
|
||||
if (size_in_bytes == 0) {
|
||||
void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length) {
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
if (is_hotspot()) {
|
||||
memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), size_in_bytes);
|
||||
memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), length);
|
||||
} else {
|
||||
JNIAccessMark jni(this);
|
||||
jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, size_in_bytes, dest);
|
||||
jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, length, dest);
|
||||
}
|
||||
}
|
||||
void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes) {
|
||||
if (size_in_bytes == 0) {
|
||||
void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
if (is_hotspot()) {
|
||||
memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, size_in_bytes);
|
||||
memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, length);
|
||||
} else {
|
||||
JNIAccessMark jni(this);
|
||||
jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, size_in_bytes, src);
|
||||
jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, length, src);
|
||||
}
|
||||
}
|
||||
|
||||
void JVMCIEnv::copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
|
||||
if (length == 0) {
|
||||
return;
|
||||
}
|
||||
if (is_hotspot()) {
|
||||
memcpy(HotSpotJVMCI::resolve(dest)->long_at_addr(offset), src, length * sizeof(jlong));
|
||||
} else {
|
||||
JNIAccessMark jni(this);
|
||||
jni()->SetLongArrayRegion(dest.as_jlongArray(), offset, length, src);
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,6 +649,8 @@ DO_THROW(NullPointerException)
|
||||
DO_THROW(IllegalArgumentException)
|
||||
DO_THROW(InvalidInstalledCodeException)
|
||||
DO_THROW(UnsatisfiedLinkError)
|
||||
DO_THROW(UnsupportedOperationException)
|
||||
DO_THROW(ClassNotFoundException)
|
||||
|
||||
#undef DO_THROW
|
||||
|
||||
@ -888,7 +927,7 @@ JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci,
|
||||
return JVMCIObject();
|
||||
}
|
||||
jobject file_name = NULL;
|
||||
if (file_name != NULL) {
|
||||
if (file_name_sym != NULL) {
|
||||
file_name = jni()->NewStringUTF(file_name_sym->as_C_string());
|
||||
if (jni()->ExceptionCheck()) {
|
||||
return JVMCIObject();
|
||||
@ -1323,14 +1362,15 @@ Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
|
||||
assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type");
|
||||
oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant));
|
||||
return Handle(THREAD, obj);
|
||||
} else {
|
||||
assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type");
|
||||
} else if (isa_IndirectHotSpotObjectConstantImpl(constant)) {
|
||||
jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant);
|
||||
oop result = resolve_handle(object_handle);
|
||||
if (result == NULL) {
|
||||
JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());
|
||||
}
|
||||
return Handle(THREAD, result);
|
||||
} else {
|
||||
JVMCI_THROW_MSG_(IllegalArgumentException, "DirectHotSpotObjectConstantImpl shouldn't reach JVMCI in SVM mode", Handle());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,15 +36,6 @@ class JVMCIPrimitiveArray;
|
||||
class JVMCICompiler;
|
||||
class JVMCIRuntime;
|
||||
|
||||
// Bring the JVMCI compiler thread into the VM state.
|
||||
#define JVMCI_VM_ENTRY_MARK \
|
||||
JavaThread* thread = JavaThread::current(); \
|
||||
ThreadInVMfromNative __tiv(thread); \
|
||||
ResetNoHandleMark rnhm; \
|
||||
HandleMarkCleaner __hm(thread); \
|
||||
Thread* THREAD = thread; \
|
||||
debug_only(VMNativeEntryWrapper __vew;)
|
||||
|
||||
#define JVMCI_EXCEPTION_CONTEXT \
|
||||
JavaThread* thread=JavaThread::current(); \
|
||||
Thread* THREAD = thread;
|
||||
@ -154,24 +145,25 @@ class JVMCIEnv : public ResourceObj {
|
||||
static void* _shared_library_handle; // result of os::dll_load
|
||||
static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library
|
||||
|
||||
// Attaches the current thread to the JavaVM in the shared library,
|
||||
// initializing the shared library VM first if necessary.
|
||||
// Returns the JNI interface pointer of the current thread.
|
||||
// The _shared_library_* fields are initialized by the first
|
||||
// call to this method.
|
||||
static JNIEnv* attach_shared_library();
|
||||
// Initializes the shared library JavaVM if not already initialized.
|
||||
// Returns the JNI interface pointer for the current thread
|
||||
// if initialization was performed by this call, NULL if
|
||||
// initialization was performed by a previous call.
|
||||
static JNIEnv* init_shared_library(JavaThread* thread);
|
||||
|
||||
// Initializes the _env, _mode and _runtime fields.
|
||||
void init_env_mode_runtime(JNIEnv* parent_env);
|
||||
void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env);
|
||||
|
||||
void init(bool is_hotspot, const char* file, int line);
|
||||
void init(JavaThread* thread, bool is_hotspot, const char* file, int line);
|
||||
|
||||
JNIEnv* _env; // JNI env for calling into shared library
|
||||
JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime
|
||||
bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in
|
||||
bool _throw_to_caller; // Propagate an exception raised in this env to the caller?
|
||||
const char* _file; // The file and ...
|
||||
int _line; // ... line where this JNIEnv was created
|
||||
JNIEnv* _env; // JNI env for calling into shared library
|
||||
bool _pop_frame_on_close; // Must pop frame on close?
|
||||
bool _detach_on_close; // Must detach on close?
|
||||
JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime
|
||||
bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in
|
||||
bool _throw_to_caller; // Propagate an exception raised in this env to the caller?
|
||||
const char* _file; // The file and ...
|
||||
int _line; // ... line where this JNIEnv was created
|
||||
|
||||
// Translates an exception on the HotSpot heap to an exception on
|
||||
// the shared library heap. The translation includes the stack and
|
||||
@ -185,12 +177,12 @@ public:
|
||||
// scope closes so that it will be propagated back to Java.
|
||||
// The JVMCIEnv destructor translates the exception object for the
|
||||
// Java runtime if necessary.
|
||||
JVMCIEnv(JNIEnv* env, const char* file, int line);
|
||||
JVMCIEnv(JavaThread* thread, JNIEnv* env, const char* file, int line);
|
||||
|
||||
// Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker.
|
||||
// An exception occurring within the scope must not be propagated back to
|
||||
// the CompileBroker.
|
||||
JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line);
|
||||
JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line);
|
||||
|
||||
// Opens a JNIEnv scope for a call from within the VM. An exception occurring
|
||||
// within the scope must not be propagated back to the caller.
|
||||
@ -198,20 +190,20 @@ public:
|
||||
|
||||
// Opens a JNIEnv scope for accessing `for_object`. An exception occurring
|
||||
// within the scope must not be propagated back to the caller.
|
||||
JVMCIEnv(JVMCIObject for_object, const char* file, int line) {
|
||||
JVMCIEnv(JavaThread* thread, JVMCIObject for_object, const char* file, int line) {
|
||||
// A JNI call to access an object in the shared library heap
|
||||
// can block or take a long time so do not allow such access
|
||||
// on the VM thread.
|
||||
assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(),
|
||||
"cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object");
|
||||
init(for_object.is_hotspot(), file, line);
|
||||
init(thread, for_object.is_hotspot(), file, line);
|
||||
}
|
||||
|
||||
// Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true
|
||||
// otherwise for the shared library runtime. An exception occurring
|
||||
// within the scope must not be propagated back to the caller.
|
||||
JVMCIEnv(bool is_hotspot, const char* file, int line) {
|
||||
init(is_hotspot, file, line);
|
||||
JVMCIEnv(JavaThread* thread, bool is_hotspot, const char* file, int line) {
|
||||
init(thread, is_hotspot, file, line);
|
||||
}
|
||||
|
||||
~JVMCIEnv();
|
||||
@ -247,8 +239,10 @@ public:
|
||||
long get_long_at(JVMCIPrimitiveArray array, int index);
|
||||
void put_long_at(JVMCIPrimitiveArray array, int index, jlong value);
|
||||
|
||||
void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes);
|
||||
void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes);
|
||||
void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length);
|
||||
void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length);
|
||||
|
||||
void copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length);
|
||||
|
||||
JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS);
|
||||
|
||||
@ -323,6 +317,8 @@ public:
|
||||
DO_THROW(IllegalArgumentException)
|
||||
DO_THROW(InvalidInstalledCodeException)
|
||||
DO_THROW(UnsatisfiedLinkError)
|
||||
DO_THROW(UnsupportedOperationException)
|
||||
DO_THROW(ClassNotFoundException)
|
||||
|
||||
#undef DO_THROW
|
||||
|
||||
|
@ -32,8 +32,8 @@ class JVMCIEnv;
|
||||
#define JVMCIENV __jvmci_env__
|
||||
#define JVMCI_TRAPS JVMCIEnv* JVMCIENV
|
||||
|
||||
#define JNI_JVMCIENV(env) \
|
||||
JVMCIEnv __stack_jvmci_env__(env, __FILE__, __LINE__); \
|
||||
#define JNI_JVMCIENV(thread, env) \
|
||||
JVMCIEnv __stack_jvmci_env__(thread, env, __FILE__, __LINE__); \
|
||||
JVMCIEnv* JVMCIENV = &__stack_jvmci_env__
|
||||
|
||||
#define THREAD_JVMCIENV(thread) \
|
||||
|
@ -356,6 +356,43 @@ extern "C" {
|
||||
jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c);
|
||||
}
|
||||
|
||||
// Dumps symbols for public <init>() and <init>(String) methods of
|
||||
// non-abstract Throwable subtypes known by the VM. This is to
|
||||
// support the use of reflection in jdk.vm.ci.hotspot.TranslatedException.create().
|
||||
class ThrowableInitDumper : public SymbolClosure {
|
||||
private:
|
||||
fileStream* _st;
|
||||
public:
|
||||
ThrowableInitDumper(fileStream* st) { _st = st; }
|
||||
void do_symbol(Symbol** p) {
|
||||
Thread* THREAD = Thread::current();
|
||||
Symbol* name = *p;
|
||||
if (name == NULL) {
|
||||
return;
|
||||
}
|
||||
Klass* k = SystemDictionary::resolve_or_null(name, CHECK_EXIT);
|
||||
if (k != NULL && k->is_instance_klass()) {
|
||||
InstanceKlass* iklass = InstanceKlass::cast(k);
|
||||
if (iklass->is_subclass_of(SystemDictionary::Throwable_klass()) && iklass->is_public() && !iklass->is_abstract()) {
|
||||
const char* class_name = NULL;
|
||||
Array<Method*>* methods = iklass->methods();
|
||||
for (int i = 0; i < methods->length(); i++) {
|
||||
Method* m = methods->at(i);
|
||||
if (m->name() == vmSymbols::object_initializer_name() &&
|
||||
m->is_public() &&
|
||||
(m->signature() == vmSymbols::void_method_signature() || m->signature() == vmSymbols::string_void_signature())) {
|
||||
if (class_name == NULL) {
|
||||
class_name = name->as_C_string();
|
||||
_st->print_cr("class %s", class_name);
|
||||
}
|
||||
_st->print_cr("method %s %s %s", class_name, m->name()->as_C_string(), m->signature()->as_C_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string()
|
||||
/**
|
||||
* Initializes the JNI method and field ids used in JNIJVMCI.
|
||||
@ -441,6 +478,8 @@ void JNIJVMCI::initialize_ids(JNIEnv* env) {
|
||||
fileStream* st = JVMCIGlobals::get_jni_config_file();
|
||||
|
||||
DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM());
|
||||
ThrowableInitDumper dumper(st);
|
||||
vmSymbols::symbols_do(&dumper);
|
||||
|
||||
st->flush();
|
||||
tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig);
|
||||
|
@ -381,12 +381,18 @@
|
||||
start_class(InternalError, java_lang_InternalError) \
|
||||
jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \
|
||||
end_class \
|
||||
start_class(ClassNotFoundException, java_lang_ClassNotFoundException) \
|
||||
jvmci_constructor(ClassNotFoundException, "(Ljava/lang/String;)V") \
|
||||
end_class \
|
||||
start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \
|
||||
jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \
|
||||
end_class \
|
||||
start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \
|
||||
jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \
|
||||
end_class \
|
||||
start_class(UnsupportedOperationException, java_lang_UnsupportedOperationException) \
|
||||
jvmci_constructor(UnsupportedOperationException, "(Ljava/lang/String;)V") \
|
||||
end_class \
|
||||
start_class(StackTraceElement, java_lang_StackTraceElement) \
|
||||
object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \
|
||||
object_field(StackTraceElement, methodName, "Ljava/lang/String;") \
|
||||
|
@ -655,7 +655,7 @@ JRT_END
|
||||
|
||||
// private static JVMCIRuntime JVMCI.initializeRuntime()
|
||||
JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
|
||||
JNI_JVMCIENV(env);
|
||||
JNI_JVMCIENV(thread, env);
|
||||
if (!EnableJVMCI) {
|
||||
JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled");
|
||||
}
|
||||
@ -877,7 +877,7 @@ JVM_ENTRY_NO_ENV(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass))
|
||||
fatal("check TLAB allocation code for address space conflicts");
|
||||
#endif
|
||||
|
||||
JNI_JVMCIENV(env);
|
||||
JNI_JVMCIENV(thread, env);
|
||||
|
||||
if (!EnableJVMCI) {
|
||||
JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled");
|
||||
@ -1353,6 +1353,10 @@ void JVMCIRuntime::compile_method(JVMCIEnv* JVMCIENV, JVMCICompiler* compiler, c
|
||||
compile_state->set_failure(true, "No OSR during boostrap");
|
||||
return;
|
||||
}
|
||||
if (JVMCI::shutdown_called()) {
|
||||
compile_state->set_failure(false, "Avoiding compilation during shutdown");
|
||||
return;
|
||||
}
|
||||
|
||||
HandleMark hm;
|
||||
JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV);
|
||||
|
@ -83,7 +83,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() {
|
||||
}
|
||||
FLAG_SET_DEFAULT(EnableJVMCI, true);
|
||||
if (BootstrapJVMCI && UseJVMCINativeLibrary) {
|
||||
jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary");
|
||||
jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,10 @@
|
||||
"Prints properties used by the JVMCI compiler and exits") \
|
||||
\
|
||||
experimental(bool, BootstrapJVMCI, false, \
|
||||
"Bootstrap JVMCI before running Java main method") \
|
||||
"Bootstrap JVMCI before running Java main method. This " \
|
||||
"initializes the compile queue with a small set of methods " \
|
||||
"and processes the queue until it is empty. Combining this with " \
|
||||
"-XX:-TieredCompilation makes JVMCI compile more of itself.") \
|
||||
\
|
||||
experimental(bool, EagerJVMCI, false, \
|
||||
"Force eager JVMCI initialization") \
|
||||
|
@ -246,6 +246,10 @@
|
||||
\
|
||||
nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \
|
||||
\
|
||||
volatile_nonstatic_field(ObjectMonitor, _cxq, ObjectWaiter*) \
|
||||
volatile_nonstatic_field(ObjectMonitor, _EntryList, ObjectWaiter*) \
|
||||
volatile_nonstatic_field(ObjectMonitor, _succ, Thread*) \
|
||||
\
|
||||
volatile_nonstatic_field(oopDesc, _mark, markOop) \
|
||||
volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \
|
||||
\
|
||||
@ -347,6 +351,7 @@
|
||||
declare_toplevel_type(JVMCIEnv) \
|
||||
declare_toplevel_type(LocalVariableTableElement) \
|
||||
declare_toplevel_type(narrowKlass) \
|
||||
declare_toplevel_type(ObjectWaiter) \
|
||||
declare_toplevel_type(Symbol*) \
|
||||
declare_toplevel_type(vtableEntry) \
|
||||
\
|
||||
|
@ -506,7 +506,7 @@ Method* ConstantPoolCacheEntry::method_if_resolved(const constantPoolHandle& cpo
|
||||
switch (invoke_code) {
|
||||
case Bytecodes::_invokeinterface:
|
||||
assert(f1->is_klass(), "");
|
||||
return klassItable::method_for_itable_index((InstanceKlass*)f1, f2_as_index());
|
||||
return f2_as_interface_method();
|
||||
case Bytecodes::_invokestatic:
|
||||
case Bytecodes::_invokespecial:
|
||||
assert(!has_appendix(), "");
|
||||
|
@ -2965,6 +2965,13 @@ void InstanceKlass::adjust_default_methods(bool* trace_name_printed) {
|
||||
|
||||
// On-stack replacement stuff
|
||||
void InstanceKlass::add_osr_nmethod(nmethod* n) {
|
||||
#ifndef PRODUCT
|
||||
if (TieredCompilation) {
|
||||
nmethod * prev = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), n->comp_level(), true);
|
||||
assert(prev == NULL || !prev->is_in_use(),
|
||||
"redundunt OSR recompilation detected. memory leak in CodeCache!");
|
||||
}
|
||||
#endif
|
||||
// only one compilation can be active
|
||||
{
|
||||
// This is a short non-blocking critical region, so the no safepoint check is ok.
|
||||
@ -3083,7 +3090,9 @@ nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_le
|
||||
}
|
||||
osr = osr->osr_link();
|
||||
}
|
||||
if (best != NULL && best->comp_level() >= comp_level && match_level == false) {
|
||||
|
||||
assert(match_level == false || best == NULL, "shouldn't pick up anything if match_level is set");
|
||||
if (best != NULL && best->comp_level() >= comp_level) {
|
||||
return best;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -733,8 +733,9 @@ void Klass::print_on(outputStream* st) const {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
#define BULLET " - "
|
||||
|
||||
void Klass::oop_print_on(oop obj, outputStream* st) {
|
||||
ResourceMark rm;
|
||||
// print title
|
||||
st->print_cr("%s ", internal_name());
|
||||
obj->print_address_on(st);
|
||||
@ -742,10 +743,13 @@ void Klass::oop_print_on(oop obj, outputStream* st) {
|
||||
if (WizardMode) {
|
||||
// print header
|
||||
obj->mark()->print_on(st);
|
||||
st->cr();
|
||||
st->print(BULLET"prototype_header: " INTPTR_FORMAT, p2i(_prototype_header));
|
||||
st->cr();
|
||||
}
|
||||
|
||||
// print class
|
||||
st->print(" - klass: ");
|
||||
st->print(BULLET"klass: ");
|
||||
obj->klass()->print_value_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
@ -25,45 +25,40 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "oops/markOop.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/objectMonitor.inline.hpp"
|
||||
#include "runtime/objectMonitor.hpp"
|
||||
|
||||
void markOopDesc::print_on(outputStream* st) const {
|
||||
if (is_marked()) {
|
||||
if (is_marked()) { // last bits = 11
|
||||
st->print(" marked(" INTPTR_FORMAT ")", value());
|
||||
} else if (has_monitor()) {
|
||||
} else if (has_monitor()) { // last bits = 10
|
||||
// have to check has_monitor() before is_locked()
|
||||
st->print(" monitor(" INTPTR_FORMAT ")=", value());
|
||||
ObjectMonitor* mon = monitor();
|
||||
if (mon == NULL) {
|
||||
st->print("NULL (this should never be seen!)");
|
||||
} else {
|
||||
st->print("{contentions=0x%08x,waiters=0x%08x"
|
||||
",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}",
|
||||
mon->contentions(), mon->waiters(), mon->recursions(),
|
||||
p2i(mon->owner()));
|
||||
mon->print_on(st);
|
||||
}
|
||||
} else if (is_locked()) {
|
||||
st->print(" locked(" INTPTR_FORMAT ")->", value());
|
||||
if (is_neutral()) {
|
||||
} else if (is_locked()) { // last bits != 01 => 00
|
||||
// thin locked
|
||||
st->print(" locked(" INTPTR_FORMAT ")", value());
|
||||
} else {
|
||||
st->print(" mark(");
|
||||
// Biased bit is 3rd rightmost bit
|
||||
if (is_neutral()) { // last bits = 001
|
||||
st->print("is_neutral");
|
||||
if (has_no_hash()) {
|
||||
st->print(" no_hash");
|
||||
} else {
|
||||
st->print(" hash=" INTPTR_FORMAT, hash());
|
||||
}
|
||||
st->print(" age=%d", age());
|
||||
} else if (has_bias_pattern()) {
|
||||
} else if (has_bias_pattern()) { // last bits = 101
|
||||
st->print("is_biased");
|
||||
JavaThread* jt = biased_locker();
|
||||
st->print(" biased_locker=" INTPTR_FORMAT, p2i(jt));
|
||||
st->print(" biased_locker=" INTPTR_FORMAT " epoch=%d", p2i(jt), bias_epoch());
|
||||
} else {
|
||||
st->print("??");
|
||||
}
|
||||
} else {
|
||||
assert(is_unlocked() || has_bias_pattern(), "just checking");
|
||||
st->print("mark(");
|
||||
if (has_bias_pattern()) st->print("biased,");
|
||||
st->print("hash " INTPTR_FORMAT ",", hash());
|
||||
st->print("age %d)", age());
|
||||
st->print(" age=%d)", age());
|
||||
}
|
||||
}
|
||||
|
@ -624,6 +624,10 @@ bool Method::can_be_statically_bound() const {
|
||||
return can_be_statically_bound(method_holder()->access_flags());
|
||||
}
|
||||
|
||||
bool Method::can_be_statically_bound(InstanceKlass* context) const {
|
||||
return (method_holder() == context) && can_be_statically_bound();
|
||||
}
|
||||
|
||||
bool Method::is_accessor() const {
|
||||
return is_getter() || is_setter();
|
||||
}
|
||||
|
@ -619,6 +619,7 @@ class Method : public Metadata {
|
||||
|
||||
// true if method needs no dynamic dispatch (final and/or no vtable entry)
|
||||
bool can_be_statically_bound() const;
|
||||
bool can_be_statically_bound(InstanceKlass* context) const;
|
||||
bool can_be_statically_bound(AccessFlags class_access_flags) const;
|
||||
|
||||
// returns true if the method has any backward branches.
|
||||
|
@ -321,6 +321,35 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InlineTree::is_not_reached(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile) {
|
||||
if (!UseInterpreter) {
|
||||
return false; // -Xcomp
|
||||
}
|
||||
if (profile.count() > 0) {
|
||||
return false; // reachable according to profile
|
||||
}
|
||||
if (!callee_method->was_executed_more_than(0)) {
|
||||
return true; // callee was never executed
|
||||
}
|
||||
if (caller_method->is_not_reached(caller_bci)) {
|
||||
return true; // call site not resolved
|
||||
}
|
||||
if (profile.count() == -1) {
|
||||
return false; // immature profile; optimistically treat as reached
|
||||
}
|
||||
assert(profile.count() == 0, "sanity");
|
||||
|
||||
// Profile info is scarce.
|
||||
// Try to guess: check if the call site belongs to a start block.
|
||||
// Call sites in a start block should be reachable if no exception is thrown earlier.
|
||||
ciMethodBlocks* caller_blocks = caller_method->get_method_blocks();
|
||||
bool is_start_block = caller_blocks->block_containing(caller_bci)->start_bci() == 0;
|
||||
if (is_start_block) {
|
||||
return false; // treat the call reached as part of start block
|
||||
}
|
||||
return true; // give up and treat the call site as not reached
|
||||
}
|
||||
|
||||
//-----------------------------try_to_inline-----------------------------------
|
||||
// return true if ok
|
||||
// Relocated from "InliningClosure::try_to_inline"
|
||||
@ -372,7 +401,7 @@ bool InlineTree::try_to_inline(ciMethod* callee_method, ciMethod* caller_method,
|
||||
// inline constructors even if they are not reached.
|
||||
} else if (forced_inline()) {
|
||||
// Inlining was forced by CompilerOracle, ciReplay or annotation
|
||||
} else if (profile.count() == 0) {
|
||||
} else if (is_not_reached(callee_method, caller_method, caller_bci, profile)) {
|
||||
// don't inline unreached call sites
|
||||
set_msg("call site not reached");
|
||||
return false;
|
||||
|
@ -1152,14 +1152,19 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass*
|
||||
cha_monomorphic_target = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (cha_monomorphic_target != NULL) {
|
||||
// Hardwiring a virtual.
|
||||
// If we inlined because CHA revealed only a single target method,
|
||||
// then we are dependent on that target method not getting overridden
|
||||
// by dynamic class loading. Be sure to test the "static" receiver
|
||||
// dest_method here, as opposed to the actual receiver, which may
|
||||
// falsely lead us to believe that the receiver is final or private.
|
||||
dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target);
|
||||
assert(!callee->can_be_statically_bound(), "should have been handled earlier");
|
||||
assert(!cha_monomorphic_target->is_abstract(), "");
|
||||
if (!cha_monomorphic_target->can_be_statically_bound(actual_receiver)) {
|
||||
// If we inlined because CHA revealed only a single target method,
|
||||
// then we are dependent on that target method not getting overridden
|
||||
// by dynamic class loading. Be sure to test the "static" receiver
|
||||
// dest_method here, as opposed to the actual receiver, which may
|
||||
// falsely lead us to believe that the receiver is final or private.
|
||||
dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target);
|
||||
}
|
||||
return cha_monomorphic_target;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -55,27 +55,31 @@
|
||||
// Return TRUE or FALSE if the loop should be unswitched
|
||||
// (ie. clone loop with an invariant test that does not exit the loop)
|
||||
bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const {
|
||||
if( !LoopUnswitching ) {
|
||||
if (!LoopUnswitching) {
|
||||
return false;
|
||||
}
|
||||
if (!_head->is_Loop()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If nodes are depleted, some transform has miscalculated its needs.
|
||||
assert(!phase->exceeding_node_budget(), "sanity");
|
||||
|
||||
// check for vectorized loops, any unswitching was already applied
|
||||
if (_head->is_CountedLoop() && _head->as_CountedLoop()->do_unroll_only()) {
|
||||
if (_head->is_CountedLoop() && _head->as_CountedLoop()->is_unroll_only()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int nodes_left = phase->C->max_node_limit() - phase->C->live_nodes();
|
||||
if ((int)(2 * _body.size()) > nodes_left) {
|
||||
return false; // Too speculative if running low on nodes.
|
||||
}
|
||||
LoopNode* head = _head->as_Loop();
|
||||
if (head->unswitch_count() + 1 > head->unswitch_max()) {
|
||||
return false;
|
||||
}
|
||||
return phase->find_unswitching_candidate(this) != NULL;
|
||||
if (phase->find_unswitching_candidate(this) == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Too speculative if running low on nodes.
|
||||
return phase->may_require_nodes(est_loop_clone_sz(3, _body.size()));
|
||||
}
|
||||
|
||||
//------------------------------find_unswitching_candidate-----------------------------
|
||||
|
@ -42,17 +42,13 @@
|
||||
#include "opto/superword.hpp"
|
||||
|
||||
//=============================================================================
|
||||
//------------------------------is_loop_iv-------------------------------------
|
||||
// Determine if a node is Counted loop induction variable.
|
||||
// The method is declared in node.hpp.
|
||||
const Node* Node::is_loop_iv() const {
|
||||
if (this->is_Phi() && !this->as_Phi()->is_copy() &&
|
||||
this->as_Phi()->region()->is_CountedLoop() &&
|
||||
this->as_Phi()->region()->as_CountedLoop()->phi() == this) {
|
||||
return this;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
//--------------------------is_cloop_ind_var-----------------------------------
|
||||
// Determine if a node is a counted loop induction variable.
|
||||
// NOTE: The method is declared in "node.hpp".
|
||||
bool Node::is_cloop_ind_var() const {
|
||||
return (is_Phi() && !as_Phi()->is_copy() &&
|
||||
as_Phi()->region()->is_CountedLoop() &&
|
||||
as_Phi()->region()->as_CountedLoop()->phi() == this);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@ -2942,14 +2938,15 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
}
|
||||
|
||||
if (ReassociateInvariants) {
|
||||
AutoNodeBudget node_budget(this, AutoNodeBudget::NO_BUDGET_CHECK);
|
||||
// Reassociate invariants and prep for split_thru_phi
|
||||
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
|
||||
IdealLoopTree* lpt = iter.current();
|
||||
bool is_counted = lpt->is_counted();
|
||||
if (!is_counted || !lpt->is_inner()) continue;
|
||||
if (!is_counted || !lpt->is_innermost()) continue;
|
||||
|
||||
// check for vectorized loops, any reassociation of invariants was already done
|
||||
if (is_counted && lpt->_head->as_CountedLoop()->do_unroll_only()) continue;
|
||||
if (is_counted && lpt->_head->as_CountedLoop()->is_unroll_only()) continue;
|
||||
|
||||
lpt->reassociate_invariants(this);
|
||||
|
||||
|
@ -264,7 +264,7 @@ public:
|
||||
bool is_reduction_loop() const { return (_loop_flags&HasReductions) == HasReductions; }
|
||||
bool was_slp_analyzed () const { return (_loop_flags&WasSlpAnalyzed) == WasSlpAnalyzed; }
|
||||
bool has_passed_slp () const { return (_loop_flags&PassedSlpAnalysis) == PassedSlpAnalysis; }
|
||||
bool do_unroll_only () const { return (_loop_flags&DoUnrollOnly) == DoUnrollOnly; }
|
||||
bool is_unroll_only () const { return (_loop_flags&DoUnrollOnly) == DoUnrollOnly; }
|
||||
bool is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; }
|
||||
bool has_atomic_post_loop () const { return (_loop_flags & HasAtomicPostLoop) == HasAtomicPostLoop; }
|
||||
void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; }
|
||||
@ -370,26 +370,49 @@ public:
|
||||
};
|
||||
|
||||
|
||||
inline CountedLoopEndNode *CountedLoopNode::loopexit_or_null() const {
|
||||
Node *bc = back_control();
|
||||
if( bc == NULL ) return NULL;
|
||||
Node *le = bc->in(0);
|
||||
if( le->Opcode() != Op_CountedLoopEnd )
|
||||
return NULL;
|
||||
return (CountedLoopEndNode*)le;
|
||||
inline CountedLoopEndNode* CountedLoopNode::loopexit_or_null() const {
|
||||
Node* bctrl = back_control();
|
||||
if (bctrl == NULL) return NULL;
|
||||
|
||||
Node* lexit = bctrl->in(0);
|
||||
return (CountedLoopEndNode*)
|
||||
(lexit->Opcode() == Op_CountedLoopEnd ? lexit : NULL);
|
||||
}
|
||||
inline CountedLoopEndNode *CountedLoopNode::loopexit() const {
|
||||
|
||||
inline CountedLoopEndNode* CountedLoopNode::loopexit() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
assert(cle != NULL, "loopexit is NULL");
|
||||
return cle;
|
||||
}
|
||||
inline Node *CountedLoopNode::init_trip() const { return loopexit_or_null() ? loopexit()->init_trip() : NULL; }
|
||||
inline Node *CountedLoopNode::stride() const { return loopexit_or_null() ? loopexit()->stride() : NULL; }
|
||||
inline int CountedLoopNode::stride_con() const { return loopexit_or_null() ? loopexit()->stride_con() : 0; }
|
||||
inline bool CountedLoopNode::stride_is_con() const { return loopexit_or_null() && loopexit()->stride_is_con(); }
|
||||
inline Node *CountedLoopNode::limit() const { return loopexit_or_null() ? loopexit()->limit() : NULL; }
|
||||
inline Node *CountedLoopNode::incr() const { return loopexit_or_null() ? loopexit()->incr() : NULL; }
|
||||
inline Node *CountedLoopNode::phi() const { return loopexit_or_null() ? loopexit()->phi() : NULL; }
|
||||
|
||||
inline Node* CountedLoopNode::init_trip() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL ? cle->init_trip() : NULL;
|
||||
}
|
||||
inline Node* CountedLoopNode::stride() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL ? cle->stride() : NULL;
|
||||
}
|
||||
inline int CountedLoopNode::stride_con() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL ? cle->stride_con() : 0;
|
||||
}
|
||||
inline bool CountedLoopNode::stride_is_con() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL && cle->stride_is_con();
|
||||
}
|
||||
inline Node* CountedLoopNode::limit() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL ? cle->limit() : NULL;
|
||||
}
|
||||
inline Node* CountedLoopNode::incr() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL ? cle->incr() : NULL;
|
||||
}
|
||||
inline Node* CountedLoopNode::phi() const {
|
||||
CountedLoopEndNode* cle = loopexit_or_null();
|
||||
return cle != NULL ? cle->phi() : NULL;
|
||||
}
|
||||
|
||||
//------------------------------LoopLimitNode-----------------------------
|
||||
// Counted Loop limit node which represents exact final iterator value:
|
||||
@ -456,9 +479,9 @@ public:
|
||||
IdealLoopTree *_child; // First child in loop tree
|
||||
|
||||
// The head-tail backedge defines the loop.
|
||||
// If tail is NULL then this loop has multiple backedges as part of the
|
||||
// same loop. During cleanup I'll peel off the multiple backedges; merge
|
||||
// them at the loop bottom and flow 1 real backedge into the loop.
|
||||
// If a loop has multiple backedges, this is addressed during cleanup where
|
||||
// we peel off the multiple backedges, merging all edges at the bottom and
|
||||
// ensuring that one proper backedge flow into the loop.
|
||||
Node *_head; // Head of loop
|
||||
Node *_tail; // Tail of loop
|
||||
inline Node *tail(); // Handle lazy update of _tail field
|
||||
@ -487,7 +510,10 @@ public:
|
||||
_safepts(NULL),
|
||||
_required_safept(NULL),
|
||||
_allow_optimizations(true)
|
||||
{ }
|
||||
{
|
||||
precond(_head != NULL);
|
||||
precond(_tail != NULL);
|
||||
}
|
||||
|
||||
// Is 'l' a member of 'this'?
|
||||
bool is_member(const IdealLoopTree *l) const; // Test for nested membership
|
||||
@ -558,10 +584,10 @@ public:
|
||||
bool policy_unswitching( PhaseIdealLoop *phase ) const;
|
||||
|
||||
// Micro-benchmark spamming. Remove empty loops.
|
||||
bool policy_do_remove_empty_loop( PhaseIdealLoop *phase );
|
||||
bool do_remove_empty_loop( PhaseIdealLoop *phase );
|
||||
|
||||
// Convert one iteration loop into normal code.
|
||||
bool policy_do_one_iteration_loop( PhaseIdealLoop *phase );
|
||||
bool do_one_iteration_loop( PhaseIdealLoop *phase );
|
||||
|
||||
// Return TRUE or FALSE if the loop should be peeled or not. Peel if we can
|
||||
// make some loop-invariant test (usually a null-check) happen before the
|
||||
@ -615,9 +641,11 @@ public:
|
||||
// Put loop body on igvn work list
|
||||
void record_for_igvn();
|
||||
|
||||
bool is_loop() { return !_irreducible && _tail && !_tail->is_top(); }
|
||||
bool is_inner() { return is_loop() && _child == NULL; }
|
||||
bool is_counted() { return is_loop() && _head != NULL && _head->is_CountedLoop(); }
|
||||
bool is_root() { return _parent == NULL; }
|
||||
// A proper/reducible loop w/o any (occasional) dead back-edge.
|
||||
bool is_loop() { return !_irreducible && !tail()->is_top(); }
|
||||
bool is_counted() { return is_loop() && _head->is_CountedLoop(); }
|
||||
bool is_innermost() { return is_loop() && _child == NULL; }
|
||||
|
||||
void remove_main_post_loops(CountedLoopNode *cl, PhaseIdealLoop *phase);
|
||||
|
||||
@ -630,13 +658,14 @@ public:
|
||||
};
|
||||
|
||||
// -----------------------------PhaseIdealLoop---------------------------------
|
||||
// Computes the mapping from Nodes to IdealLoopTrees. Organizes IdealLoopTrees into a
|
||||
// loop tree. Drives the loop-based transformations on the ideal graph.
|
||||
// Computes the mapping from Nodes to IdealLoopTrees. Organizes IdealLoopTrees
|
||||
// into a loop tree. Drives the loop-based transformations on the ideal graph.
|
||||
class PhaseIdealLoop : public PhaseTransform {
|
||||
friend class IdealLoopTree;
|
||||
friend class SuperWord;
|
||||
friend class CountedLoopReserveKit;
|
||||
friend class ShenandoahBarrierC2Support;
|
||||
friend class AutoNodeBudget;
|
||||
|
||||
// Pre-computed def-use info
|
||||
PhaseIterGVN &_igvn;
|
||||
@ -731,8 +760,7 @@ private:
|
||||
}
|
||||
Node *dom_lca_for_get_late_ctrl_internal( Node *lca, Node *n, Node *tag );
|
||||
|
||||
// Helper function for directing control inputs away from CFG split
|
||||
// points.
|
||||
// Helper function for directing control inputs away from CFG split points.
|
||||
Node *find_non_split_ctrl( Node *ctrl ) const {
|
||||
if (ctrl != NULL) {
|
||||
if (ctrl->is_MultiBranch()) {
|
||||
@ -883,7 +911,8 @@ private:
|
||||
_igvn(igvn),
|
||||
_verify_me(NULL),
|
||||
_verify_only(true),
|
||||
_dom_lca_tags(arena()) { // Thread::resource_area
|
||||
_dom_lca_tags(arena()), // Thread::resource_area
|
||||
_nodes_required(UINT_MAX) {
|
||||
build_and_optimize(LoopOptsVerify);
|
||||
}
|
||||
|
||||
@ -899,7 +928,8 @@ private:
|
||||
_igvn(igvn),
|
||||
_verify_me(NULL),
|
||||
_verify_only(false),
|
||||
_dom_lca_tags(arena()) { // Thread::resource_area
|
||||
_dom_lca_tags(arena()), // Thread::resource_area
|
||||
_nodes_required(UINT_MAX) {
|
||||
build_and_optimize(mode);
|
||||
}
|
||||
|
||||
@ -909,7 +939,8 @@ private:
|
||||
_igvn(igvn),
|
||||
_verify_me(verify_me),
|
||||
_verify_only(false),
|
||||
_dom_lca_tags(arena()) { // Thread::resource_area
|
||||
_dom_lca_tags(arena()), // Thread::resource_area
|
||||
_nodes_required(UINT_MAX) {
|
||||
build_and_optimize(LoopOptsVerify);
|
||||
}
|
||||
|
||||
@ -1320,8 +1351,54 @@ private:
|
||||
return C->live_nodes() > threshold;
|
||||
}
|
||||
|
||||
// A simplistic node request tracking mechanism, where
|
||||
// = UINT_MAX Request not valid or made final.
|
||||
// < UINT_MAX Nodes currently requested (estimate).
|
||||
uint _nodes_required;
|
||||
|
||||
bool exceeding_node_budget(uint required = 0) {
|
||||
assert(C->live_nodes() < C->max_node_limit(), "sanity");
|
||||
uint available = C->max_node_limit() - C->live_nodes();
|
||||
return available < required + _nodes_required;
|
||||
}
|
||||
|
||||
uint require_nodes(uint require) {
|
||||
precond(require > 0);
|
||||
_nodes_required += MAX2(100u, require); // Keep requests at minimum 100.
|
||||
return _nodes_required;
|
||||
}
|
||||
|
||||
bool may_require_nodes(uint require) {
|
||||
return !exceeding_node_budget(require) && require_nodes(require) > 0;
|
||||
}
|
||||
|
||||
void require_nodes_begin() {
|
||||
assert(_nodes_required == UINT_MAX, "Bad state (begin).");
|
||||
_nodes_required = 0;
|
||||
}
|
||||
|
||||
// Final check that the requested nodes did not exceed the limit and that
|
||||
// the request was reasonably correct with respect to the number of new
|
||||
// nodes introduced by any transform since the last 'begin'.
|
||||
void require_nodes_final_check(uint live_at_begin) {
|
||||
uint required = _nodes_required;
|
||||
require_nodes_final();
|
||||
uint delta = C->live_nodes() - live_at_begin;
|
||||
assert(delta <= 2 * required, "Bad node estimate (actual: %d, request: %d)",
|
||||
delta, required);
|
||||
}
|
||||
|
||||
void require_nodes_final() {
|
||||
assert(_nodes_required < UINT_MAX, "Bad state (final).");
|
||||
assert(!exceeding_node_budget(), "Too many NODES required!");
|
||||
_nodes_required = UINT_MAX;
|
||||
}
|
||||
|
||||
bool _created_loop_node;
|
||||
|
||||
public:
|
||||
uint nodes_required() const { return _nodes_required; }
|
||||
|
||||
void set_created_loop_node() { _created_loop_node = true; }
|
||||
bool created_loop_node() { return _created_loop_node; }
|
||||
void register_new_node( Node *n, Node *blk );
|
||||
@ -1347,6 +1424,62 @@ public:
|
||||
void rpo( Node *start, Node_Stack &stk, VectorSet &visited, Node_List &rpo_list ) const;
|
||||
};
|
||||
|
||||
|
||||
class AutoNodeBudget : public StackObj
|
||||
{
|
||||
public:
|
||||
enum budget_check_t { BUDGET_CHECK, NO_BUDGET_CHECK };
|
||||
|
||||
AutoNodeBudget(PhaseIdealLoop* phase, budget_check_t chk = BUDGET_CHECK)
|
||||
: _phase(phase),
|
||||
_check_at_final(chk == BUDGET_CHECK),
|
||||
_nodes_at_begin(0)
|
||||
{
|
||||
precond(_phase != NULL);
|
||||
|
||||
_nodes_at_begin = _phase->C->live_nodes();
|
||||
_phase->require_nodes_begin();
|
||||
}
|
||||
|
||||
~AutoNodeBudget() {
|
||||
if (_check_at_final) {
|
||||
#ifndef PRODUCT
|
||||
if (TraceLoopOpts) {
|
||||
uint request = _phase->nodes_required();
|
||||
|
||||
if (request > 0) {
|
||||
uint delta = _phase->C->live_nodes() - _nodes_at_begin;
|
||||
|
||||
if (request < delta) {
|
||||
tty->print_cr("Exceeding node budget: %d < %d", request, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
_phase->require_nodes_final_check(_nodes_at_begin);
|
||||
} else {
|
||||
_phase->require_nodes_final();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
PhaseIdealLoop* _phase;
|
||||
bool _check_at_final;
|
||||
uint _nodes_at_begin;
|
||||
};
|
||||
|
||||
// The Estimated Loop Clone Size: CloneFactor * (BodySize + BC) + CC, where BC
|
||||
// and CC are totally ad-hoc/magic "body" and "clone" constants, respectively,
|
||||
// used to ensure that node usage estimates made are on the safe side, for the
|
||||
// most part.
|
||||
static inline uint est_loop_clone_sz(uint fact, uint size) {
|
||||
uint const bc = 31;
|
||||
uint const cc = 41;
|
||||
uint estimate = fact * (size + bc) + cc;
|
||||
return (estimate - cc) / fact == size + bc ? estimate : UINT_MAX;
|
||||
}
|
||||
|
||||
|
||||
// This kit may be used for making of a reserved copy of a loop before this loop
|
||||
// goes under non-reversible changes.
|
||||
//
|
||||
@ -1410,14 +1543,11 @@ class CountedLoopReserveKit {
|
||||
};// class CountedLoopReserveKit
|
||||
|
||||
inline Node* IdealLoopTree::tail() {
|
||||
// Handle lazy update of _tail field
|
||||
Node *n = _tail;
|
||||
//while( !n->in(0) ) // Skip dead CFG nodes
|
||||
//n = n->in(1);
|
||||
if (n->in(0) == NULL)
|
||||
n = _phase->get_ctrl(n);
|
||||
_tail = n;
|
||||
return n;
|
||||
// Handle lazy update of _tail field.
|
||||
if (_tail->in(0) == NULL) {
|
||||
_tail = _phase->get_ctrl(_tail);
|
||||
}
|
||||
return _tail;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2662,7 +2662,7 @@ int PhaseIdealLoop::clone_for_use_outside_loop( IdealLoopTree *loop, Node* n, No
|
||||
assert(!loop->is_member(get_loop(use_c)), "should be outside loop");
|
||||
get_loop(use_c)->_body.push(n_clone);
|
||||
_igvn.register_new_node_with_optimizer(n_clone);
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("loop exit cloning old: %d new: %d newbb: %d", n->_idx, n_clone->_idx, get_ctrl(n_clone)->_idx);
|
||||
}
|
||||
@ -2700,7 +2700,7 @@ void PhaseIdealLoop::clone_for_special_use_inside_loop( IdealLoopTree *loop, Nod
|
||||
set_ctrl(n_clone, get_ctrl(n));
|
||||
sink_list.push(n_clone);
|
||||
not_peel <<= n_clone->_idx; // add n_clone to not_peel set.
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("special not_peeled cloning old: %d new: %d", n->_idx, n_clone->_idx);
|
||||
}
|
||||
@ -3046,7 +3046,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
opc == Op_CatchProj ||
|
||||
opc == Op_Jump ||
|
||||
opc == Op_JumpProj) {
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("\nExit control too complex: lp: %d", head->_idx);
|
||||
}
|
||||
@ -3102,7 +3102,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TraceLoopOpts) {
|
||||
tty->print("PartialPeel ");
|
||||
loop->dump_head();
|
||||
@ -3131,6 +3131,10 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
Node_List worklist(area);
|
||||
Node_List sink_list(area);
|
||||
|
||||
if (!may_require_nodes(est_loop_clone_sz(2, loop->_body.size()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set of cfg nodes to peel are those that are executable from
|
||||
// the head through last_peel.
|
||||
assert(worklist.size() == 0, "should be empty");
|
||||
@ -3179,7 +3183,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
if (use->is_Phi()) old_phi_cnt++;
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("\npeeled list");
|
||||
}
|
||||
@ -3190,7 +3194,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
uint cloned_for_outside_use = 0;
|
||||
for (i = 0; i < peel_list.size();) {
|
||||
Node* n = peel_list.at(i);
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) n->dump();
|
||||
#endif
|
||||
bool incr = true;
|
||||
@ -3212,7 +3216,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
not_peel <<= n->_idx; // add n to not_peel set.
|
||||
peel_list.remove(i);
|
||||
incr = false;
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("sink to not_peeled region: %d newbb: %d",
|
||||
n->_idx, get_ctrl(n)->_idx);
|
||||
@ -3231,7 +3235,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
}
|
||||
|
||||
if (new_phi_cnt > old_phi_cnt + PartialPeelNewPhiDelta) {
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("\nToo many new phis: %d old %d new cmpi: %c",
|
||||
new_phi_cnt, old_phi_cnt, new_peel_if != NULL?'T':'F');
|
||||
@ -3389,7 +3393,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
|
||||
C->set_major_progress();
|
||||
loop->record_for_igvn();
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
#ifndef PRODUCT
|
||||
if (TracePartialPeeling) {
|
||||
tty->print_cr("\nafter partial peel one iteration");
|
||||
Node_List wl(area);
|
||||
@ -3429,10 +3433,10 @@ void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) {
|
||||
Node *exit = cle->proj_out(false);
|
||||
Node *phi = cl->phi();
|
||||
|
||||
// Check for the special case of folks using the pre-incremented
|
||||
// trip-counter on the fall-out path (forces the pre-incremented
|
||||
// and post-incremented trip counter to be live at the same time).
|
||||
// Fix this by adjusting to use the post-increment trip counter.
|
||||
// Check for the special case when using the pre-incremented trip-counter on
|
||||
// the fall-out path (forces the pre-incremented and post-incremented trip
|
||||
// counter to be live at the same time). Fix this by adjusting to use the
|
||||
// post-increment trip counter.
|
||||
|
||||
bool progress = true;
|
||||
while (progress) {
|
||||
|
@ -1047,11 +1047,11 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
|
||||
// Try harder before giving up. Unify base pointers with casts (e.g., raw/non-raw pointers).
|
||||
intptr_t st_off = 0;
|
||||
Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_off);
|
||||
if (ld_base == NULL) return NULL;
|
||||
if (st_base == NULL) return NULL;
|
||||
if (ld_base->uncast() != st_base->uncast()) return NULL;
|
||||
if (ld_off != st_off) return NULL;
|
||||
if (ld_off == Type::OffsetBot) return NULL;
|
||||
if (ld_base == NULL) return NULL;
|
||||
if (st_base == NULL) return NULL;
|
||||
if (!ld_base->eqv_uncast(st_base, /*keep_deps=*/true)) return NULL;
|
||||
if (ld_off != st_off) return NULL;
|
||||
if (ld_off == Type::OffsetBot) return NULL;
|
||||
// Same base, same offset.
|
||||
// Possible improvement for arrays: check index value instead of absolute offset.
|
||||
|
||||
@ -1062,6 +1062,7 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
|
||||
// (Actually, we haven't yet proven the Q's are the same.)
|
||||
// In other words, we are loading from a casted version of
|
||||
// the same pointer-and-offset that we stored to.
|
||||
// Casted version may carry a dependency and it is respected.
|
||||
// Thus, we are able to replace L by V.
|
||||
}
|
||||
// Now prove that we have a LoadQ matched to a StoreQ, for some Q.
|
||||
|
@ -891,13 +891,15 @@ int Node::disconnect_inputs(Node *n, Compile* C) {
|
||||
//-----------------------------uncast---------------------------------------
|
||||
// %%% Temporary, until we sort out CheckCastPP vs. CastPP.
|
||||
// Strip away casting. (It is depth-limited.)
|
||||
Node* Node::uncast() const {
|
||||
// Optionally, keep casts with dependencies.
|
||||
Node* Node::uncast(bool keep_deps) const {
|
||||
// Should be inline:
|
||||
//return is_ConstraintCast() ? uncast_helper(this) : (Node*) this;
|
||||
if (is_ConstraintCast())
|
||||
return uncast_helper(this);
|
||||
else
|
||||
if (is_ConstraintCast()) {
|
||||
return uncast_helper(this, keep_deps);
|
||||
} else {
|
||||
return (Node*) this;
|
||||
}
|
||||
}
|
||||
|
||||
// Find out of current node that matches opcode.
|
||||
@ -929,7 +931,7 @@ bool Node::has_out_with(int opcode1, int opcode2, int opcode3, int opcode4) {
|
||||
|
||||
|
||||
//---------------------------uncast_helper-------------------------------------
|
||||
Node* Node::uncast_helper(const Node* p) {
|
||||
Node* Node::uncast_helper(const Node* p, bool keep_deps) {
|
||||
#ifdef ASSERT
|
||||
uint depth_count = 0;
|
||||
const Node* orig_p = p;
|
||||
@ -947,6 +949,9 @@ Node* Node::uncast_helper(const Node* p) {
|
||||
if (p == NULL || p->req() != 2) {
|
||||
break;
|
||||
} else if (p->is_ConstraintCast()) {
|
||||
if (keep_deps && p->as_ConstraintCast()->carry_dependency()) {
|
||||
break; // stop at casts with dependencies
|
||||
}
|
||||
p = p->in(1);
|
||||
} else {
|
||||
break;
|
||||
|
@ -456,10 +456,10 @@ protected:
|
||||
void setup_is_top();
|
||||
|
||||
// Strip away casting. (It is depth-limited.)
|
||||
Node* uncast() const;
|
||||
Node* uncast(bool keep_deps = false) const;
|
||||
// Return whether two Nodes are equivalent, after stripping casting.
|
||||
bool eqv_uncast(const Node* n) const {
|
||||
return (this->uncast() == n->uncast());
|
||||
bool eqv_uncast(const Node* n, bool keep_deps = false) const {
|
||||
return (this->uncast(keep_deps) == n->uncast(keep_deps));
|
||||
}
|
||||
|
||||
// Find out of current node that matches opcode.
|
||||
@ -470,7 +470,7 @@ protected:
|
||||
bool has_out_with(int opcode1, int opcode2, int opcode3, int opcode4);
|
||||
|
||||
private:
|
||||
static Node* uncast_helper(const Node* n);
|
||||
static Node* uncast_helper(const Node* n, bool keep_deps);
|
||||
|
||||
// Add an output edge to the end of the list
|
||||
void add_out( Node *n ) {
|
||||
@ -1007,9 +1007,9 @@ public:
|
||||
// value, if it appears (by local graph inspection) to be computed by a simple conditional.
|
||||
bool is_iteratively_computed();
|
||||
|
||||
// Determine if a node is Counted loop induction variable.
|
||||
// The method is defined in loopnode.cpp.
|
||||
const Node* is_loop_iv() const;
|
||||
// Determine if a node is a counted loop induction variable.
|
||||
// NOTE: The method is defined in "loopnode.cpp".
|
||||
bool is_cloop_ind_var() const;
|
||||
|
||||
// Return a node with opcode "opc" and same inputs as "this" if one can
|
||||
// be found; Otherwise return NULL;
|
||||
|
@ -88,6 +88,10 @@ protected:
|
||||
ciMethod* caller_method,
|
||||
JVMState* jvms,
|
||||
WarmCallInfo* wci_result);
|
||||
bool is_not_reached(ciMethod* callee_method,
|
||||
ciMethod* caller_method,
|
||||
int caller_bci,
|
||||
ciCallProfile& profile);
|
||||
void print_inlining(ciMethod* callee_method, int caller_bci,
|
||||
ciMethod* caller_method, bool success) const;
|
||||
|
||||
|
@ -114,31 +114,37 @@ const Type* SubNode::Value(PhaseGVN* phase) const {
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
|
||||
//------------------------------Helper function--------------------------------
|
||||
static bool ok_to_convert(Node* inc, Node* iv) {
|
||||
// Do not collapse (x+c0)-y if "+" is a loop increment, because the
|
||||
// "-" is loop invariant and collapsing extends the live-range of "x"
|
||||
// to overlap with the "+", forcing another register to be used in
|
||||
// the loop.
|
||||
// This test will be clearer with '&&' (apply DeMorgan's rule)
|
||||
// but I like the early cutouts that happen here.
|
||||
const PhiNode *phi;
|
||||
if( ( !inc->in(1)->is_Phi() ||
|
||||
!(phi=inc->in(1)->as_Phi()) ||
|
||||
phi->is_copy() ||
|
||||
!phi->region()->is_CountedLoop() ||
|
||||
inc != phi->region()->as_CountedLoop()->incr() )
|
||||
&&
|
||||
// Do not collapse (x+c0)-iv if "iv" is a loop induction variable,
|
||||
// because "x" maybe invariant.
|
||||
( !iv->is_loop_iv() )
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_cloop_increment(Node* inc) {
|
||||
precond(inc->Opcode() == Op_AddI || inc->Opcode() == Op_AddL);
|
||||
|
||||
if (!inc->in(1)->is_Phi()) {
|
||||
return false;
|
||||
}
|
||||
const PhiNode* phi = inc->in(1)->as_Phi();
|
||||
|
||||
if (phi->is_copy() || !phi->region()->is_CountedLoop()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return inc == phi->region()->as_CountedLoop()->incr();
|
||||
}
|
||||
|
||||
// Given the expression '(x + C) - v', or
|
||||
// 'v - (x + C)', we examine nodes '+' and 'v':
|
||||
//
|
||||
// 1. Do not convert if '+' is a counted-loop increment, because the '-' is
|
||||
// loop invariant and converting extends the live-range of 'x' to overlap
|
||||
// with the '+', forcing another register to be used in the loop.
|
||||
//
|
||||
// 2. Do not convert if 'v' is a counted-loop induction variable, because
|
||||
// 'x' might be invariant.
|
||||
//
|
||||
static bool ok_to_convert(Node* inc, Node* var) {
|
||||
return !(is_cloop_increment(inc) || var->is_cloop_ind_var());
|
||||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||
Node *in1 = in(1);
|
||||
|
@ -145,7 +145,7 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) {
|
||||
// Skip any loops already optimized by slp
|
||||
if (cl->is_vectorized_loop()) return;
|
||||
|
||||
if (cl->do_unroll_only()) return;
|
||||
if (cl->is_unroll_only()) return;
|
||||
|
||||
if (cl->is_main_loop()) {
|
||||
// Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))
|
||||
|
@ -254,7 +254,7 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
|
||||
return _tag_map;
|
||||
}
|
||||
|
||||
JvmtiTagMap* acquire_tag_map() {
|
||||
JvmtiTagMap* tag_map_acquire() {
|
||||
return OrderAccess::load_acquire(&_tag_map);
|
||||
}
|
||||
|
||||
|
@ -514,7 +514,7 @@ void JvmtiTagMap::destroy_entry(JvmtiTagHashmapEntry* entry) {
|
||||
// returns the tag map for the given environments. If the tag map
|
||||
// doesn't exist then it is created.
|
||||
JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) {
|
||||
JvmtiTagMap* tag_map = ((JvmtiEnvBase*)env)->acquire_tag_map();
|
||||
JvmtiTagMap* tag_map = ((JvmtiEnvBase*)env)->tag_map_acquire();
|
||||
if (tag_map == NULL) {
|
||||
MutexLocker mu(JvmtiThreadState_lock);
|
||||
tag_map = ((JvmtiEnvBase*)env)->tag_map();
|
||||
@ -3318,7 +3318,7 @@ void JvmtiTagMap::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
if (JvmtiEnv::environments_might_exist()) {
|
||||
JvmtiEnvIterator it;
|
||||
for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) {
|
||||
JvmtiTagMap* tag_map = env->acquire_tag_map();
|
||||
JvmtiTagMap* tag_map = env->tag_map_acquire();
|
||||
if (tag_map != NULL && !tag_map->is_empty()) {
|
||||
tag_map->do_weak_oops(is_alive, f);
|
||||
}
|
||||
|
@ -1080,6 +1080,24 @@ WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring
|
||||
return result;
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(void, WB_MarkMethodProfiled(JNIEnv* env, jobject o, jobject method))
|
||||
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
||||
CHECK_JNI_EXCEPTION(env);
|
||||
methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
|
||||
|
||||
MethodData* mdo = mh->method_data();
|
||||
if (mdo == NULL) {
|
||||
Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR);
|
||||
mdo = mh->method_data();
|
||||
}
|
||||
mdo->init();
|
||||
InvocationCounter* icnt = mdo->invocation_counter();
|
||||
InvocationCounter* bcnt = mdo->backedge_counter();
|
||||
// set i-counter according to TieredThresholdPolicy::is_method_profiled
|
||||
icnt->set(InvocationCounter::wait_for_compile, Tier4MinInvocationThreshold);
|
||||
bcnt->set(InvocationCounter::wait_for_compile, Tier4CompileThreshold);
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
||||
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
||||
CHECK_JNI_EXCEPTION(env);
|
||||
@ -2209,6 +2227,8 @@ static JNINativeMethod methods[] = {
|
||||
CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation},
|
||||
{CC"enqueueInitializerForCompilation0",
|
||||
CC"(Ljava/lang/Class;I)Z", (void*)&WB_EnqueueInitializerForCompilation},
|
||||
{CC"markMethodProfiled",
|
||||
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_MarkMethodProfiled},
|
||||
{CC"clearMethodState0",
|
||||
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
|
||||
{CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation},
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -499,6 +499,7 @@ protected:
|
||||
JavaThread* _requesting_thread;
|
||||
BiasedLocking::Condition _status_code;
|
||||
traceid _biased_locker_id;
|
||||
uint64_t _safepoint_id;
|
||||
|
||||
public:
|
||||
VM_RevokeBias(Handle* obj, JavaThread* requesting_thread)
|
||||
@ -506,14 +507,16 @@ public:
|
||||
, _objs(NULL)
|
||||
, _requesting_thread(requesting_thread)
|
||||
, _status_code(BiasedLocking::NOT_BIASED)
|
||||
, _biased_locker_id(0) {}
|
||||
, _biased_locker_id(0)
|
||||
, _safepoint_id(0) {}
|
||||
|
||||
VM_RevokeBias(GrowableArray<Handle>* objs, JavaThread* requesting_thread)
|
||||
: _obj(NULL)
|
||||
, _objs(objs)
|
||||
, _requesting_thread(requesting_thread)
|
||||
, _status_code(BiasedLocking::NOT_BIASED)
|
||||
, _biased_locker_id(0) {}
|
||||
, _biased_locker_id(0)
|
||||
, _safepoint_id(0) {}
|
||||
|
||||
virtual VMOp_Type type() const { return VMOp_RevokeBias; }
|
||||
|
||||
@ -545,6 +548,7 @@ public:
|
||||
if (biased_locker != NULL) {
|
||||
_biased_locker_id = JFR_THREAD_ID(biased_locker);
|
||||
}
|
||||
_safepoint_id = SafepointSynchronize::safepoint_counter();
|
||||
clean_up_cached_monitor_info();
|
||||
return;
|
||||
} else {
|
||||
@ -560,6 +564,10 @@ public:
|
||||
traceid biased_locker() const {
|
||||
return _biased_locker_id;
|
||||
}
|
||||
|
||||
uint64_t safepoint_id() const {
|
||||
return _safepoint_id;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -581,16 +589,14 @@ public:
|
||||
|
||||
virtual void doit() {
|
||||
_status_code = bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread);
|
||||
_safepoint_id = SafepointSynchronize::safepoint_counter();
|
||||
clean_up_cached_monitor_info();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename E>
|
||||
static void set_safepoint_id(E* event) {
|
||||
assert(event != NULL, "invariant");
|
||||
// Subtract 1 to match the id of events committed inside the safepoint
|
||||
event->set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
|
||||
}
|
||||
bool is_bulk_rebias() const {
|
||||
return _bulk_rebias;
|
||||
}
|
||||
};
|
||||
|
||||
static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Klass* k) {
|
||||
assert(event != NULL, "invariant");
|
||||
@ -600,24 +606,25 @@ static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Kla
|
||||
event->commit();
|
||||
}
|
||||
|
||||
static void post_revocation_event(EventBiasedLockRevocation* event, Klass* k, VM_RevokeBias* revoke) {
|
||||
static void post_revocation_event(EventBiasedLockRevocation* event, Klass* k, VM_RevokeBias* op) {
|
||||
assert(event != NULL, "invariant");
|
||||
assert(k != NULL, "invariant");
|
||||
assert(revoke != NULL, "invariant");
|
||||
assert(op != NULL, "invariant");
|
||||
assert(event->should_commit(), "invariant");
|
||||
event->set_lockClass(k);
|
||||
set_safepoint_id(event);
|
||||
event->set_previousOwner(revoke->biased_locker());
|
||||
event->set_safepointId(op->safepoint_id());
|
||||
event->set_previousOwner(op->biased_locker());
|
||||
event->commit();
|
||||
}
|
||||
|
||||
static void post_class_revocation_event(EventBiasedLockClassRevocation* event, Klass* k, bool disabled_bias) {
|
||||
static void post_class_revocation_event(EventBiasedLockClassRevocation* event, Klass* k, VM_BulkRevokeBias* op) {
|
||||
assert(event != NULL, "invariant");
|
||||
assert(k != NULL, "invariant");
|
||||
assert(op != NULL, "invariant");
|
||||
assert(event->should_commit(), "invariant");
|
||||
event->set_revokedClass(k);
|
||||
event->set_disableBiasing(disabled_bias);
|
||||
set_safepoint_id(event);
|
||||
event->set_disableBiasing(!op->is_bulk_rebias());
|
||||
event->set_safepointId(op->safepoint_id());
|
||||
event->commit();
|
||||
}
|
||||
|
||||
@ -729,7 +736,7 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem
|
||||
attempt_rebias);
|
||||
VMThread::execute(&bulk_revoke);
|
||||
if (event.should_commit()) {
|
||||
post_class_revocation_event(&event, obj->klass(), heuristics != HR_BULK_REBIAS);
|
||||
post_class_revocation_event(&event, obj->klass(), &bulk_revoke);
|
||||
}
|
||||
return bulk_revoke.status_code();
|
||||
}
|
||||
|
@ -674,8 +674,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m
|
||||
int top_frame_expression_stack_adjustment = 0;
|
||||
methodHandle mh(thread, iframe->interpreter_frame_method());
|
||||
OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask);
|
||||
BytecodeStream str(mh);
|
||||
str.set_start(iframe->interpreter_frame_bci());
|
||||
BytecodeStream str(mh, iframe->interpreter_frame_bci());
|
||||
int max_bci = mh->code_size();
|
||||
// Get to the next bytecode if possible
|
||||
assert(str.bci() < max_bci, "bci in interpreter frame out of bounds");
|
||||
|
@ -526,11 +526,31 @@ void vm_exit(int code) {
|
||||
vm_direct_exit(code);
|
||||
}
|
||||
|
||||
// We'd like to add an entry to the XML log to show that the VM is
|
||||
// terminating, but we can't safely do that here. The logic to make
|
||||
// XML termination logging safe is tied to the termination of the
|
||||
// VMThread, and it doesn't terminate on this exit path. See 8222534.
|
||||
|
||||
if (VMThread::vm_thread() != NULL) {
|
||||
if (thread->is_Java_thread()) {
|
||||
// We must be "in_vm" for the code below to work correctly.
|
||||
// Historically there must have been some exit path for which
|
||||
// that was not the case and so we set it explicitly - even
|
||||
// though we no longer know what that path may be.
|
||||
((JavaThread*)thread)->set_thread_state(_thread_in_vm);
|
||||
}
|
||||
|
||||
// Fire off a VM_Exit operation to bring VM to a safepoint and exit
|
||||
VM_Exit op(code);
|
||||
if (thread->is_Java_thread())
|
||||
((JavaThread*)thread)->set_thread_state(_thread_in_vm);
|
||||
|
||||
// 4945125 The vm thread comes to a safepoint during exit.
|
||||
// GC vm_operations can get caught at the safepoint, and the
|
||||
// heap is unparseable if they are caught. Grab the Heap_lock
|
||||
// to prevent this. The GC vm_operations will not be able to
|
||||
// queue until after we release it, but we never do that as we
|
||||
// are terminating the VM process.
|
||||
MutexLocker ml(Heap_lock);
|
||||
|
||||
VMThread::execute(&op);
|
||||
// should never reach here; but in case something wrong with VM Thread.
|
||||
vm_direct_exit(code);
|
||||
|
@ -1926,3 +1926,11 @@ void ObjectMonitor::Initialize() {
|
||||
|
||||
DEBUG_ONLY(InitDone = true;)
|
||||
}
|
||||
|
||||
void ObjectMonitor::print_on(outputStream* st) const {
|
||||
// The minimal things to print for markOop printing, more can be added for debugging and logging.
|
||||
st->print("{contentions=0x%08x,waiters=0x%08x"
|
||||
",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}",
|
||||
contentions(), waiters(), recursions(),
|
||||
p2i(owner()));
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ class ObjectMonitor {
|
||||
friend class ObjectSynchronizer;
|
||||
friend class ObjectWaiter;
|
||||
friend class VMStructs;
|
||||
JVMCI_ONLY(friend class JVMCIVMStructs;)
|
||||
|
||||
volatile markOop _header; // displaced object header word - mark
|
||||
void* volatile _object; // backward object pointer - strong root
|
||||
@ -291,6 +292,9 @@ class ObjectMonitor {
|
||||
void notify(TRAPS);
|
||||
void notifyAll(TRAPS);
|
||||
|
||||
void print() const { print_on(tty); }
|
||||
void print_on(outputStream* st) const;
|
||||
|
||||
// Use the following at your own risk
|
||||
intptr_t complete_exit(TRAPS);
|
||||
void reenter(intptr_t recursions, TRAPS);
|
||||
|
@ -1575,18 +1575,15 @@ bool jvmci_counters_include(JavaThread* thread) {
|
||||
return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread();
|
||||
}
|
||||
|
||||
void JavaThread::collect_counters(JVMCIEnv* jvmci_env, JVMCIPrimitiveArray array) {
|
||||
if (JVMCICounterSize > 0) {
|
||||
JavaThreadIteratorWithHandle jtiwh;
|
||||
int len = jvmci_env->get_length(array);
|
||||
for (int i = 0; i < len; i++) {
|
||||
jvmci_env->put_long_at(array, i, _jvmci_old_thread_counters[i]);
|
||||
}
|
||||
for (; JavaThread *tp = jtiwh.next(); ) {
|
||||
if (jvmci_counters_include(tp)) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
jvmci_env->put_long_at(array, i, jvmci_env->get_long_at(array, i) + tp->_jvmci_counters[i]);
|
||||
}
|
||||
void JavaThread::collect_counters(jlong* array, int length) {
|
||||
assert(length == JVMCICounterSize, "wrong value");
|
||||
for (int i = 0; i < length; i++) {
|
||||
array[i] = _jvmci_old_thread_counters[i];
|
||||
}
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) {
|
||||
if (jvmci_counters_include(tp)) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
array[i] += tp->_jvmci_counters[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1152,7 +1152,7 @@ class JavaThread: public Thread {
|
||||
|
||||
public:
|
||||
static jlong* _jvmci_old_thread_counters;
|
||||
static void collect_counters(JVMCIEnv* JVMCIENV, JVMCIPrimitiveArray array);
|
||||
static void collect_counters(jlong* array, int length);
|
||||
private:
|
||||
#endif // INCLUDE_JVMCI
|
||||
|
||||
|
@ -353,6 +353,16 @@ CompileTask* TieredThresholdPolicy::select_task(CompileQueue* compile_queue) {
|
||||
TieredStopAtLevel > CompLevel_full_profile &&
|
||||
max_method != NULL && is_method_profiled(max_method)) {
|
||||
max_task->set_comp_level(CompLevel_limited_profile);
|
||||
|
||||
if (CompileBroker::compilation_is_complete(max_method, max_task->osr_bci(), CompLevel_limited_profile)) {
|
||||
if (PrintTieredEvents) {
|
||||
print_event(REMOVE_FROM_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
|
||||
}
|
||||
compile_queue->remove_and_mark_stale(max_task);
|
||||
max_method->clear_queued_for_compilation();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PrintTieredEvents) {
|
||||
print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "gc/shared/isGCActiveMark.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
@ -437,14 +438,14 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
|
||||
if (thr->is_Compiler_thread()) {
|
||||
#if INCLUDE_JVMCI
|
||||
CompilerThread* ct = (CompilerThread*) thr;
|
||||
if (ct->compiler() == NULL || !ct->compiler()->is_jvmci() || !UseJVMCINativeLibrary) {
|
||||
if (ct->compiler() == NULL || !ct->compiler()->is_jvmci()) {
|
||||
num_active_compiler_thread++;
|
||||
} else {
|
||||
// When using a compiler in a JVMCI shared library, it's possible
|
||||
// for one compiler thread to grab a lock in the shared library,
|
||||
// enter HotSpot and go to sleep on the shutdown safepoint. Another
|
||||
// JVMCI shared library compiler thread can then attempt to grab the
|
||||
// lock and thus never make progress.
|
||||
// A JVMCI compiler thread never accesses VM data structures
|
||||
// while in _thread_in_native state so there's no need to wait
|
||||
// for it and potentially add a 300 millisecond delay to VM
|
||||
// shutdown.
|
||||
num_active--;
|
||||
}
|
||||
#else
|
||||
num_active_compiler_thread++;
|
||||
@ -469,6 +470,16 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
|
||||
}
|
||||
|
||||
void VM_Exit::doit() {
|
||||
|
||||
if (VerifyBeforeExit) {
|
||||
HandleMark hm(VMThread::vm_thread());
|
||||
// Among other things, this ensures that Eden top is correct.
|
||||
Universe::heap()->prepare_for_verify();
|
||||
// Silent verification so as not to pollute normal output,
|
||||
// unless we really asked for it.
|
||||
Universe::verify();
|
||||
}
|
||||
|
||||
CompileBroker::set_should_block();
|
||||
|
||||
// Wait for a short period for threads in native to block. Any thread
|
||||
@ -480,10 +491,17 @@ void VM_Exit::doit() {
|
||||
|
||||
set_vm_exited();
|
||||
|
||||
// We'd like to call IdealGraphPrinter::clean_up() to finalize the
|
||||
// XML logging, but we can't safely do that here. The logic to make
|
||||
// XML termination logging safe is tied to the termination of the
|
||||
// VMThread, and it doesn't terminate on this exit path. See 8222534.
|
||||
|
||||
// cleanup globals resources before exiting. exit_globals() currently
|
||||
// cleans up outputStream resources and PerfMemory resources.
|
||||
exit_globals();
|
||||
|
||||
LogConfiguration::finalize();
|
||||
|
||||
// Check for exit hook
|
||||
exit_hook_t exit_hook = Arguments::exit_hook();
|
||||
if (exit_hook != NULL) {
|
||||
|
@ -63,6 +63,9 @@ do { \
|
||||
// For backward compatibility.
|
||||
#define assert(p, ...) vmassert(p, __VA_ARGS__)
|
||||
|
||||
#define precond(p) assert(p, "precond")
|
||||
#define postcond(p) assert(p, "postcond")
|
||||
|
||||
#ifndef ASSERT
|
||||
#define vmassert_status(p, status, msg)
|
||||
#else
|
||||
|
@ -75,7 +75,7 @@ import static java.util.function.Predicate.not;
|
||||
* System.out.println("abc");
|
||||
* String cde = "cde";
|
||||
* System.out.println("abc" + cde);
|
||||
* String c = "abc".substring(2,3);
|
||||
* String c = "abc".substring(2, 3);
|
||||
* String d = cde.substring(1, 2);
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
@ -2160,27 +2160,48 @@ public final class String
|
||||
* @since 1.5
|
||||
*/
|
||||
public String replace(CharSequence target, CharSequence replacement) {
|
||||
String tgtStr = target.toString();
|
||||
String trgtStr = target.toString();
|
||||
String replStr = replacement.toString();
|
||||
int j = indexOf(tgtStr);
|
||||
if (j < 0) {
|
||||
return this;
|
||||
}
|
||||
int tgtLen = tgtStr.length();
|
||||
int tgtLen1 = Math.max(tgtLen, 1);
|
||||
int thisLen = length();
|
||||
int trgtLen = trgtStr.length();
|
||||
int replLen = replStr.length();
|
||||
|
||||
int newLenHint = thisLen - tgtLen + replStr.length();
|
||||
if (newLenHint < 0) {
|
||||
throw new OutOfMemoryError();
|
||||
if (trgtLen > 0) {
|
||||
if (trgtLen == 1 && replLen == 1) {
|
||||
return replace(trgtStr.charAt(0), replStr.charAt(0));
|
||||
}
|
||||
|
||||
boolean thisIsLatin1 = this.isLatin1();
|
||||
boolean trgtIsLatin1 = trgtStr.isLatin1();
|
||||
boolean replIsLatin1 = replStr.isLatin1();
|
||||
String ret = (thisIsLatin1 && trgtIsLatin1 && replIsLatin1)
|
||||
? StringLatin1.replace(value, thisLen,
|
||||
trgtStr.value, trgtLen,
|
||||
replStr.value, replLen)
|
||||
: StringUTF16.replace(value, thisLen, thisIsLatin1,
|
||||
trgtStr.value, trgtLen, trgtIsLatin1,
|
||||
replStr.value, replLen, replIsLatin1);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
return this;
|
||||
|
||||
} else { // trgtLen == 0
|
||||
int resultLen;
|
||||
try {
|
||||
resultLen = Math.addExact(thisLen, Math.multiplyExact(
|
||||
Math.addExact(thisLen, 1), replLen));
|
||||
} catch (ArithmeticException ignored) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(resultLen);
|
||||
sb.append(replStr);
|
||||
for (int i = 0; i < thisLen; ++i) {
|
||||
sb.append(charAt(i)).append(replStr);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(newLenHint);
|
||||
int i = 0;
|
||||
do {
|
||||
sb.append(this, i, j).append(replStr);
|
||||
i = j + tgtLen;
|
||||
} while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
|
||||
return sb.append(this, i, thisLen).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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
|
||||
@ -42,6 +42,14 @@ import static java.lang.String.checkOffset;
|
||||
|
||||
final class StringLatin1 {
|
||||
|
||||
/**
|
||||
* The maximum size of array to allocate (unless necessary).
|
||||
* Some VMs reserve some header words in an array.
|
||||
* Attempts to allocate larger arrays may result in
|
||||
* OutOfMemoryError: Requested array size exceeds VM limit
|
||||
*/
|
||||
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
||||
|
||||
public static char charAt(byte[] value, int index) {
|
||||
if (index < 0 || index >= value.length) {
|
||||
throw new StringIndexOutOfBoundsException(index);
|
||||
@ -304,7 +312,7 @@ final class StringLatin1 {
|
||||
}
|
||||
if (i < len) {
|
||||
if (canEncode(newChar)) {
|
||||
byte buf[] = new byte[len];
|
||||
byte[] buf = StringConcatHelper.newArray(len);
|
||||
for (int j = 0; j < i; j++) { // TBD arraycopy?
|
||||
buf[j] = value[j];
|
||||
}
|
||||
@ -330,6 +338,64 @@ final class StringLatin1 {
|
||||
return null; // for string to return this;
|
||||
}
|
||||
|
||||
public static String replace(byte[] value, int valLen, byte[] targ,
|
||||
int targLen, byte[] repl, int replLen)
|
||||
{
|
||||
assert targLen > 0;
|
||||
int i, j, p = 0;
|
||||
if (valLen == 0 || (i = indexOf(value, valLen, targ, targLen, 0)) < 0) {
|
||||
return null; // for string to return this;
|
||||
}
|
||||
|
||||
// find and store indices of substrings to replace
|
||||
int[] pos = new int[16];
|
||||
pos[0] = i;
|
||||
i += targLen;
|
||||
while ((j = indexOf(value, valLen, targ, targLen, i)) > 0) {
|
||||
if (++p == pos.length) {
|
||||
int cap = p + (p >> 1);
|
||||
// overflow-conscious code
|
||||
if (cap - MAX_ARRAY_SIZE > 0) {
|
||||
if (p == MAX_ARRAY_SIZE) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
cap = MAX_ARRAY_SIZE;
|
||||
}
|
||||
pos = Arrays.copyOf(pos, cap);
|
||||
}
|
||||
pos[p] = j;
|
||||
i = j + targLen;
|
||||
}
|
||||
|
||||
int resultLen;
|
||||
try {
|
||||
resultLen = Math.addExact(valLen,
|
||||
Math.multiplyExact(++p, replLen - targLen));
|
||||
} catch (ArithmeticException ignored) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
if (resultLen == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
byte[] result = StringConcatHelper.newArray(resultLen);
|
||||
int posFrom = 0, posTo = 0;
|
||||
for (int q = 0; q < p; ++q) {
|
||||
int nextPos = pos[q];
|
||||
while (posFrom < nextPos) {
|
||||
result[posTo++] = value[posFrom++];
|
||||
}
|
||||
posFrom += targLen;
|
||||
for (int k = 0; k < replLen; ++k) {
|
||||
result[posTo++] = repl[k];
|
||||
}
|
||||
}
|
||||
while (posFrom < valLen) {
|
||||
result[posTo++] = value[posFrom++];
|
||||
}
|
||||
return new String(result, LATIN1);
|
||||
}
|
||||
|
||||
// case insensitive
|
||||
public static boolean regionMatchesCI(byte[] value, int toffset,
|
||||
byte[] other, int ooffset, int len) {
|
||||
|
@ -574,7 +574,7 @@ final class StringUTF16 {
|
||||
}
|
||||
}
|
||||
if (i < len) {
|
||||
byte buf[] = new byte[value.length];
|
||||
byte[] buf = new byte[value.length];
|
||||
for (int j = 0; j < i; j++) {
|
||||
putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
|
||||
}
|
||||
@ -582,21 +582,145 @@ final class StringUTF16 {
|
||||
char c = getChar(value, i);
|
||||
putChar(buf, i, c == oldChar ? newChar : c);
|
||||
i++;
|
||||
}
|
||||
// Check if we should try to compress to latin1
|
||||
if (String.COMPACT_STRINGS &&
|
||||
!StringLatin1.canEncode(oldChar) &&
|
||||
StringLatin1.canEncode(newChar)) {
|
||||
byte[] val = compress(buf, 0, len);
|
||||
if (val != null) {
|
||||
return new String(val, LATIN1);
|
||||
}
|
||||
}
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
// Check if we should try to compress to latin1
|
||||
if (String.COMPACT_STRINGS &&
|
||||
!StringLatin1.canEncode(oldChar) &&
|
||||
StringLatin1.canEncode(newChar)) {
|
||||
byte[] val = compress(buf, 0, len);
|
||||
if (val != null) {
|
||||
return new String(val, LATIN1);
|
||||
}
|
||||
}
|
||||
return new String(buf, UTF16);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String replace(byte[] value, int valLen, boolean valLat1,
|
||||
byte[] targ, int targLen, boolean targLat1,
|
||||
byte[] repl, int replLen, boolean replLat1)
|
||||
{
|
||||
assert targLen > 0;
|
||||
assert !valLat1 || !targLat1 || !replLat1;
|
||||
|
||||
// Possible combinations of the arguments/result encodings:
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | # | VALUE | TARGET | REPL | RESULT |
|
||||
// +===+========+========+========+=======================+
|
||||
// | 1 | Latin1 | Latin1 | UTF16 | null or UTF16 |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | 2 | Latin1 | UTF16 | Latin1 | null |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | 3 | Latin1 | UTF16 | UTF16 | null |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | 4 | UTF16 | Latin1 | Latin1 | null or UTF16 |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | 5 | UTF16 | Latin1 | UTF16 | null or UTF16 |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | 6 | UTF16 | UTF16 | Latin1 | null, Latin1 or UTF16 |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
// | 7 | UTF16 | UTF16 | UTF16 | null or UTF16 |
|
||||
// +---+--------+--------+--------+-----------------------+
|
||||
|
||||
if (String.COMPACT_STRINGS && valLat1 && !targLat1) {
|
||||
// combinations 2 or 3
|
||||
return null; // for string to return this;
|
||||
}
|
||||
|
||||
int i = (String.COMPACT_STRINGS && valLat1)
|
||||
? StringLatin1.indexOf(value, targ) :
|
||||
(String.COMPACT_STRINGS && targLat1)
|
||||
? indexOfLatin1(value, targ)
|
||||
: indexOf(value, targ);
|
||||
if (i < 0) {
|
||||
return null; // for string to return this;
|
||||
}
|
||||
|
||||
// find and store indices of substrings to replace
|
||||
int j, p = 0;
|
||||
int[] pos = new int[16];
|
||||
pos[0] = i;
|
||||
i += targLen;
|
||||
while ((j = ((String.COMPACT_STRINGS && valLat1)
|
||||
? StringLatin1.indexOf(value, valLen, targ, targLen, i) :
|
||||
(String.COMPACT_STRINGS && targLat1)
|
||||
? indexOfLatin1(value, valLen, targ, targLen, i)
|
||||
: indexOf(value, valLen, targ, targLen, i))) > 0)
|
||||
{
|
||||
if (++p == pos.length) {
|
||||
int cap = p + (p >> 1);
|
||||
// overflow-conscious code
|
||||
if (cap - MAX_ARRAY_SIZE > 0) {
|
||||
if (p == MAX_ARRAY_SIZE) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
cap = MAX_ARRAY_SIZE;
|
||||
}
|
||||
pos = Arrays.copyOf(pos, cap);
|
||||
}
|
||||
pos[p] = j;
|
||||
i = j + targLen;
|
||||
}
|
||||
|
||||
int resultLen;
|
||||
try {
|
||||
resultLen = Math.addExact(valLen,
|
||||
Math.multiplyExact(++p, replLen - targLen));
|
||||
} catch (ArithmeticException ignored) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
if (resultLen == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
byte[] result = newBytesFor(resultLen);
|
||||
int posFrom = 0, posTo = 0;
|
||||
for (int q = 0; q < p; ++q) {
|
||||
int nextPos = pos[q];
|
||||
if (String.COMPACT_STRINGS && valLat1) {
|
||||
while (posFrom < nextPos) {
|
||||
char c = (char)(value[posFrom++] & 0xff);
|
||||
putChar(result, posTo++, c);
|
||||
}
|
||||
} else {
|
||||
while (posFrom < nextPos) {
|
||||
putChar(result, posTo++, getChar(value, posFrom++));
|
||||
}
|
||||
}
|
||||
posFrom += targLen;
|
||||
if (String.COMPACT_STRINGS && replLat1) {
|
||||
for (int k = 0; k < replLen; ++k) {
|
||||
char c = (char)(repl[k] & 0xff);
|
||||
putChar(result, posTo++, c);
|
||||
}
|
||||
} else {
|
||||
for (int k = 0; k < replLen; ++k) {
|
||||
putChar(result, posTo++, getChar(repl, k));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (String.COMPACT_STRINGS && valLat1) {
|
||||
while (posFrom < valLen) {
|
||||
char c = (char)(value[posFrom++] & 0xff);
|
||||
putChar(result, posTo++, c);
|
||||
}
|
||||
} else {
|
||||
while (posFrom < valLen) {
|
||||
putChar(result, posTo++, getChar(value, posFrom++));
|
||||
}
|
||||
}
|
||||
|
||||
if (String.COMPACT_STRINGS && replLat1 && !targLat1) {
|
||||
// combination 6
|
||||
byte[] lat1Result = compress(result, 0, resultLen);
|
||||
if (lat1Result != null) {
|
||||
return new String(lat1Result, LATIN1);
|
||||
}
|
||||
}
|
||||
return new String(result, UTF16);
|
||||
}
|
||||
|
||||
public static boolean regionMatchesCI(byte[] value, int toffset,
|
||||
byte[] other, int ooffset, int len) {
|
||||
int last = toffset + len;
|
||||
@ -1430,6 +1554,15 @@ final class StringUTF16 {
|
||||
|
||||
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
|
||||
|
||||
|
||||
/**
|
||||
* The maximum size of array to allocate (unless necessary).
|
||||
* Some VMs reserve some header words in an array.
|
||||
* Attempts to allocate larger arrays may result in
|
||||
* OutOfMemoryError: Requested array size exceeds VM limit
|
||||
*/
|
||||
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
||||
|
||||
// Used by trusted callers. Assumes all necessary bounds checks have
|
||||
// been done by the caller.
|
||||
|
||||
|
@ -213,7 +213,7 @@ public interface ClassDesc
|
||||
* @param moreNestedNames the unqualified name(s) of the remaining levels of
|
||||
* nested class
|
||||
* @return a {@linkplain ClassDesc} describing the nested class
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws NullPointerException if any argument or its contents is {@code null}
|
||||
* @throws IllegalStateException if this {@linkplain ClassDesc} does not
|
||||
* describe a class or interface type
|
||||
* @throws IllegalArgumentException if the nested class name is invalid
|
||||
@ -221,6 +221,11 @@ public interface ClassDesc
|
||||
default ClassDesc nested(String firstNestedName, String... moreNestedNames) {
|
||||
if (!isClassOrInterface())
|
||||
throw new IllegalStateException("Outer class is not a class or interface type");
|
||||
validateMemberName(firstNestedName, false);
|
||||
requireNonNull(moreNestedNames);
|
||||
for (String addNestedNames : moreNestedNames) {
|
||||
validateMemberName(addNestedNames, false);
|
||||
}
|
||||
return moreNestedNames.length == 0
|
||||
? nested(firstNestedName)
|
||||
: nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", "")));
|
||||
|
@ -32,6 +32,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Collections;
|
||||
|
||||
@ -81,6 +82,7 @@ class ServerSocket implements java.io.Closeable {
|
||||
* @since 12
|
||||
*/
|
||||
protected ServerSocket(SocketImpl impl) {
|
||||
Objects.requireNonNull(impl);
|
||||
this.impl = impl;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2019, 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
|
||||
@ -1403,8 +1403,9 @@ public final class URL implements java.io.Serializable {
|
||||
|
||||
URLStreamHandlerFactory fac;
|
||||
boolean checkedWithFactory = false;
|
||||
boolean overrideableProtocol = isOverrideable(protocol);
|
||||
|
||||
if (isOverrideable(protocol) && jdk.internal.misc.VM.isBooted()) {
|
||||
if (overrideableProtocol && jdk.internal.misc.VM.isBooted()) {
|
||||
// Use the factory (if any). Volatile read makes
|
||||
// URLStreamHandlerFactory appear fully initialized to current thread.
|
||||
fac = factory;
|
||||
@ -1440,7 +1441,8 @@ public final class URL implements java.io.Serializable {
|
||||
|
||||
// Check with factory if another thread set a
|
||||
// factory since our last check
|
||||
if (!checkedWithFactory && (fac = factory) != null) {
|
||||
if (overrideableProtocol && !checkedWithFactory &&
|
||||
(fac = factory) != null) {
|
||||
handler2 = fac.createURLStreamHandler(protocol);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2019, 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
|
||||
@ -252,10 +252,8 @@ public final class FileSystems {
|
||||
* Suppose there is a provider identified by the scheme {@code "memory"}
|
||||
* installed:
|
||||
* <pre>
|
||||
* Map<String,String> env = new HashMap<>();
|
||||
* env.put("capacity", "16G");
|
||||
* env.put("blockSize", "4k");
|
||||
* FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
|
||||
* FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"),
|
||||
* Map.of("capacity", "16G", "blockSize", "4k"));
|
||||
* </pre>
|
||||
*
|
||||
* @param uri
|
||||
@ -365,14 +363,13 @@ public final class FileSystems {
|
||||
* systems where the contents of one or more files is treated as a file
|
||||
* system.
|
||||
*
|
||||
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
||||
* installed} providers. It invokes, in turn, each provider's {@link
|
||||
* FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method
|
||||
* with an empty map. If a provider returns a file system then the iteration
|
||||
* terminates and the file system is returned. If none of the installed
|
||||
* providers return a {@code FileSystem} then an attempt is made to locate
|
||||
* the provider using the given class loader. If a provider returns a file
|
||||
* system then the lookup terminates and the file system is returned.
|
||||
* <p> This method first attempts to locate an installed provider in exactly
|
||||
* the same manner as the {@link #newFileSystem(Path, Map, ClassLoader)
|
||||
* newFileSystem(Path, Map, ClassLoader)} method with an empty map. If none
|
||||
* of the installed providers return a {@code FileSystem} then an attempt is
|
||||
* made to locate the provider using the given class loader. If a provider
|
||||
* returns a file system then the lookup terminates and the file system is
|
||||
* returned.
|
||||
*
|
||||
* @param path
|
||||
* the path to the file
|
||||
@ -395,11 +392,132 @@ public final class FileSystems {
|
||||
public static FileSystem newFileSystem(Path path,
|
||||
ClassLoader loader)
|
||||
throws IOException
|
||||
{
|
||||
return newFileSystem(path, Map.of(), loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code FileSystem} to access the contents of a file as a
|
||||
* file system.
|
||||
*
|
||||
* <p> This method makes use of specialized providers that create pseudo file
|
||||
* systems where the contents of one or more files is treated as a file
|
||||
* system.
|
||||
*
|
||||
* <p> This method first attempts to locate an installed provider in exactly
|
||||
* the same manner as the {@link #newFileSystem(Path,Map,ClassLoader)
|
||||
* newFileSystem(Path, Map, ClassLoader)} method. If found, the provider's
|
||||
* {@link FileSystemProvider#newFileSystem(Path, Map) newFileSystem(Path, Map)}
|
||||
* method is invoked to construct the new file system.
|
||||
*
|
||||
* @param path
|
||||
* the path to the file
|
||||
* @param env
|
||||
* a map of provider specific properties to configure the file system;
|
||||
* may be empty
|
||||
*
|
||||
* @return a new file system
|
||||
*
|
||||
* @throws ProviderNotFoundException
|
||||
* if a provider supporting this file type cannot be located
|
||||
* @throws ServiceConfigurationError
|
||||
* when an error occurs while loading a service provider
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
* @throws SecurityException
|
||||
* if a security manager is installed and it denies an unspecified
|
||||
* permission
|
||||
*
|
||||
* @since 13
|
||||
*/
|
||||
public static FileSystem newFileSystem(Path path, Map<String,?> env)
|
||||
throws IOException
|
||||
{
|
||||
return newFileSystem(path, env, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code FileSystem} to access the contents of a file as a
|
||||
* file system.
|
||||
*
|
||||
* <p> This method makes use of specialized providers that create pseudo file
|
||||
* systems where the contents of one or more files is treated as a file
|
||||
* system.
|
||||
*
|
||||
* <p> This method first attempts to locate an installed provider in exactly
|
||||
* the same manner as the {@link #newFileSystem(Path,Map,ClassLoader)
|
||||
* newFileSystem(Path, Map, ClassLoader)} method. If found, the provider's
|
||||
* {@link FileSystemProvider#newFileSystem(Path, Map) newFileSystem(Path, Map)}
|
||||
* method is invoked with an empty map to construct the new file system.
|
||||
*
|
||||
* @param path
|
||||
* the path to the file
|
||||
*
|
||||
* @return a new file system
|
||||
*
|
||||
* @throws ProviderNotFoundException
|
||||
* if a provider supporting this file type cannot be located
|
||||
* @throws ServiceConfigurationError
|
||||
* when an error occurs while loading a service provider
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
* @throws SecurityException
|
||||
* if a security manager is installed and it denies an unspecified
|
||||
* permission
|
||||
*
|
||||
* @since 13
|
||||
*/
|
||||
public static FileSystem newFileSystem(Path path) throws IOException {
|
||||
return newFileSystem(path, Map.of(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code FileSystem} to access the contents of a file as a
|
||||
* file system.
|
||||
*
|
||||
* <p> This method makes use of specialized providers that create pseudo file
|
||||
* systems where the contents of one or more files is treated as a file
|
||||
* system.
|
||||
*
|
||||
* <p> This method iterates over the {@link FileSystemProvider#installedProviders()
|
||||
* installed} providers. It invokes, in turn, each provider's {@link
|
||||
* FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)}
|
||||
* method. If a provider returns a file system then the iteration
|
||||
* terminates and the file system is returned.
|
||||
* If none of the installed providers return a {@code FileSystem} then
|
||||
* an attempt is made to locate the provider using the given class loader.
|
||||
* If a provider returns a file
|
||||
* system, then the lookup terminates and the file system is returned.
|
||||
*
|
||||
* @param path
|
||||
* the path to the file
|
||||
* @param env
|
||||
* a map of provider specific properties to configure the file system;
|
||||
* may be empty
|
||||
* @param loader
|
||||
* the class loader to locate the provider or {@code null} to only
|
||||
* attempt to locate an installed provider
|
||||
*
|
||||
* @return a new file system
|
||||
*
|
||||
* @throws ProviderNotFoundException
|
||||
* if a provider supporting this file type cannot be located
|
||||
* @throws ServiceConfigurationError
|
||||
* when an error occurs while loading a service provider
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
* @throws SecurityException
|
||||
* if a security manager is installed and it denies an unspecified
|
||||
* permission
|
||||
*
|
||||
* @since 13
|
||||
*/
|
||||
public static FileSystem newFileSystem(Path path, Map<String,?> env,
|
||||
ClassLoader loader)
|
||||
throws IOException
|
||||
{
|
||||
if (path == null)
|
||||
throw new NullPointerException();
|
||||
Map<String,?> env = Collections.emptyMap();
|
||||
|
||||
// check installed providers
|
||||
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
|
||||
try {
|
||||
|
@ -62,10 +62,11 @@ public final class Objects {
|
||||
* Returns {@code true} if the arguments are equal to each other
|
||||
* and {@code false} otherwise.
|
||||
* Consequently, if both arguments are {@code null}, {@code true}
|
||||
* is returned and if exactly one argument is {@code null}, {@code
|
||||
* false} is returned. Otherwise, equality is determined by using
|
||||
* the {@link Object#equals equals} method of the first
|
||||
* argument.
|
||||
* is returned. Otherwise, if the first argument is not {@code
|
||||
* null}, equality is determined by calling the {@link
|
||||
* Object#equals equals} method of the first argument with the
|
||||
* second argument of this method. Otherwise, {@code false} is
|
||||
* returned.
|
||||
*
|
||||
* @param a an object
|
||||
* @param b an object to be compared with {@code a} for equality
|
||||
|
@ -1678,7 +1678,13 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
||||
return;
|
||||
int j = i;
|
||||
i += 2;
|
||||
int[] newtemp = new int[j + 3*(pLen-i) + 2];
|
||||
int newTempLen;
|
||||
try {
|
||||
newTempLen = Math.addExact(j + 2, Math.multiplyExact(3, pLen - i));
|
||||
} catch (ArithmeticException ae) {
|
||||
throw new OutOfMemoryError();
|
||||
}
|
||||
int[] newtemp = new int[newTempLen];
|
||||
System.arraycopy(temp, 0, newtemp, 0, j);
|
||||
|
||||
boolean inQuote = true;
|
||||
|
@ -826,6 +826,10 @@ public final class SSLSocketImpl
|
||||
// reading lock
|
||||
private final ReentrantLock readLock = new ReentrantLock();
|
||||
|
||||
// closing status
|
||||
private volatile boolean isClosing;
|
||||
private volatile boolean hasDepleted;
|
||||
|
||||
AppInputStream() {
|
||||
this.appDataIsAvailable = false;
|
||||
this.buffer = ByteBuffer.allocate(4096);
|
||||
@ -871,8 +875,7 @@ public final class SSLSocketImpl
|
||||
* and returning "-1" on non-fault EOF status.
|
||||
*/
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len)
|
||||
throws IOException {
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException("the target buffer is null");
|
||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
||||
@ -900,12 +903,40 @@ public final class SSLSocketImpl
|
||||
throw new SocketException("Connection or inbound has closed");
|
||||
}
|
||||
|
||||
// Check if the input stream has been depleted.
|
||||
//
|
||||
// Note that the "hasDepleted" rather than the isClosing
|
||||
// filed is checked here, in case the closing process is
|
||||
// still in progress.
|
||||
if (hasDepleted) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.fine("The input stream has been depleted");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read the available bytes at first.
|
||||
//
|
||||
// Note that the receiving and processing of post-handshake message
|
||||
// are also synchronized with the read lock.
|
||||
readLock.lock();
|
||||
try {
|
||||
// Double check if the Socket is invalid (error or closed).
|
||||
if (conContext.isBroken || conContext.isInboundClosed()) {
|
||||
throw new SocketException(
|
||||
"Connection or inbound has closed");
|
||||
}
|
||||
|
||||
// Double check if the input stream has been depleted.
|
||||
if (hasDepleted) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.fine("The input stream is closing");
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int remains = available();
|
||||
if (remains > 0) {
|
||||
int howmany = Math.min(remains, len);
|
||||
@ -938,7 +969,17 @@ public final class SSLSocketImpl
|
||||
return -1;
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
// Check if the input stream is closing.
|
||||
//
|
||||
// If the deplete() did not hold the lock, clean up the
|
||||
// input stream here.
|
||||
try {
|
||||
if (isClosing) {
|
||||
readLockedDeplete();
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1016,34 +1057,48 @@ public final class SSLSocketImpl
|
||||
* socket gracefully, without impact the performance too much.
|
||||
*/
|
||||
private void deplete() {
|
||||
if (conContext.isInboundClosed()) {
|
||||
if (conContext.isInboundClosed() || isClosing) {
|
||||
return;
|
||||
}
|
||||
|
||||
readLock.lock();
|
||||
try {
|
||||
// double check
|
||||
if (conContext.isInboundClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SSLSocketInputRecord socketInputRecord =
|
||||
(SSLSocketInputRecord)conContext.inputRecord;
|
||||
isClosing = true;
|
||||
if (readLock.tryLock()) {
|
||||
try {
|
||||
socketInputRecord.deplete(
|
||||
conContext.isNegotiated && (getSoTimeout() > 0));
|
||||
} catch (IOException ioe) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.warning(
|
||||
"input stream close depletion failed", ioe);
|
||||
}
|
||||
readLockedDeplete();
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to use up the input records.
|
||||
*
|
||||
* Please don't call this method unless the readLock is held by
|
||||
* the current thread.
|
||||
*/
|
||||
private void readLockedDeplete() {
|
||||
// double check
|
||||
if (hasDepleted || conContext.isInboundClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SSLSocketInputRecord socketInputRecord =
|
||||
(SSLSocketInputRecord)conContext.inputRecord;
|
||||
try {
|
||||
socketInputRecord.deplete(
|
||||
conContext.isNegotiated && (getSoTimeout() > 0));
|
||||
} catch (Exception ex) {
|
||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||
SSLLogger.warning(
|
||||
"input stream close depletion failed", ex);
|
||||
}
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
hasDepleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2019, 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
|
||||
@ -73,15 +73,23 @@ class UnixFileAttributeViews {
|
||||
|
||||
boolean haveFd = false;
|
||||
boolean useFutimes = false;
|
||||
boolean useLutimes = false;
|
||||
int fd = -1;
|
||||
try {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
if (fd != -1) {
|
||||
haveFd = true;
|
||||
useFutimes = futimesSupported();
|
||||
if (!followLinks) {
|
||||
useLutimes = lutimesSupported() &&
|
||||
UnixFileAttributes.get(file, false).isSymbolicLink();
|
||||
}
|
||||
if (!useLutimes) {
|
||||
fd = file.openForAttributeAccess(followLinks);
|
||||
if (fd != -1) {
|
||||
haveFd = true;
|
||||
useFutimes = futimesSupported();
|
||||
}
|
||||
}
|
||||
} catch (UnixException x) {
|
||||
if (x.errno() != UnixConstants.ENXIO) {
|
||||
if (!(x.errno() == UnixConstants.ENXIO ||
|
||||
(x.errno() == UnixConstants.ELOOP && useLutimes))) {
|
||||
x.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
@ -112,6 +120,8 @@ class UnixFileAttributeViews {
|
||||
try {
|
||||
if (useFutimes) {
|
||||
futimes(fd, accessValue, modValue);
|
||||
} else if (useLutimes) {
|
||||
lutimes(file, accessValue, modValue);
|
||||
} else {
|
||||
utimes(file, accessValue, modValue);
|
||||
}
|
||||
@ -131,6 +141,8 @@ class UnixFileAttributeViews {
|
||||
try {
|
||||
if (useFutimes) {
|
||||
futimes(fd, accessValue, modValue);
|
||||
} else if (useLutimes) {
|
||||
lutimes(file, accessValue, modValue);
|
||||
} else {
|
||||
utimes(file, accessValue, modValue);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2019, 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
|
||||
@ -401,7 +401,7 @@ class UnixNativeDispatcher {
|
||||
static native void fchmod(int fd, int mode) throws UnixException;
|
||||
|
||||
/**
|
||||
* utimes(conar char* path, const struct timeval times[2])
|
||||
* utimes(const char* path, const struct timeval times[2])
|
||||
*/
|
||||
static void utimes(UnixPath path, long times0, long times1)
|
||||
throws UnixException
|
||||
@ -417,10 +417,26 @@ class UnixNativeDispatcher {
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* futimes(int fildes,, const struct timeval times[2])
|
||||
* futimes(int fildes, const struct timeval times[2])
|
||||
*/
|
||||
static native void futimes(int fd, long times0, long times1) throws UnixException;
|
||||
|
||||
/**
|
||||
* lutimes(const char* path, const struct timeval times[2])
|
||||
*/
|
||||
static void lutimes(UnixPath path, long times0, long times1)
|
||||
throws UnixException
|
||||
{
|
||||
NativeBuffer buffer = copyToNativeBuffer(path);
|
||||
try {
|
||||
lutimes0(buffer.address(), times0, times1);
|
||||
} finally {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
private static native void lutimes0(long pathAddress, long times0, long times1)
|
||||
throws UnixException;
|
||||
|
||||
/**
|
||||
* DIR *opendir(const char* dirname)
|
||||
*/
|
||||
@ -578,9 +594,10 @@ class UnixNativeDispatcher {
|
||||
/**
|
||||
* Capabilities
|
||||
*/
|
||||
private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
|
||||
private static final int SUPPORTS_OPENAT = 1 << 1; // syscalls
|
||||
private static final int SUPPORTS_FUTIMES = 1 << 2;
|
||||
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
|
||||
private static final int SUPPORTS_LUTIMES = 1 << 4;
|
||||
private static final int SUPPORTS_BIRTHTIME = 1 << 16; // other features
|
||||
private static final int capabilities;
|
||||
|
||||
/**
|
||||
@ -597,6 +614,13 @@ class UnixNativeDispatcher {
|
||||
return (capabilities & SUPPORTS_FUTIMES) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports lutimes
|
||||
*/
|
||||
static boolean lutimesSupported() {
|
||||
return (capabilities & SUPPORTS_LUTIMES) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports file birth (creation) time attribute
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2019, 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
|
||||
@ -143,6 +143,7 @@ typedef int fstatat64_func(int, const char *, struct stat64 *, int);
|
||||
typedef int unlinkat_func(int, const char*, int);
|
||||
typedef int renameat_func(int, const char*, int, const char*);
|
||||
typedef int futimesat_func(int, const char *, const struct timeval *);
|
||||
typedef int lutimes_func(const char *, const struct timeval *);
|
||||
typedef DIR* fdopendir_func(int);
|
||||
|
||||
static openat64_func* my_openat64_func = NULL;
|
||||
@ -150,6 +151,7 @@ static fstatat64_func* my_fstatat64_func = NULL;
|
||||
static unlinkat_func* my_unlinkat_func = NULL;
|
||||
static renameat_func* my_renameat_func = NULL;
|
||||
static futimesat_func* my_futimesat_func = NULL;
|
||||
static lutimes_func* my_lutimes_func = NULL;
|
||||
static fdopendir_func* my_fdopendir_func = NULL;
|
||||
|
||||
/**
|
||||
@ -269,7 +271,10 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
|
||||
#endif
|
||||
my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat");
|
||||
my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat");
|
||||
#ifndef _ALLBSD_SOURCE
|
||||
my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat");
|
||||
my_lutimes_func = (lutimes_func*) dlsym(RTLD_DEFAULT, "lutimes");
|
||||
#endif
|
||||
#if defined(_AIX)
|
||||
my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64");
|
||||
#else
|
||||
@ -282,13 +287,16 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
|
||||
my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;
|
||||
#endif
|
||||
|
||||
/* supports futimes or futimesat */
|
||||
/* supports futimes or futimesat and/or lutimes */
|
||||
|
||||
#ifdef _ALLBSD_SOURCE
|
||||
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;
|
||||
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;
|
||||
#else
|
||||
if (my_futimesat_func != NULL)
|
||||
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;
|
||||
if (my_lutimes_func != NULL)
|
||||
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;
|
||||
#endif
|
||||
|
||||
/* supports openat, etc. */
|
||||
@ -675,7 +683,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint file
|
||||
RESTARTABLE(futimes(filedes, ×[0]), err);
|
||||
#else
|
||||
if (my_futimesat_func == NULL) {
|
||||
JNU_ThrowInternalError(env, "my_ftimesat_func is NULL");
|
||||
JNU_ThrowInternalError(env, "my_futimesat_func is NULL");
|
||||
return;
|
||||
}
|
||||
RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err);
|
||||
@ -685,6 +693,34 @@ Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint file
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_lutimes0(JNIEnv* env, jclass this,
|
||||
jlong pathAddress, jlong accessTime, jlong modificationTime)
|
||||
{
|
||||
int err;
|
||||
struct timeval times[2];
|
||||
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||
|
||||
times[0].tv_sec = accessTime / 1000000;
|
||||
times[0].tv_usec = accessTime % 1000000;
|
||||
|
||||
times[1].tv_sec = modificationTime / 1000000;
|
||||
times[1].tv_usec = modificationTime % 1000000;
|
||||
|
||||
#ifdef _ALLBSD_SOURCE
|
||||
RESTARTABLE(lutimes(path, ×[0]), err);
|
||||
#else
|
||||
if (my_lutimes_func == NULL) {
|
||||
JNU_ThrowInternalError(env, "my_lutimes_func is NULL");
|
||||
return;
|
||||
}
|
||||
RESTARTABLE((*my_lutimes_func)(path, ×[0]), err);
|
||||
#endif
|
||||
if (err == -1) {
|
||||
throwUnixException(env, errno);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,
|
||||
jlong pathAddress)
|
||||
|
@ -40,6 +40,7 @@ import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
public abstract class IntegrityHmac extends SignatureAlgorithmSpi {
|
||||
@ -325,12 +326,13 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi {
|
||||
throw new IllegalArgumentException("element null");
|
||||
}
|
||||
|
||||
Text hmaclength =
|
||||
XMLUtils.selectDsNodeText(element.getFirstChild(), Constants._TAG_HMACOUTPUTLENGTH, 0);
|
||||
|
||||
if (hmaclength != null) {
|
||||
this.HMACOutputLength = Integer.parseInt(hmaclength.getData());
|
||||
this.HMACOutputLengthSet = true;
|
||||
Node n = XMLUtils.selectDsNode(element.getFirstChild(), Constants._TAG_HMACOUTPUTLENGTH, 0);
|
||||
if (n != null) {
|
||||
String hmacLength = XMLUtils.getFullTextChildrenFromNode(n);
|
||||
if (hmacLength != null && !"".equals(hmacLength)) {
|
||||
this.HMACOutputLength = Integer.parseInt(hmacLength);
|
||||
this.HMACOutputLengthSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
import java.security.interfaces.DSAKey;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.Base64;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
|
||||
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi;
|
||||
@ -41,6 +40,7 @@ import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
|
||||
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.JavaUtils;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
|
||||
public class SignatureDSA extends SignatureAlgorithmSpi {
|
||||
|
||||
@ -109,7 +109,7 @@ public class SignatureDSA extends SignatureAlgorithmSpi {
|
||||
throws XMLSignatureException {
|
||||
try {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Called DSA.verify() on " + Base64.getMimeEncoder().encodeToString(signature));
|
||||
LOG.debug("Called DSA.verify() on " + XMLUtils.encodeToString(signature));
|
||||
}
|
||||
|
||||
byte[] jcebytes = JavaUtils.convertDsaXMLDSIGtoASN1(signature,
|
||||
|
@ -33,12 +33,12 @@ import java.security.SecureRandom;
|
||||
import java.security.Signature;
|
||||
import java.security.SignatureException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.Base64;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.algorithms.JCEMapper;
|
||||
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi;
|
||||
import com.sun.org.apache.xml.internal.security.signature.XMLSignature;
|
||||
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -132,7 +132,7 @@ public abstract class SignatureECDSA extends SignatureAlgorithmSpi {
|
||||
byte[] jcebytes = SignatureECDSA.convertXMLDSIGtoASN1(signature);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Called ECDSA.verify() on " + Base64.getMimeEncoder().encodeToString(signature));
|
||||
LOG.debug("Called ECDSA.verify() on " + XMLUtils.encodeToString(signature));
|
||||
}
|
||||
|
||||
return this.signatureAlgorithm.verify(jcebytes);
|
||||
|
@ -331,7 +331,7 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase {
|
||||
ns.addMapping(NName, NValue, attribute);
|
||||
}
|
||||
} else if (XML_LANG_URI.equals(attribute.getNamespaceURI())
|
||||
&& (!c14n11 || c14n11 && !"id".equals(NName))) {
|
||||
&& (!c14n11 || !"id".equals(NName))) {
|
||||
xmlattrStack.addXmlnsAttr(attribute);
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase {
|
||||
protected void circumventBugIfNeeded(XMLSignatureInput input)
|
||||
throws CanonicalizationException, ParserConfigurationException,
|
||||
IOException, SAXException {
|
||||
if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty() || inclusiveNSSet.isEmpty()) {
|
||||
if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Document doc = null;
|
||||
|
@ -50,7 +50,6 @@ import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver;
|
||||
import com.sun.org.apache.xml.internal.security.transforms.Transforms;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.ElementProxy;
|
||||
import com.sun.org.apache.xml.internal.security.utils.EncryptionConstants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
import org.w3c.dom.Attr;
|
||||
|
@ -26,6 +26,7 @@ import java.security.PublicKey;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
|
||||
import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.DSAKeyValue;
|
||||
import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.ECKeyValue;
|
||||
import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.RSAKeyValue;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
|
||||
@ -107,9 +108,14 @@ public class KeyValue extends SignatureElementProxy implements KeyInfoContent {
|
||||
|
||||
appendSelf(rsa);
|
||||
addReturnToSelf();
|
||||
} else if (pk instanceof java.security.interfaces.ECPublicKey) {
|
||||
ECKeyValue ec = new ECKeyValue(getDocument(), pk);
|
||||
|
||||
appendSelf(ec);
|
||||
addReturnToSelf();
|
||||
} else {
|
||||
String error = "The given PublicKey type " + pk + " is not supported. Only DSAPublicKey and "
|
||||
+ "RSAPublicKey types are currently supported";
|
||||
+ "RSAPublicKey and ECPublicKey types are currently supported";
|
||||
throw new IllegalArgumentException(error);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,366 @@
|
||||
/*
|
||||
* reserved comment block
|
||||
* DO NOT REMOVE OR ALTER!
|
||||
*/
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.sun.org.apache.xml.internal.security.keys.content.keyvalues;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.ECField;
|
||||
import java.security.spec.ECFieldFp;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.EllipticCurve;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.xml.crypto.MarshalException;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.Text;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.I18n;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Signature11ElementProxy;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
|
||||
public class ECKeyValue extends Signature11ElementProxy implements KeyValueContent {
|
||||
|
||||
/* Supported curve, secp256r1 */
|
||||
private static final Curve SECP256R1 = initializeCurve(
|
||||
"secp256r1 [NIST P-256, X9.62 prime256v1]",
|
||||
"1.2.840.10045.3.1.7",
|
||||
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
|
||||
"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
|
||||
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
|
||||
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
|
||||
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
|
||||
1
|
||||
);
|
||||
|
||||
/* Supported curve secp384r1 */
|
||||
private static final Curve SECP384R1 = initializeCurve(
|
||||
"secp384r1 [NIST P-384]",
|
||||
"1.3.132.0.34",
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
|
||||
"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
|
||||
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
|
||||
"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
|
||||
1
|
||||
);
|
||||
|
||||
/* Supported curve secp521r1 */
|
||||
private static final Curve SECP521R1 = initializeCurve(
|
||||
"secp521r1 [NIST P-521]",
|
||||
"1.3.132.0.35",
|
||||
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
|
||||
"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
|
||||
"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
|
||||
"011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
|
||||
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
|
||||
1
|
||||
);
|
||||
|
||||
private static Curve initializeCurve(String name, String oid,
|
||||
String sfield, String a, String b,
|
||||
String x, String y, String n, int h) {
|
||||
BigInteger p = bigInt(sfield);
|
||||
ECField field = new ECFieldFp(p);
|
||||
EllipticCurve curve = new EllipticCurve(field, bigInt(a),
|
||||
bigInt(b));
|
||||
ECPoint g = new ECPoint(bigInt(x), bigInt(y));
|
||||
return new Curve(name, oid, curve, g, bigInt(n), h);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor DSAKeyValue
|
||||
*
|
||||
* @param element
|
||||
* @param baseURI
|
||||
* @throws XMLSecurityException
|
||||
*/
|
||||
public ECKeyValue(Element element, String baseURI) throws XMLSecurityException {
|
||||
super(element, baseURI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor DSAKeyValue
|
||||
*
|
||||
* @param doc
|
||||
* @param key
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public ECKeyValue(Document doc, Key key) throws IllegalArgumentException {
|
||||
super(doc);
|
||||
|
||||
addReturnToSelf();
|
||||
|
||||
if (key instanceof ECPublicKey) {
|
||||
ECParameterSpec ecParams = ((ECPublicKey)key).getParams();
|
||||
|
||||
// NamedCurve
|
||||
String oid = getCurveOid(ecParams);
|
||||
if (oid == null) {
|
||||
throw new IllegalArgumentException("Invalid ECParameterSpec");
|
||||
}
|
||||
|
||||
Element namedCurveElement = XMLUtils.createElementInSignature11Space(getDocument(), "NamedCurve");
|
||||
namedCurveElement.setAttributeNS(null, "URI", "urn:oid:" + oid);
|
||||
appendSelf(namedCurveElement);
|
||||
addReturnToSelf();
|
||||
|
||||
// PublicKey
|
||||
ECPoint ecPoint = ((ECPublicKey)key).getW();
|
||||
byte[] secPublicKey = encodePoint(ecPoint, ecParams.getCurve());
|
||||
String encoded = XMLUtils.encodeToString(secPublicKey);
|
||||
Element publicKeyElement = XMLUtils.createElementInSignature11Space(getDocument(), "PublicKey");
|
||||
Text text = getDocument().createTextNode(encoded);
|
||||
|
||||
publicKeyElement.appendChild(text);
|
||||
|
||||
appendSelf(publicKeyElement);
|
||||
addReturnToSelf();
|
||||
|
||||
} else {
|
||||
Object[] exArgs = { Constants._TAG_ECKEYVALUE, key.getClass().getName() };
|
||||
|
||||
throw new IllegalArgumentException(I18n.translate("KeyValue.IllegalArgument", exArgs));
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public PublicKey getPublicKey() throws XMLSecurityException {
|
||||
try {
|
||||
ECParameterSpec ecParams = null;
|
||||
Element curElem = getFirstChildElement(getElement());
|
||||
if (curElem == null) {
|
||||
throw new MarshalException("KeyValue must contain at least one type");
|
||||
}
|
||||
|
||||
if ("ECParameters".equals(curElem.getLocalName())
|
||||
&& Constants.SignatureSpec11NS.equals(curElem.getNamespaceURI())) {
|
||||
throw new UnsupportedOperationException
|
||||
("ECParameters not supported");
|
||||
} else if ("NamedCurve".equals(curElem.getLocalName())
|
||||
&& Constants.SignatureSpec11NS.equals(curElem.getNamespaceURI())) {
|
||||
String uri = null;
|
||||
if (curElem.hasAttributeNS(null, "URI")) {
|
||||
uri = curElem.getAttributeNS(null, "URI");
|
||||
}
|
||||
// strip off "urn:oid"
|
||||
if (uri.startsWith("urn:oid:")) {
|
||||
String oid = uri.substring("urn:oid:".length());
|
||||
ecParams = getECParameterSpec(oid);
|
||||
if (ecParams == null) {
|
||||
throw new MarshalException("Invalid curve OID");
|
||||
}
|
||||
} else {
|
||||
throw new MarshalException("Invalid NamedCurve URI");
|
||||
}
|
||||
} else {
|
||||
throw new MarshalException("Invalid ECKeyValue");
|
||||
}
|
||||
curElem = getNextSiblingElement(curElem, "PublicKey", Constants.SignatureSpec11NS);
|
||||
ECPoint ecPoint = null;
|
||||
|
||||
try {
|
||||
String content = XMLUtils.getFullTextChildrenFromNode(curElem);
|
||||
ecPoint = decodePoint(XMLUtils.decode(content), ecParams.getCurve());
|
||||
} catch (IOException ioe) {
|
||||
throw new MarshalException("Invalid EC Point", ioe);
|
||||
}
|
||||
|
||||
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParams);
|
||||
return KeyFactory.getInstance("EC").generatePublic(spec);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new XMLSecurityException(ex);
|
||||
} catch (InvalidKeySpecException ex) {
|
||||
throw new XMLSecurityException(ex);
|
||||
} catch (MarshalException ex) {
|
||||
throw new XMLSecurityException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public String getBaseLocalName() {
|
||||
return Constants._TAG_ECKEYVALUE;
|
||||
}
|
||||
|
||||
private static Element getFirstChildElement(Node node) {
|
||||
Node child = node.getFirstChild();
|
||||
while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return (Element)child;
|
||||
}
|
||||
|
||||
private static Element getNextSiblingElement(Node node, String localName, String namespaceURI)
|
||||
throws MarshalException
|
||||
{
|
||||
return verifyElement(getNextSiblingElement(node), localName, namespaceURI);
|
||||
}
|
||||
|
||||
private static Element getNextSiblingElement(Node node) {
|
||||
Node sibling = node.getNextSibling();
|
||||
while (sibling != null && sibling.getNodeType() != Node.ELEMENT_NODE) {
|
||||
sibling = sibling.getNextSibling();
|
||||
}
|
||||
return (Element)sibling;
|
||||
}
|
||||
|
||||
private static Element verifyElement(Element elem, String localName, String namespaceURI)
|
||||
throws MarshalException
|
||||
{
|
||||
if (elem == null) {
|
||||
throw new MarshalException("Missing " + localName + " element");
|
||||
}
|
||||
String name = elem.getLocalName();
|
||||
String namespace = elem.getNamespaceURI();
|
||||
if (!name.equals(localName) || namespace == null && namespaceURI != null
|
||||
|| namespace != null && !namespace.equals(namespaceURI)) {
|
||||
throw new MarshalException("Invalid element name: " +
|
||||
namespace + ":" + name + ", expected " + namespaceURI + ":" + localName);
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
private static String getCurveOid(ECParameterSpec params) {
|
||||
// Check that the params represent one of the supported
|
||||
// curves. If there is a match, return the object identifier
|
||||
// of the curve.
|
||||
Curve match;
|
||||
if (matchCurve(params, SECP256R1)) {
|
||||
match = SECP256R1;
|
||||
} else if (matchCurve(params, SECP384R1)) {
|
||||
match = SECP384R1;
|
||||
} else if (matchCurve(params, SECP521R1)) {
|
||||
match = SECP521R1;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return match.getObjectId();
|
||||
}
|
||||
|
||||
private static boolean matchCurve(ECParameterSpec params, Curve curve) {
|
||||
int fieldSize = params.getCurve().getField().getFieldSize();
|
||||
return curve.getCurve().getField().getFieldSize() == fieldSize
|
||||
&& curve.getCurve().equals(params.getCurve())
|
||||
&& curve.getGenerator().equals(params.getGenerator())
|
||||
&& curve.getOrder().equals(params.getOrder())
|
||||
&& curve.getCofactor() == params.getCofactor();
|
||||
}
|
||||
|
||||
private static ECPoint decodePoint(byte[] data, EllipticCurve curve)
|
||||
throws IOException {
|
||||
if (data.length == 0 || data[0] != 4) {
|
||||
throw new IOException("Only uncompressed point format " +
|
||||
"supported");
|
||||
}
|
||||
// Per ANSI X9.62, an encoded point is a 1 byte type followed by
|
||||
// ceiling(LOG base 2 field-size / 8) bytes of x and the same of y.
|
||||
int n = (data.length - 1) / 2;
|
||||
if (n != (curve.getField().getFieldSize() + 7) >> 3) {
|
||||
throw new IOException("Point does not match field size");
|
||||
}
|
||||
|
||||
byte[] xb = Arrays.copyOfRange(data, 1, 1 + n);
|
||||
byte[] yb = Arrays.copyOfRange(data, n + 1, n + 1 + n);
|
||||
|
||||
return new ECPoint(new BigInteger(1, xb), new BigInteger(1, yb));
|
||||
}
|
||||
|
||||
private static byte[] encodePoint(ECPoint point, EllipticCurve curve) {
|
||||
// get field size in bytes (rounding up)
|
||||
int n = (curve.getField().getFieldSize() + 7) >> 3;
|
||||
byte[] xb = trimZeroes(point.getAffineX().toByteArray());
|
||||
byte[] yb = trimZeroes(point.getAffineY().toByteArray());
|
||||
if (xb.length > n || yb.length > n) {
|
||||
throw new RuntimeException("Point coordinates do not " +
|
||||
"match field size");
|
||||
}
|
||||
byte[] b = new byte[1 + (n << 1)];
|
||||
b[0] = 4; // uncompressed
|
||||
System.arraycopy(xb, 0, b, n - xb.length + 1, xb.length);
|
||||
System.arraycopy(yb, 0, b, b.length - yb.length, yb.length);
|
||||
return b;
|
||||
}
|
||||
|
||||
private static byte[] trimZeroes(byte[] b) {
|
||||
int i = 0;
|
||||
while (i < b.length - 1 && b[i] == 0) {
|
||||
i++;
|
||||
}
|
||||
if (i == 0) {
|
||||
return b;
|
||||
}
|
||||
return Arrays.copyOfRange(b, i, b.length);
|
||||
}
|
||||
|
||||
private static ECParameterSpec getECParameterSpec(String oid) {
|
||||
if (oid.equals(SECP256R1.getObjectId())) {
|
||||
return SECP256R1;
|
||||
} else if (oid.equals(SECP384R1.getObjectId())) {
|
||||
return SECP384R1;
|
||||
} else if (oid.equals(SECP521R1.getObjectId())) {
|
||||
return SECP521R1;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static final class Curve extends ECParameterSpec {
|
||||
private final String name;
|
||||
private final String oid;
|
||||
|
||||
Curve(String name, String oid, EllipticCurve curve,
|
||||
ECPoint g, BigInteger n, int h) {
|
||||
super(curve, g, n, h);
|
||||
this.name = name;
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
private String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
private String getObjectId() {
|
||||
return oid;
|
||||
}
|
||||
}
|
||||
|
||||
private static BigInteger bigInt(String s) {
|
||||
return new BigInteger(s, 16);
|
||||
}
|
||||
}
|
@ -24,18 +24,18 @@ package com.sun.org.apache.xml.internal.security.keys.content.x509;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.SignatureElementProxy;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Handles SubjectKeyIdentifier (SKI) for X.509v3.
|
||||
*
|
||||
* @see <A HREF="http://docs.oracle.com/javase/1.5.0/docs/api/java/security/cert/X509Extension.html">
|
||||
* @see <A HREF="http://docs.oracle.com/javase/8/docs/api/java/security/cert/X509Extension.html">
|
||||
* Interface X509Extension</A>
|
||||
*/
|
||||
public class XMLX509SKI extends SignatureElementProxy implements XMLX509DataContent {
|
||||
@ -138,7 +138,7 @@ public class XMLX509SKI extends SignatureElementProxy implements XMLX509DataCont
|
||||
System.arraycopy(extensionValue, 4, skidValue, 0, skidValue.length);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Base64 of SKI is " + Base64.getMimeEncoder().encodeToString(skidValue));
|
||||
LOG.debug("Base64 of SKI is " + XMLUtils.encodeToString(skidValue));
|
||||
}
|
||||
|
||||
return skidValue;
|
||||
|
@ -33,6 +33,7 @@ import javax.crypto.SecretKey;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DEREncodedKeyValueResolver;
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DSAKeyValueResolver;
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.ECKeyValueResolver;
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.KeyInfoReferenceResolver;
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RSAKeyValueResolver;
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RetrievalMethodResolver;
|
||||
@ -295,6 +296,7 @@ public class KeyResolver {
|
||||
keyResolverList.add(new KeyResolver(new DEREncodedKeyValueResolver()));
|
||||
keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver()));
|
||||
keyResolverList.add(new KeyResolver(new X509DigestResolver()));
|
||||
keyResolverList.add(new KeyResolver(new ECKeyValueResolver()));
|
||||
|
||||
resolverVector.addAll(keyResolverList);
|
||||
}
|
||||
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* reserved comment block
|
||||
* DO NOT REMOVE OR ALTER!
|
||||
*/
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
|
||||
import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.ECKeyValue;
|
||||
import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverSpi;
|
||||
import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver;
|
||||
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
public class ECKeyValueResolver extends KeyResolverSpi {
|
||||
|
||||
private static final com.sun.org.slf4j.internal.Logger LOG =
|
||||
com.sun.org.slf4j.internal.LoggerFactory.getLogger(ECKeyValueResolver.class);
|
||||
|
||||
|
||||
/**
|
||||
* Method engineResolvePublicKey
|
||||
*
|
||||
* @param element
|
||||
* @param baseURI
|
||||
* @param storage
|
||||
* @return null if no {@link PublicKey} could be obtained
|
||||
*/
|
||||
public PublicKey engineLookupAndResolvePublicKey(
|
||||
Element element, String baseURI, StorageResolver storage
|
||||
) {
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
Element ecKeyElement = null;
|
||||
boolean isKeyValue =
|
||||
XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYVALUE);
|
||||
if (isKeyValue) {
|
||||
ecKeyElement =
|
||||
XMLUtils.selectDs11Node(element.getFirstChild(), Constants._TAG_ECKEYVALUE, 0);
|
||||
} else if (XMLUtils.elementIsInSignature11Space(element, Constants._TAG_ECKEYVALUE)) {
|
||||
// this trick is needed to allow the RetrievalMethodResolver to eat a
|
||||
// ds:ECKeyValue directly (without KeyValue)
|
||||
ecKeyElement = element;
|
||||
}
|
||||
|
||||
if (ecKeyElement == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
ECKeyValue ecKeyValue = new ECKeyValue(ecKeyElement, baseURI);
|
||||
return ecKeyValue.getPublicKey();
|
||||
} catch (XMLSecurityException ex) {
|
||||
LOG.debug(ex.getMessage(), ex);
|
||||
//do nothing
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public X509Certificate engineLookupResolveX509Certificate(
|
||||
Element element, String baseURI, StorageResolver storage
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public javax.crypto.SecretKey engineLookupAndResolveSecretKey(
|
||||
Element element, String baseURI, StorageResolver storage
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -44,11 +44,12 @@ public class RSAKeyValueResolver extends KeyResolverSpi {
|
||||
public PublicKey engineLookupAndResolvePublicKey(
|
||||
Element element, String baseURI, StorageResolver storage
|
||||
) {
|
||||
LOG.debug("Can I resolve {}", element.getTagName());
|
||||
if (element == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
LOG.debug("Can I resolve {}", element.getTagName());
|
||||
|
||||
boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYVALUE);
|
||||
Element rsaKeyElement = null;
|
||||
if (isKeyValue) {
|
||||
|
@ -35,12 +35,12 @@ import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverException;
|
||||
import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi;
|
||||
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||
|
||||
/**
|
||||
* This {@link StorageResolverSpi} makes all raw (binary) {@link X509Certificate}s
|
||||
@ -207,7 +207,7 @@ public class CertsInFilesystemDirectoryResolver extends StorageResolverSpi {
|
||||
|
||||
System.out.println();
|
||||
System.out.println("Base64(SKI())= \""
|
||||
+ Base64.getMimeEncoder().encodeToString(ski) + "\"");
|
||||
+ XMLUtils.encodeToString(ski) + "\"");
|
||||
System.out.println("cert.getSerialNumber()= \""
|
||||
+ cert.getSerialNumber().toString() + "\"");
|
||||
System.out.println("cert.getSubjectX500Principal().getName()= \""
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user