This commit is contained in:
Phil Race 2019-05-07 11:52:28 -07:00
commit 1b03f22dff
272 changed files with 7154 additions and 1904 deletions

View File

@ -387,7 +387,7 @@ else # $(HAS_SPEC)=true
fi fi
# Re-run configure with the same arguments (and possibly some additional), # Re-run configure with the same arguments (and possibly some additional),
# must be done after patching. # 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)) $(BASH) $(topdir)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
endef endef

View File

@ -219,7 +219,7 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS],
-Wunused-function -Wundef -Wunused-value -Woverloaded-virtual" -Wunused-function -Wundef -Wunused-value -Woverloaded-virtual"
WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL" 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 if test "x$OPENJDK_TARGET_OS" = xmacosx; then
# missing-method-return-type triggers in JavaNativeFoundation framework # missing-method-return-type triggers in JavaNativeFoundation framework

View File

@ -76,7 +76,8 @@ $(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \
DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc) \
undef, \ undef, \
DISABLED_WARNINGS_clang := $(DISABLED_WARNINGS_clang) \ 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) \ DISABLED_WARNINGS_solstudio := $(DISABLED_WARNINGS_solstudio) \
identexpected, \ identexpected, \
DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) \ DISABLED_WARNINGS_microsoft := $(DISABLED_WARNINGS_microsoft) \

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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) { if (sb.indexOf("root") == -1) {
sb.append("root"); sb.append("root");
} }
Bundle b = new Bundle(id, sb.toString(), null, null); retList.add(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);
}
} }
} }
} }
// 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; return retList;
} }

View File

@ -46,12 +46,14 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) {
// Apply storeval barrier to newval. // Apply storeval barrier to newval.
ShenandoahBarrierSet::assembler()->storeval_barrier(masm->masm(), newval, tmp1); ShenandoahBarrierSet::assembler()->storeval_barrier(masm->masm(), newval, tmp1);
#ifdef _LP64
if (UseCompressedOops) { if (UseCompressedOops) {
__ encode_heap_oop(cmpval); __ encode_heap_oop(cmpval);
__ mov(rscratch1, newval); __ mov(rscratch1, newval);
__ encode_heap_oop(rscratch1); __ encode_heap_oop(rscratch1);
newval = rscratch1; newval = rscratch1;
} }
#endif
ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), result, Address(addr, 0), cmpval, newval, false, tmp1, tmp2); ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), result, Address(addr, 0), cmpval, newval, false, tmp1, tmp2);
} }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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_eieio() __asm__ __volatile__ ("eieio" : : : "memory");
#define inlasm_isync() __asm__ __volatile__ ("isync" : : : "memory"); #define inlasm_isync() __asm__ __volatile__ ("isync" : : : "memory");
// Use twi-isync for load_acquire (faster than lwsync). // 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) __asm__ __volatile__ ("twi 0,%0,0\n isync\n" : : "r" (X) : "memory");
#define inlasm_acquire_reg(X) inlasm_lwsync();
inline void OrderAccess::loadload() { inlasm_lwsync(); } inline void OrderAccess::loadload() { inlasm_lwsync(); }
inline void OrderAccess::storestore() { inlasm_lwsync(); } inline void OrderAccess::storestore() { inlasm_lwsync(); }

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 stub = NULL;
address pc = NULL; address pc = NULL;
//%note os_trap_1
if (info != NULL && uc != NULL && thread != NULL) { if (info != NULL && uc != NULL && thread != NULL) {
pc = (address) os::Linux::ucontext_get_pc(uc); 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 // 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. // comment below). Use get_stack_bang_address instead of si_addr.
// If SIGSEGV is caused due to a branch to an invalid address an // 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 // contains the invalid address. Otherwise, the SIGSEGV is caused due to
// load/store instruction trying to load/store from/to an invalid address // 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. // in order to extract the faulty data addresss.
address addr; address addr;
if ((ucontext_get_trap(uc) & 0x0F00 /* no IRQ reply bits */) == 0x0400) { if ((ucontext_get_trap(uc) & 0x0F00 /* no IRQ reply bits */) == 0x0400) {
// Instruction interruption // Instruction Storage Interrupt (ISI)
addr = pc; addr = pc;
} else { } 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); addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc);
} }

View File

@ -1988,8 +1988,9 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} }
if (cha_monomorphic_target != NULL) { if (cha_monomorphic_target != NULL) {
assert(!target->can_be_statically_bound() || target == cha_monomorphic_target, "");
assert(!cha_monomorphic_target->is_abstract(), ""); 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, // If we inlined because CHA revealed only a single target method,
// then we are dependent on that target method not getting overridden // then we are dependent on that target method not getting overridden
// by dynamic class loading. Be sure to test the "static" receiver // by dynamic class loading. Be sure to test the "static" receiver

View File

@ -764,6 +764,14 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
return CURRENT_THREAD_ENV->get_method(target()); 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 // ciMethod::resolve_invoke
// //

View File

@ -352,6 +352,8 @@ class ciMethod : public ciMetadata {
bool is_unboxing_method() const; bool is_unboxing_method() const;
bool is_object_initializer() const; bool is_object_initializer() const;
bool can_be_statically_bound(ciInstanceKlass* context) const;
// Replay data methods // Replay data methods
void dump_name_as_ascii(outputStream* st); void dump_name_as_ascii(outputStream* st);
void dump_replay_data(outputStream* st); void dump_replay_data(outputStream* st);

View File

@ -108,6 +108,7 @@ void Dependencies::assert_concrete_with_no_concrete_subtype(ciKlass* ctxk) {
void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm) { void Dependencies::assert_unique_concrete_method(ciKlass* ctxk, ciMethod* uniqm) {
check_ctxk(ctxk); check_ctxk(ctxk);
check_unique_method(ctxk, uniqm);
assert_common_2(unique_concrete_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) { void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) {
check_ctxk(ctxk); check_ctxk(ctxk);
check_unique_method(ctxk, uniqm);
assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm)); assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm));
} }

View File

@ -27,6 +27,7 @@
#include "ci/ciCallSite.hpp" #include "ci/ciCallSite.hpp"
#include "ci/ciKlass.hpp" #include "ci/ciKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodHandle.hpp" #include "ci/ciMethodHandle.hpp"
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "code/compressedStream.hpp" #include "code/compressedStream.hpp"
@ -341,6 +342,9 @@ class Dependencies: public ResourceObj {
check_ctxk(ctxk); check_ctxk(ctxk);
assert(!is_concrete_klass(ctxk->as_instance_klass()), "must be abstract"); 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_1(DepType dept, ciBaseObject* x);
void assert_common_2(DepType dept, ciBaseObject* x0, ciBaseObject* x1); void assert_common_2(DepType dept, ciBaseObject* x0, ciBaseObject* x1);
@ -368,6 +372,11 @@ class Dependencies: public ResourceObj {
check_ctxk(ctxk); check_ctxk(ctxk);
assert(ctxk->is_abstract(), "must be abstract"); 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_1(DepType dept, DepValue x);
void assert_common_2(DepType dept, DepValue x0, DepValue x1); void assert_common_2(DepType dept, DepValue x0, DepValue x1);

View File

@ -70,7 +70,6 @@
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
#include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciEnv.hpp"
#include "jvmci/jvmciRuntime.hpp" #include "jvmci/jvmciRuntime.hpp"
#include "runtime/vframe.hpp"
#endif #endif
#ifdef COMPILER2 #ifdef COMPILER2
#include "opto/c2compiler.hpp" #include "opto/c2compiler.hpp"
@ -1063,20 +1062,22 @@ void CompileBroker::compile_method_base(const methodHandle& method,
} }
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
if (UseJVMCICompiler && blocking && !UseJVMCINativeLibrary) { if (UseJVMCICompiler && blocking) {
// Don't allow blocking compiles for requests triggered by JVMCI. // Don't allow blocking compiles for requests triggered by JVMCI.
if (thread->is_Compiler_thread()) { if (thread->is_Compiler_thread()) {
blocking = false; blocking = false;
} }
// Don't allow blocking compiles if inside a class initializer or while performing class loading if (!UseJVMCINativeLibrary) {
vframeStream vfst((JavaThread*) thread); // Don't allow blocking compiles if inside a class initializer or while performing class loading
for (; !vfst.at_end(); vfst.next()) { vframeStream vfst((JavaThread*) thread);
if (vfst.method()->is_static_initializer() || for (; !vfst.at_end(); vfst.next()) {
(vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) && if (vfst.method()->is_static_initializer() ||
vfst.method()->name() == vmSymbols::loadClass_name())) { (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
blocking = false; vfst.method()->name() == vmSymbols::loadClass_name())) {
break; blocking = false;
break;
}
} }
} }
@ -2063,7 +2064,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
compilable = ciEnv::MethodCompilable_never; compilable = ciEnv::MethodCompilable_never;
} else { } else {
JVMCICompileState compile_state(task, system_dictionary_modification_counter); 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); methodHandle method(thread, target_handle);
env.runtime()->compile_method(&env, jvmci, method, osr_bci); env.runtime()->compile_method(&env, jvmci, method, osr_bci);

View File

@ -229,7 +229,6 @@ class CompileBroker: AllStatic {
static JavaThread* make_thread(jobject thread_oop, CompileQueue* queue, AbstractCompiler* comp, TRAPS); static JavaThread* make_thread(jobject thread_oop, CompileQueue* queue, AbstractCompiler* comp, TRAPS);
static void init_compiler_sweeper_threads(); static void init_compiler_sweeper_threads();
static void possibly_add_compiler_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 bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded);
static void preload_classes (const methodHandle& method, TRAPS); static void preload_classes (const methodHandle& method, TRAPS);
@ -285,6 +284,7 @@ public:
return NULL; 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 bool compilation_is_in_queue(const methodHandle& method);
static void print_compile_queues(outputStream* st); static void print_compile_queues(outputStream* st);
static void print_directives(outputStream* st); static void print_directives(outputStream* st);

View File

@ -1036,7 +1036,7 @@ void G1CollectedHeap::prepare_heap_for_full_collection() {
void G1CollectedHeap::verify_before_full_collection(bool explicit_gc) { void G1CollectedHeap::verify_before_full_collection(bool explicit_gc) {
assert(!GCCause::is_user_requested_gc(gc_cause()) || explicit_gc, "invariant"); 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_region_sets_optional();
_verifier->verify_before_gc(G1HeapVerifier::G1VerifyFull); _verifier->verify_before_gc(G1HeapVerifier::G1VerifyFull);
_verifier->check_bitmaps("Full GC Start"); _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 full GC has compacted objects and updated TAMS but not updated
// the prev bitmap. // the prev bitmap.
if (G1VerifyBitmaps) { if (G1VerifyBitmaps) {
GCTraceTime(Debug, gc)("Clear Prev Bitmap for Verification"); GCTraceTime(Debug, gc) tm("Clear Prev Bitmap for Verification");
_cm->clear_prev_bitmap(workers()); _cm->clear_prev_bitmap(workers());
} }
// This call implicitly verifies that the next bitmap is clear after Full GC. // 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(); _archive_allocator->clear_used();
} }
} }
assert(used() == recalculate_used(), assert_used_and_recalculate_used_equal(this);
"inconsistent used(), value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT,
used(), recalculate_used());
} }
// Methods for the mutator alloc region // Methods for the mutator alloc region

View File

@ -354,6 +354,15 @@ private:
assert(Thread::current()->is_VM_thread(), "current thread is not VM thread"); \ assert(Thread::current()->is_VM_thread(), "current thread is not VM thread"); \
} while (0) } 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; const char* young_gc_name() const;
// The young region list. // The young region list.

View File

@ -289,6 +289,6 @@ void G1FullCollector::verify_after_marking() {
// fail. At the end of the GC, the original mark word values // fail. At the end of the GC, the original mark word values
// (including hash values) are restored to the appropriate // (including hash values) are restored to the appropriate
// objects. // objects.
GCTraceTime(Info, gc, verify)("Verifying During GC (full)"); GCTraceTime(Info, gc, verify) tm("Verifying During GC (full)");
_heap->verify(VerifyOption_G1UseFullMarking); _heap->verify(VerifyOption_G1UseFullMarking);
} }

View File

@ -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[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[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[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):"); _gc_par_phases[UpdateRS] = new WorkerDataArray<double>(max_gc_threads, "Update RS (ms):");
if (G1HotCardCache::default_use_cache()) { if (G1HotCardCache::default_use_cache()) {
@ -406,7 +405,7 @@ double G1GCPhaseTimes::print_evacuate_collection_set() const {
trace_phase(_gc_par_phases[GCWorkerStart], false); trace_phase(_gc_par_phases[GCWorkerStart], false);
debug_phase(_gc_par_phases[ExtRootScan]); 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]); trace_phase(_gc_par_phases[i]);
} }
if (G1HotCardCache::default_use_cache()) { if (G1HotCardCache::default_use_cache()) {
@ -531,7 +530,6 @@ const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
"CMRefRoots", "CMRefRoots",
"WaitForStrongCLD", "WaitForStrongCLD",
"WeakCLDRoots", "WeakCLDRoots",
"SATBFiltering",
"UpdateRS", "UpdateRS",
"ScanHCC", "ScanHCC",
"ScanRS", "ScanRS",

View File

@ -60,7 +60,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
CMRefRoots, CMRefRoots,
WaitForStrongCLD, WaitForStrongCLD,
WeakCLDRoots, WeakCLDRoots,
SATBFiltering,
UpdateRS, UpdateRS,
ScanHCC, ScanHCC,
ScanRS, ScanRS,
@ -82,8 +81,8 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
GCParPhasesSentinel GCParPhasesSentinel
}; };
static const GCParPhases ExtRootScanSubPhasesStart = ThreadRoots; static const GCParPhases ExtRootScanSubPhasesFirst = ThreadRoots;
static const GCParPhases ExtRootScanSubPhasesEnd = SATBFiltering; static const GCParPhases ExtRootScanSubPhasesLast = WeakCLDRoots;
enum GCScanRSWorkItems { enum GCScanRSWorkItems {
ScanRSScannedCards, ScanRSScannedCards,

View File

@ -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(), assert(max_survivor_regions() + _g1h->num_used_regions() <= _g1h->max_regions(),
"Maximum survivor regions %u plus used regions %u exceeds max regions %u", "Maximum survivor regions %u plus used regions %u exceeds max regions %u",
max_survivor_regions(), _g1h->num_used_regions(), _g1h->max_regions()); max_survivor_regions(), _g1h->num_used_regions(), _g1h->max_regions());
assert_used_and_recalculate_used_equal(_g1h);
assert(_g1h->used() == _g1h->recalculate_used(),
"sanity, used: " SIZE_FORMAT " recalculate_used: " SIZE_FORMAT,
_g1h->used(), _g1h->recalculate_used());
phase_times()->record_cur_collection_start_sec(start_time_sec); phase_times()->record_cur_collection_start_sec(start_time_sec);
_pending_cards = _g1h->pending_card_num(); _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) { 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(); double end_time_sec = os::elapsedTime();
assert_used_and_recalculate_used_equal(_g1h);
size_t cur_used_bytes = _g1h->used(); 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_included_initial_mark = false;
bool this_pause_was_young_only = collector_state()->in_young_only_phase(); bool this_pause_was_young_only = collector_state()->in_young_only_phase();

View File

@ -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."); 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()); _process_strong_tasks.all_tasks_completed(n_workers());
} }

View File

@ -65,7 +65,6 @@ class G1RootProcessor : public StackObj {
G1RP_PS_CodeCache_oops_do, G1RP_PS_CodeCache_oops_do,
AOT_ONLY(G1RP_PS_aot_oops_do COMMA) AOT_ONLY(G1RP_PS_aot_oops_do COMMA)
JVMCI_ONLY(G1RP_PS_JVMCI_oops_do COMMA) JVMCI_ONLY(G1RP_PS_JVMCI_oops_do COMMA)
G1RP_PS_filter_satb_buffers,
G1RP_PS_refProcessor_oops_do, G1RP_PS_refProcessor_oops_do,
// Leave this one last. // Leave this one last.
G1RP_PS_NumElements G1RP_PS_NumElements

View File

@ -189,18 +189,6 @@ void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active)
Threads::threads_do(&closure); 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) { bool SATBMarkQueueSet::apply_closure_to_completed_buffer(SATBBufferClosure* cl) {
BufferNode* nd = get_completed_buffer(); BufferNode* nd = get_completed_buffer();
if (nd != NULL) { if (nd != NULL) {

View File

@ -125,9 +125,6 @@ public:
size_t buffer_enqueue_threshold() const { return _buffer_enqueue_threshold; } size_t buffer_enqueue_threshold() const { return _buffer_enqueue_threshold; }
virtual void filter(SATBMarkQueue* queue) = 0; 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 // If there exists some completed buffer, pop and process it, and
// return true. Otherwise return false. Processing a buffer // return true. Otherwise return false. Processing a buffer
// consists of applying the closure to the active range of the // consists of applying the closure to the active range of the

View File

@ -1333,8 +1333,8 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
} }
} }
} }
if (ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) { if ((ctrl->is_Proj() && ctrl->in(0)->is_CallJava()) || ctrl->is_CallJava()) {
CallNode* call = ctrl->in(0)->as_CallJava(); CallNode* call = ctrl->is_Proj() ? ctrl->in(0)->as_CallJava() : ctrl->as_CallJava();
CallProjections projs; CallProjections projs;
call->extract_projections(&projs, false, false); call->extract_projections(&projs, false, false);
@ -1362,7 +1362,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
if (idx < n->outcnt()) { if (idx < n->outcnt()) {
Node* u = n->raw_out(idx); Node* u = n->raw_out(idx);
Node* c = phase->ctrl_or_self(u); 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); stack.set_index(idx+1);
assert(!u->is_CFG(), ""); assert(!u->is_CFG(), "");
stack.push(u, 0); stack.push(u, 0);
@ -1404,14 +1404,11 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) {
} }
} }
} else { } else {
// assert(n_clone->outcnt() > 0, "");
// assert(n->outcnt() > 0, "");
stack.pop(); stack.pop();
clones.pop(); clones.pop();
} }
} while (stack.size() > 0); } while (stack.size() > 0);
assert(stack.size() == 0 && clones.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); head->verify_strip_mined(0);
} }
move_heap_stable_test_out_of_loop(iff, phase); move_heap_stable_test_out_of_loop(iff, phase);
AutoNodeBudget node_budget(phase);
if (loop->policy_unswitching(phase)) { if (loop->policy_unswitching(phase)) {
if (head->is_strip_mined()) { if (head->is_strip_mined()) {
OuterStripMinedLoopNode* outer = head->as_CountedLoop()->outer_loop(); OuterStripMinedLoopNode* outer = head->as_CountedLoop()->outer_loop();

View File

@ -45,10 +45,13 @@ void ShenandoahArguments::initialize() {
FLAG_SET_DEFAULT(ShenandoahGCHeuristics, "passive"); FLAG_SET_DEFAULT(ShenandoahGCHeuristics, "passive");
FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false); FLAG_SET_DEFAULT(ShenandoahSATBBarrier, false);
FLAG_SET_DEFAULT(ShenandoahLoadRefBarrier, false);
FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false); FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false);
FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, false); FLAG_SET_DEFAULT(ShenandoahStoreValEnqueueBarrier, false);
FLAG_SET_DEFAULT(ShenandoahCASBarrier, false); FLAG_SET_DEFAULT(ShenandoahCASBarrier, false);
FLAG_SET_DEFAULT(ShenandoahCloneBarrier, false); FLAG_SET_DEFAULT(ShenandoahCloneBarrier, false);
FLAG_SET_DEFAULT(ShenandoahVerifyOptoBarriers, false);
#endif #endif
#ifdef _LP64 #ifdef _LP64
@ -106,6 +109,7 @@ void ShenandoahArguments::initialize() {
// C2 barrier verification is only reliable when all default barriers are enabled // C2 barrier verification is only reliable when all default barriers are enabled
if (ShenandoahVerifyOptoBarriers && if (ShenandoahVerifyOptoBarriers &&
(!FLAG_IS_DEFAULT(ShenandoahSATBBarrier) || (!FLAG_IS_DEFAULT(ShenandoahSATBBarrier) ||
!FLAG_IS_DEFAULT(ShenandoahLoadRefBarrier) ||
!FLAG_IS_DEFAULT(ShenandoahKeepAliveBarrier) || !FLAG_IS_DEFAULT(ShenandoahKeepAliveBarrier) ||
!FLAG_IS_DEFAULT(ShenandoahStoreValEnqueueBarrier) || !FLAG_IS_DEFAULT(ShenandoahStoreValEnqueueBarrier) ||
!FLAG_IS_DEFAULT(ShenandoahCASBarrier) || !FLAG_IS_DEFAULT(ShenandoahCASBarrier) ||

View File

@ -89,7 +89,6 @@ void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) {
AlwaysTrueClosure always_true; AlwaysTrueClosure always_true;
WeakProcessor::weak_oops_do(&always_true, oops); WeakProcessor::weak_oops_do(&always_true, oops);
JvmtiExport::weak_oops_do(&always_true, oops);
if (ShenandoahStringDedup::is_enabled()) { if (ShenandoahStringDedup::is_enabled()) {
ShenandoahStringDedup::oops_do_slow(oops); ShenandoahStringDedup::oops_do_slow(oops);

View File

@ -35,10 +35,10 @@ class ZGranuleMap {
friend class ZGranuleMapIterator<T>; friend class ZGranuleMapIterator<T>;
private: private:
T* const _map; const size_t _size;
T* const _map;
size_t index_for_addr(uintptr_t addr) const; size_t index_for_addr(uintptr_t addr) const;
size_t size() const;
public: public:
ZGranuleMap(); ZGranuleMap();

View File

@ -31,11 +31,12 @@
template <typename T> template <typename T>
inline ZGranuleMap<T>::ZGranuleMap() : inline ZGranuleMap<T>::ZGranuleMap() :
_map(MmapArrayAllocator<T>::allocate(size(), mtGC)) {} _size(ZAddressOffsetMax >> ZGranuleSizeShift),
_map(MmapArrayAllocator<T>::allocate(_size, mtGC)) {}
template <typename T> template <typename T>
inline ZGranuleMap<T>::~ZGranuleMap() { inline ZGranuleMap<T>::~ZGranuleMap() {
MmapArrayAllocator<T>::free(_map, size()); MmapArrayAllocator<T>::free(_map, _size);
} }
template <typename T> 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"); assert(!ZAddress::is_null(addr), "Invalid address");
const size_t index = ZAddress::offset(addr) >> ZGranuleSizeShift; const size_t index = ZAddress::offset(addr) >> ZGranuleSizeShift;
assert(index < size(), "Invalid index"); assert(index < _size, "Invalid index");
return index; return index;
} }
template <typename T>
inline size_t ZGranuleMap<T>::size() const {
return ZAddressOffsetMax >> ZGranuleSizeShift;
}
template <typename T> template <typename T>
inline T ZGranuleMap<T>::get(uintptr_t addr) const { inline T ZGranuleMap<T>::get(uintptr_t addr) const {
const size_t index = index_for_addr(addr); const size_t index = index_for_addr(addr);
@ -83,7 +79,7 @@ inline ZGranuleMapIterator<T>::ZGranuleMapIterator(const ZGranuleMap<T>* map) :
template <typename T> template <typename T>
inline bool ZGranuleMapIterator<T>::next(T* value) { inline bool ZGranuleMapIterator<T>::next(T* value) {
if (_next < _map->size()) { if (_next < _map->_size) {
*value = _map->_map[_next++]; *value = _map->_map[_next++];
return true; return true;
} }
@ -94,7 +90,7 @@ inline bool ZGranuleMapIterator<T>::next(T* value) {
template <typename T> template <typename T>
inline bool ZGranuleMapIterator<T>::next(T** value) { inline bool ZGranuleMapIterator<T>::next(T** value) {
if (_next < _map->size()) { if (_next < _map->_size) {
*value = _map->_map + _next++; *value = _map->_map + _next++;
return true; return true;
} }

View File

@ -28,6 +28,7 @@
#include "compiler/disassembler.hpp" #include "compiler/disassembler.hpp"
#include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/bytecodeInterpreter.hpp" #include "interpreter/bytecodeInterpreter.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp" #include "interpreter/interpreterRuntime.hpp"
#include "interpreter/interp_masm.hpp" #include "interpreter/interp_masm.hpp"
@ -36,6 +37,8 @@
#include "memory/metaspaceShared.hpp" #include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/arrayOop.hpp" #include "oops/arrayOop.hpp"
#include "oops/constantPool.hpp"
#include "oops/cpCache.inline.hpp"
#include "oops/methodData.hpp" #include "oops/methodData.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "oops/oop.inline.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 // Return true if the interpreter can prove that the given bytecode has
// not yet been executed (in Java semantics, not in actual operation). // not yet been executed (in Java semantics, not in actual operation).
bool AbstractInterpreter::is_not_reached(const methodHandle& method, int bci) { 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 // might have been reached
return false; return false;
} }

View File

@ -170,6 +170,10 @@ class BytecodeStream: public BaseBytecodeStream {
// Construction // Construction
BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { } BytecodeStream(const methodHandle& method) : BaseBytecodeStream(method) { }
BytecodeStream(const methodHandle& method, int bci) : BaseBytecodeStream(method) {
set_start(bci);
}
// Iteration // Iteration
Bytecodes::Code next() { Bytecodes::Code next() {
Bytecodes::Code raw_code, code; Bytecodes::Code raw_code, code;

File diff suppressed because it is too large Load Diff

View File

@ -160,13 +160,14 @@ class JavaArgumentUnboxer : public SignatureIterator {
}; };
class JNIHandleMark : public StackObj { class JNIHandleMark : public StackObj {
JavaThread* _thread;
public: public:
JNIHandleMark() { push_jni_handle_block(); } JNIHandleMark(JavaThread* thread) : _thread(thread) { push_jni_handle_block(thread); }
~JNIHandleMark() { pop_jni_handle_block(); } ~JNIHandleMark() { pop_jni_handle_block(_thread); }
private: private:
static void push_jni_handle_block(); static void push_jni_handle_block(JavaThread* thread);
static void pop_jni_handle_block(); static void pop_jni_handle_block(JavaThread* thread);
}; };
#endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP #endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP

View File

@ -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) { if (_shared_library_javavm == NULL) {
MutexLocker locker(JVMCI_lock); MutexLocker locker(JVMCI_lock);
if (_shared_library_javavm == NULL) { if (_shared_library_javavm == NULL) {
char path[JVM_MAXPATHLEN]; char path[JVM_MAXPATHLEN];
char ebuf[1024]; char ebuf[1024];
if (JVMCILibPath != NULL) { 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; 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. // By default there is only one runtime which is the compiler runtime.
_runtime = JVMCI::compiler_runtime(); _runtime = JVMCI::compiler_runtime();
_env = NULL;
_pop_frame_on_close = false;
_detach_on_close = false;
if (!UseJVMCINativeLibrary) { if (!UseJVMCINativeLibrary) {
// In HotSpot mode, JNI isn't used at all. // In HotSpot mode, JNI isn't used at all.
_is_hotspot = true; _is_hotspot = true;
_env = NULL;
return; return;
} }
if (parent_env != NULL) { if (parent_env != NULL) {
// If the parent JNI environment is non-null then figure out whether it // 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. // is a HotSpot or shared library JNIEnv and set the state appropriately.
JavaThread* thread = JavaThread::current(); _is_hotspot = thread->jni_environment() == parent_env;
if (thread->jni_environment() == parent_env) { if (_is_hotspot) {
// Select the Java runtime // Select the Java runtime
_runtime = JVMCI::java_runtime(); _runtime = JVMCI::java_runtime();
_is_hotspot = true;
_env = NULL;
return; 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; _is_hotspot = false;
_env = attach_shared_library(); _env = init_shared_library(thread);
assert(parent_env == NULL || _env == parent_env, "must be");
if (parent_env == NULL) { if (_env != NULL) {
// There is no parent shared library JNI env so push // Creating the JVMCI shared library VM also attaches the current thread
// a JNI local frame to release all local handles in _detach_on_close = true;
// this JVMCIEnv scope when it's closed. } else {
assert(_throw_to_caller == false, "must be"); _shared_library_javavm->GetEnv((void**)&parent_env, JNI_VERSION_1_2);
JNIAccessMark jni(this); if (parent_env != NULL) {
jint result = _env->PushLocalFrame(32); // Even though there's a parent JNI env, there's no guarantee
if (result != JNI_OK) { // it was opened by a JVMCIEnv scope and thus may not have
char message[256]; // pushed a local JNI frame. As such, we use a new JNI local
jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line); // frame in this scope to ensure local JNI refs are collected
JVMCIRuntime::exit_on_pending_exception(this, message); // 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) { _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): JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line):
_throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) { _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) { _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"); 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; _compile_state = NULL;
_throw_to_caller = false; _throw_to_caller = false;
_file = file; _file = file;
_line = line; _line = line;
if (is_hotspot) { if (is_hotspot) {
_env = NULL; _env = NULL;
_pop_frame_on_close = false;
_detach_on_close = false;
_is_hotspot = true; _is_hotspot = true;
_runtime = JVMCI::java_runtime(); _runtime = JVMCI::java_runtime();
} else { } else {
init_env_mode_runtime(NULL); init_env_mode_runtime(thread, NULL);
} }
} }
@ -324,7 +345,7 @@ JVMCIEnv::~JVMCIEnv() {
} }
} }
} else { } else {
if (!is_hotspot()) { if (_pop_frame_on_close) {
// Pop the JNI local frame that was pushed when entering this JVMCIEnv scope. // Pop the JNI local frame that was pushed when entering this JVMCIEnv scope.
JNIAccessMark jni(this); JNIAccessMark jni(this);
jni()->PopLocalFrame(NULL); jni()->PopLocalFrame(NULL);
@ -335,6 +356,10 @@ JVMCIEnv::~JVMCIEnv() {
jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line); jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line);
JVMCIRuntime::exit_on_pending_exception(this, message); 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) { void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length) {
if (size_in_bytes == 0) { if (length == 0) {
return; return;
} }
if (is_hotspot()) { 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 { } else {
JNIAccessMark jni(this); 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) { void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
if (size_in_bytes == 0) { if (length == 0) {
return; return;
} }
if (is_hotspot()) { 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 { } else {
JNIAccessMark jni(this); 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(IllegalArgumentException)
DO_THROW(InvalidInstalledCodeException) DO_THROW(InvalidInstalledCodeException)
DO_THROW(UnsatisfiedLinkError) DO_THROW(UnsatisfiedLinkError)
DO_THROW(UnsupportedOperationException)
DO_THROW(ClassNotFoundException)
#undef DO_THROW #undef DO_THROW
@ -888,7 +927,7 @@ JVMCIObject JVMCIEnv::new_StackTraceElement(const methodHandle& method, int bci,
return JVMCIObject(); return JVMCIObject();
} }
jobject file_name = NULL; jobject file_name = NULL;
if (file_name != NULL) { if (file_name_sym != NULL) {
file_name = jni()->NewStringUTF(file_name_sym->as_C_string()); file_name = jni()->NewStringUTF(file_name_sym->as_C_string());
if (jni()->ExceptionCheck()) { if (jni()->ExceptionCheck()) {
return JVMCIObject(); return JVMCIObject();
@ -1323,14 +1362,15 @@ Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type"); assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type");
oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant)); oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant));
return Handle(THREAD, obj); return Handle(THREAD, obj);
} else { } else if (isa_IndirectHotSpotObjectConstantImpl(constant)) {
assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type");
jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant); jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant);
oop result = resolve_handle(object_handle); oop result = resolve_handle(object_handle);
if (result == NULL) { if (result == NULL) {
JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle()); JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());
} }
return Handle(THREAD, result); return Handle(THREAD, result);
} else {
JVMCI_THROW_MSG_(IllegalArgumentException, "DirectHotSpotObjectConstantImpl shouldn't reach JVMCI in SVM mode", Handle());
} }
} }

View File

@ -36,15 +36,6 @@ class JVMCIPrimitiveArray;
class JVMCICompiler; class JVMCICompiler;
class JVMCIRuntime; 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 \ #define JVMCI_EXCEPTION_CONTEXT \
JavaThread* thread=JavaThread::current(); \ JavaThread* thread=JavaThread::current(); \
Thread* THREAD = thread; Thread* THREAD = thread;
@ -154,24 +145,25 @@ class JVMCIEnv : public ResourceObj {
static void* _shared_library_handle; // result of os::dll_load static void* _shared_library_handle; // result of os::dll_load
static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library
// Attaches the current thread to the JavaVM in the shared library, // Initializes the shared library JavaVM if not already initialized.
// initializing the shared library VM first if necessary. // Returns the JNI interface pointer for the current thread
// Returns the JNI interface pointer of the current thread. // if initialization was performed by this call, NULL if
// The _shared_library_* fields are initialized by the first // initialization was performed by a previous call.
// call to this method. static JNIEnv* init_shared_library(JavaThread* thread);
static JNIEnv* attach_shared_library();
// Initializes the _env, _mode and _runtime fields. // 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 JNIEnv* _env; // JNI env for calling into shared library
JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime bool _pop_frame_on_close; // Must pop frame on close?
bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in bool _detach_on_close; // Must detach on close?
bool _throw_to_caller; // Propagate an exception raised in this env to the caller? JVMCIRuntime* _runtime; // Access to a HotSpotJVMCIRuntime
const char* _file; // The file and ... bool _is_hotspot; // Which heap is the HotSpotJVMCIRuntime in
int _line; // ... line where this JNIEnv was created 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 // Translates an exception on the HotSpot heap to an exception on
// the shared library heap. The translation includes the stack and // 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. // scope closes so that it will be propagated back to Java.
// The JVMCIEnv destructor translates the exception object for the // The JVMCIEnv destructor translates the exception object for the
// Java runtime if necessary. // 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. // Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker.
// An exception occurring within the scope must not be propagated back to // An exception occurring within the scope must not be propagated back to
// the CompileBroker. // 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 // 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. // 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 // Opens a JNIEnv scope for accessing `for_object`. An exception occurring
// within the scope must not be propagated back to the caller. // 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 // 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 // can block or take a long time so do not allow such access
// on the VM thread. // on the VM thread.
assert(for_object.is_hotspot() || !Thread::current()->is_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"); "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 // Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true
// otherwise for the shared library runtime. An exception occurring // otherwise for the shared library runtime. An exception occurring
// within the scope must not be propagated back to the caller. // within the scope must not be propagated back to the caller.
JVMCIEnv(bool is_hotspot, const char* file, int line) { JVMCIEnv(JavaThread* thread, bool is_hotspot, const char* file, int line) {
init(is_hotspot, file, line); init(thread, is_hotspot, file, line);
} }
~JVMCIEnv(); ~JVMCIEnv();
@ -247,8 +239,10 @@ public:
long get_long_at(JVMCIPrimitiveArray array, int index); long get_long_at(JVMCIPrimitiveArray array, int index);
void put_long_at(JVMCIPrimitiveArray array, int index, jlong value); 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_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length);
void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes); 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); JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS);
@ -323,6 +317,8 @@ public:
DO_THROW(IllegalArgumentException) DO_THROW(IllegalArgumentException)
DO_THROW(InvalidInstalledCodeException) DO_THROW(InvalidInstalledCodeException)
DO_THROW(UnsatisfiedLinkError) DO_THROW(UnsatisfiedLinkError)
DO_THROW(UnsupportedOperationException)
DO_THROW(ClassNotFoundException)
#undef DO_THROW #undef DO_THROW

View File

@ -32,8 +32,8 @@ class JVMCIEnv;
#define JVMCIENV __jvmci_env__ #define JVMCIENV __jvmci_env__
#define JVMCI_TRAPS JVMCIEnv* JVMCIENV #define JVMCI_TRAPS JVMCIEnv* JVMCIENV
#define JNI_JVMCIENV(env) \ #define JNI_JVMCIENV(thread, env) \
JVMCIEnv __stack_jvmci_env__(env, __FILE__, __LINE__); \ JVMCIEnv __stack_jvmci_env__(thread, env, __FILE__, __LINE__); \
JVMCIEnv* JVMCIENV = &__stack_jvmci_env__ JVMCIEnv* JVMCIENV = &__stack_jvmci_env__
#define THREAD_JVMCIENV(thread) \ #define THREAD_JVMCIENV(thread) \

View File

@ -356,6 +356,43 @@ extern "C" {
jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass 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() #define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string()
/** /**
* Initializes the JNI method and field ids used in JNIJVMCI. * 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(); fileStream* st = JVMCIGlobals::get_jni_config_file();
DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM()); DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM());
ThrowableInitDumper dumper(st);
vmSymbols::symbols_do(&dumper);
st->flush(); st->flush();
tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig); tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig);

View File

@ -381,12 +381,18 @@
start_class(InternalError, java_lang_InternalError) \ start_class(InternalError, java_lang_InternalError) \
jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \ jvmci_constructor(InternalError, "(Ljava/lang/String;)V") \
end_class \ 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) \ start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException) \
jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \ jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V") \
end_class \ end_class \
start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \ start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError) \
jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \ jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V") \
end_class \ end_class \
start_class(UnsupportedOperationException, java_lang_UnsupportedOperationException) \
jvmci_constructor(UnsupportedOperationException, "(Ljava/lang/String;)V") \
end_class \
start_class(StackTraceElement, java_lang_StackTraceElement) \ start_class(StackTraceElement, java_lang_StackTraceElement) \
object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \ object_field(StackTraceElement, declaringClass, "Ljava/lang/String;") \
object_field(StackTraceElement, methodName, "Ljava/lang/String;") \ object_field(StackTraceElement, methodName, "Ljava/lang/String;") \

View File

@ -655,7 +655,7 @@ JRT_END
// private static JVMCIRuntime JVMCI.initializeRuntime() // private static JVMCIRuntime JVMCI.initializeRuntime()
JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
JNI_JVMCIENV(env); JNI_JVMCIENV(thread, env);
if (!EnableJVMCI) { if (!EnableJVMCI) {
JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled"); 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"); fatal("check TLAB allocation code for address space conflicts");
#endif #endif
JNI_JVMCIENV(env); JNI_JVMCIENV(thread, env);
if (!EnableJVMCI) { if (!EnableJVMCI) {
JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled"); 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"); compile_state->set_failure(true, "No OSR during boostrap");
return; return;
} }
if (JVMCI::shutdown_called()) {
compile_state->set_failure(false, "Avoiding compilation during shutdown");
return;
}
HandleMark hm; HandleMark hm;
JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV); JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV);

View File

@ -83,7 +83,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() {
} }
FLAG_SET_DEFAULT(EnableJVMCI, true); FLAG_SET_DEFAULT(EnableJVMCI, true);
if (BootstrapJVMCI && UseJVMCINativeLibrary) { 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; return false;
} }
} }

View File

@ -53,7 +53,10 @@
"Prints properties used by the JVMCI compiler and exits") \ "Prints properties used by the JVMCI compiler and exits") \
\ \
experimental(bool, BootstrapJVMCI, false, \ 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, \ experimental(bool, EagerJVMCI, false, \
"Force eager JVMCI initialization") \ "Force eager JVMCI initialization") \

View File

@ -246,6 +246,10 @@
\ \
nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \ 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, _mark, markOop) \
volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \
\ \
@ -347,6 +351,7 @@
declare_toplevel_type(JVMCIEnv) \ declare_toplevel_type(JVMCIEnv) \
declare_toplevel_type(LocalVariableTableElement) \ declare_toplevel_type(LocalVariableTableElement) \
declare_toplevel_type(narrowKlass) \ declare_toplevel_type(narrowKlass) \
declare_toplevel_type(ObjectWaiter) \
declare_toplevel_type(Symbol*) \ declare_toplevel_type(Symbol*) \
declare_toplevel_type(vtableEntry) \ declare_toplevel_type(vtableEntry) \
\ \

View File

@ -506,7 +506,7 @@ Method* ConstantPoolCacheEntry::method_if_resolved(const constantPoolHandle& cpo
switch (invoke_code) { switch (invoke_code) {
case Bytecodes::_invokeinterface: case Bytecodes::_invokeinterface:
assert(f1->is_klass(), ""); 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::_invokestatic:
case Bytecodes::_invokespecial: case Bytecodes::_invokespecial:
assert(!has_appendix(), ""); assert(!has_appendix(), "");

View File

@ -2965,6 +2965,13 @@ void InstanceKlass::adjust_default_methods(bool* trace_name_printed) {
// On-stack replacement stuff // On-stack replacement stuff
void InstanceKlass::add_osr_nmethod(nmethod* n) { 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 // only one compilation can be active
{ {
// This is a short non-blocking critical region, so the no safepoint check is ok. // 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(); 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 best;
} }
return NULL; return NULL;

View File

@ -733,8 +733,9 @@ void Klass::print_on(outputStream* st) const {
st->cr(); st->cr();
} }
#define BULLET " - "
void Klass::oop_print_on(oop obj, outputStream* st) { void Klass::oop_print_on(oop obj, outputStream* st) {
ResourceMark rm;
// print title // print title
st->print_cr("%s ", internal_name()); st->print_cr("%s ", internal_name());
obj->print_address_on(st); obj->print_address_on(st);
@ -742,10 +743,13 @@ void Klass::oop_print_on(oop obj, outputStream* st) {
if (WizardMode) { if (WizardMode) {
// print header // print header
obj->mark()->print_on(st); obj->mark()->print_on(st);
st->cr();
st->print(BULLET"prototype_header: " INTPTR_FORMAT, p2i(_prototype_header));
st->cr();
} }
// print class // print class
st->print(" - klass: "); st->print(BULLET"klass: ");
obj->klass()->print_value_on(st); obj->klass()->print_value_on(st);
st->cr(); st->cr();
} }

View File

@ -25,45 +25,40 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "oops/markOop.hpp" #include "oops/markOop.hpp"
#include "runtime/thread.inline.hpp" #include "runtime/thread.inline.hpp"
#include "runtime/objectMonitor.inline.hpp" #include "runtime/objectMonitor.hpp"
void markOopDesc::print_on(outputStream* st) const { void markOopDesc::print_on(outputStream* st) const {
if (is_marked()) { if (is_marked()) { // last bits = 11
st->print(" marked(" INTPTR_FORMAT ")", value()); 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() // have to check has_monitor() before is_locked()
st->print(" monitor(" INTPTR_FORMAT ")=", value()); st->print(" monitor(" INTPTR_FORMAT ")=", value());
ObjectMonitor* mon = monitor(); ObjectMonitor* mon = monitor();
if (mon == NULL) { if (mon == NULL) {
st->print("NULL (this should never be seen!)"); st->print("NULL (this should never be seen!)");
} else { } else {
st->print("{contentions=0x%08x,waiters=0x%08x" mon->print_on(st);
",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}",
mon->contentions(), mon->waiters(), mon->recursions(),
p2i(mon->owner()));
} }
} else if (is_locked()) { } else if (is_locked()) { // last bits != 01 => 00
st->print(" locked(" INTPTR_FORMAT ")->", value()); // thin locked
if (is_neutral()) { 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"); st->print("is_neutral");
if (has_no_hash()) { if (has_no_hash()) {
st->print(" no_hash"); st->print(" no_hash");
} else { } else {
st->print(" hash=" INTPTR_FORMAT, hash()); st->print(" hash=" INTPTR_FORMAT, hash());
} }
st->print(" age=%d", age()); } else if (has_bias_pattern()) { // last bits = 101
} else if (has_bias_pattern()) {
st->print("is_biased"); st->print("is_biased");
JavaThread* jt = biased_locker(); 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 { } else {
st->print("??"); st->print("??");
} }
} else { st->print(" age=%d)", age());
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());
} }
} }

View File

@ -624,6 +624,10 @@ bool Method::can_be_statically_bound() const {
return can_be_statically_bound(method_holder()->access_flags()); 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 { bool Method::is_accessor() const {
return is_getter() || is_setter(); return is_getter() || is_setter();
} }

View File

@ -619,6 +619,7 @@ class Method : public Metadata {
// true if method needs no dynamic dispatch (final and/or no vtable entry) // true if method needs no dynamic dispatch (final and/or no vtable entry)
bool can_be_statically_bound() const; bool can_be_statically_bound() const;
bool can_be_statically_bound(InstanceKlass* context) const;
bool can_be_statically_bound(AccessFlags class_access_flags) const; bool can_be_statically_bound(AccessFlags class_access_flags) const;
// returns true if the method has any backward branches. // returns true if the method has any backward branches.

View File

@ -321,6 +321,35 @@ bool InlineTree::should_not_inline(ciMethod *callee_method,
return false; 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----------------------------------- //-----------------------------try_to_inline-----------------------------------
// return true if ok // return true if ok
// Relocated from "InliningClosure::try_to_inline" // 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. // inline constructors even if they are not reached.
} else if (forced_inline()) { } else if (forced_inline()) {
// Inlining was forced by CompilerOracle, ciReplay or annotation // 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 // don't inline unreached call sites
set_msg("call site not reached"); set_msg("call site not reached");
return false; return false;

View File

@ -1152,14 +1152,19 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass*
cha_monomorphic_target = NULL; cha_monomorphic_target = NULL;
} }
} }
if (cha_monomorphic_target != NULL) { if (cha_monomorphic_target != NULL) {
// Hardwiring a virtual. // Hardwiring a virtual.
// If we inlined because CHA revealed only a single target method, assert(!callee->can_be_statically_bound(), "should have been handled earlier");
// then we are dependent on that target method not getting overridden assert(!cha_monomorphic_target->is_abstract(), "");
// by dynamic class loading. Be sure to test the "static" receiver if (!cha_monomorphic_target->can_be_statically_bound(actual_receiver)) {
// dest_method here, as opposed to the actual receiver, which may // If we inlined because CHA revealed only a single target method,
// falsely lead us to believe that the receiver is final or private. // then we are dependent on that target method not getting overridden
dependencies()->assert_unique_concrete_method(actual_receiver, cha_monomorphic_target); // 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; return cha_monomorphic_target;
} }

File diff suppressed because it is too large Load Diff

View File

@ -55,27 +55,31 @@
// Return TRUE or FALSE if the loop should be unswitched // Return TRUE or FALSE if the loop should be unswitched
// (ie. clone loop with an invariant test that does not exit the loop) // (ie. clone loop with an invariant test that does not exit the loop)
bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const { bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const {
if( !LoopUnswitching ) { if (!LoopUnswitching) {
return false; return false;
} }
if (!_head->is_Loop()) { if (!_head->is_Loop()) {
return false; 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 // 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; 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(); LoopNode* head = _head->as_Loop();
if (head->unswitch_count() + 1 > head->unswitch_max()) { if (head->unswitch_count() + 1 > head->unswitch_max()) {
return false; 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----------------------------- //------------------------------find_unswitching_candidate-----------------------------

View File

@ -42,17 +42,13 @@
#include "opto/superword.hpp" #include "opto/superword.hpp"
//============================================================================= //=============================================================================
//------------------------------is_loop_iv------------------------------------- //--------------------------is_cloop_ind_var-----------------------------------
// Determine if a node is Counted loop induction variable. // Determine if a node is a counted loop induction variable.
// The method is declared in node.hpp. // NOTE: The method is declared in "node.hpp".
const Node* Node::is_loop_iv() const { bool Node::is_cloop_ind_var() const {
if (this->is_Phi() && !this->as_Phi()->is_copy() && return (is_Phi() && !as_Phi()->is_copy() &&
this->as_Phi()->region()->is_CountedLoop() && as_Phi()->region()->is_CountedLoop() &&
this->as_Phi()->region()->as_CountedLoop()->phi() == this) { as_Phi()->region()->as_CountedLoop()->phi() == this);
return this;
} else {
return NULL;
}
} }
//============================================================================= //=============================================================================
@ -2942,14 +2938,15 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
} }
if (ReassociateInvariants) { if (ReassociateInvariants) {
AutoNodeBudget node_budget(this, AutoNodeBudget::NO_BUDGET_CHECK);
// Reassociate invariants and prep for split_thru_phi // Reassociate invariants and prep for split_thru_phi
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) { for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
IdealLoopTree* lpt = iter.current(); IdealLoopTree* lpt = iter.current();
bool is_counted = lpt->is_counted(); 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 // 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); lpt->reassociate_invariants(this);

View File

@ -264,7 +264,7 @@ public:
bool is_reduction_loop() const { return (_loop_flags&HasReductions) == HasReductions; } bool is_reduction_loop() const { return (_loop_flags&HasReductions) == HasReductions; }
bool was_slp_analyzed () const { return (_loop_flags&WasSlpAnalyzed) == WasSlpAnalyzed; } bool was_slp_analyzed () const { return (_loop_flags&WasSlpAnalyzed) == WasSlpAnalyzed; }
bool has_passed_slp () const { return (_loop_flags&PassedSlpAnalysis) == PassedSlpAnalysis; } 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 is_main_no_pre_loop() const { return _loop_flags & MainHasNoPreLoop; }
bool has_atomic_post_loop () const { return (_loop_flags & HasAtomicPostLoop) == HasAtomicPostLoop; } bool has_atomic_post_loop () const { return (_loop_flags & HasAtomicPostLoop) == HasAtomicPostLoop; }
void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; } void set_main_no_pre_loop() { _loop_flags |= MainHasNoPreLoop; }
@ -370,26 +370,49 @@ public:
}; };
inline CountedLoopEndNode *CountedLoopNode::loopexit_or_null() const { inline CountedLoopEndNode* CountedLoopNode::loopexit_or_null() const {
Node *bc = back_control(); Node* bctrl = back_control();
if( bc == NULL ) return NULL; if (bctrl == NULL) return NULL;
Node *le = bc->in(0);
if( le->Opcode() != Op_CountedLoopEnd ) Node* lexit = bctrl->in(0);
return NULL; return (CountedLoopEndNode*)
return (CountedLoopEndNode*)le; (lexit->Opcode() == Op_CountedLoopEnd ? lexit : NULL);
} }
inline CountedLoopEndNode *CountedLoopNode::loopexit() const {
inline CountedLoopEndNode* CountedLoopNode::loopexit() const {
CountedLoopEndNode* cle = loopexit_or_null(); CountedLoopEndNode* cle = loopexit_or_null();
assert(cle != NULL, "loopexit is NULL"); assert(cle != NULL, "loopexit is NULL");
return cle; 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 Node* CountedLoopNode::init_trip() const {
inline int CountedLoopNode::stride_con() const { return loopexit_or_null() ? loopexit()->stride_con() : 0; } CountedLoopEndNode* cle = loopexit_or_null();
inline bool CountedLoopNode::stride_is_con() const { return loopexit_or_null() && loopexit()->stride_is_con(); } return cle != NULL ? cle->init_trip() : NULL;
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::stride() const {
inline Node *CountedLoopNode::phi() const { return loopexit_or_null() ? loopexit()->phi() : NULL; } 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----------------------------- //------------------------------LoopLimitNode-----------------------------
// Counted Loop limit node which represents exact final iterator value: // Counted Loop limit node which represents exact final iterator value:
@ -456,9 +479,9 @@ public:
IdealLoopTree *_child; // First child in loop tree IdealLoopTree *_child; // First child in loop tree
// The head-tail backedge defines the loop. // The head-tail backedge defines the loop.
// If tail is NULL then this loop has multiple backedges as part of the // If a loop has multiple backedges, this is addressed during cleanup where
// same loop. During cleanup I'll peel off the multiple backedges; merge // we peel off the multiple backedges, merging all edges at the bottom and
// them at the loop bottom and flow 1 real backedge into the loop. // ensuring that one proper backedge flow into the loop.
Node *_head; // Head of loop Node *_head; // Head of loop
Node *_tail; // Tail of loop Node *_tail; // Tail of loop
inline Node *tail(); // Handle lazy update of _tail field inline Node *tail(); // Handle lazy update of _tail field
@ -487,7 +510,10 @@ public:
_safepts(NULL), _safepts(NULL),
_required_safept(NULL), _required_safept(NULL),
_allow_optimizations(true) _allow_optimizations(true)
{ } {
precond(_head != NULL);
precond(_tail != NULL);
}
// Is 'l' a member of 'this'? // Is 'l' a member of 'this'?
bool is_member(const IdealLoopTree *l) const; // Test for nested membership bool is_member(const IdealLoopTree *l) const; // Test for nested membership
@ -558,10 +584,10 @@ public:
bool policy_unswitching( PhaseIdealLoop *phase ) const; bool policy_unswitching( PhaseIdealLoop *phase ) const;
// Micro-benchmark spamming. Remove empty loops. // 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. // 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 // 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 // make some loop-invariant test (usually a null-check) happen before the
@ -615,9 +641,11 @@ public:
// Put loop body on igvn work list // Put loop body on igvn work list
void record_for_igvn(); void record_for_igvn();
bool is_loop() { return !_irreducible && _tail && !_tail->is_top(); } bool is_root() { return _parent == NULL; }
bool is_inner() { return is_loop() && _child == NULL; } // A proper/reducible loop w/o any (occasional) dead back-edge.
bool is_counted() { return is_loop() && _head != NULL && _head->is_CountedLoop(); } 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); void remove_main_post_loops(CountedLoopNode *cl, PhaseIdealLoop *phase);
@ -630,13 +658,14 @@ public:
}; };
// -----------------------------PhaseIdealLoop--------------------------------- // -----------------------------PhaseIdealLoop---------------------------------
// Computes the mapping from Nodes to IdealLoopTrees. Organizes IdealLoopTrees into a // Computes the mapping from Nodes to IdealLoopTrees. Organizes IdealLoopTrees
// loop tree. Drives the loop-based transformations on the ideal graph. // into a loop tree. Drives the loop-based transformations on the ideal graph.
class PhaseIdealLoop : public PhaseTransform { class PhaseIdealLoop : public PhaseTransform {
friend class IdealLoopTree; friend class IdealLoopTree;
friend class SuperWord; friend class SuperWord;
friend class CountedLoopReserveKit; friend class CountedLoopReserveKit;
friend class ShenandoahBarrierC2Support; friend class ShenandoahBarrierC2Support;
friend class AutoNodeBudget;
// Pre-computed def-use info // Pre-computed def-use info
PhaseIterGVN &_igvn; PhaseIterGVN &_igvn;
@ -731,8 +760,7 @@ private:
} }
Node *dom_lca_for_get_late_ctrl_internal( Node *lca, Node *n, Node *tag ); Node *dom_lca_for_get_late_ctrl_internal( Node *lca, Node *n, Node *tag );
// Helper function for directing control inputs away from CFG split // Helper function for directing control inputs away from CFG split points.
// points.
Node *find_non_split_ctrl( Node *ctrl ) const { Node *find_non_split_ctrl( Node *ctrl ) const {
if (ctrl != NULL) { if (ctrl != NULL) {
if (ctrl->is_MultiBranch()) { if (ctrl->is_MultiBranch()) {
@ -883,7 +911,8 @@ private:
_igvn(igvn), _igvn(igvn),
_verify_me(NULL), _verify_me(NULL),
_verify_only(true), _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); build_and_optimize(LoopOptsVerify);
} }
@ -899,7 +928,8 @@ private:
_igvn(igvn), _igvn(igvn),
_verify_me(NULL), _verify_me(NULL),
_verify_only(false), _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); build_and_optimize(mode);
} }
@ -909,7 +939,8 @@ private:
_igvn(igvn), _igvn(igvn),
_verify_me(verify_me), _verify_me(verify_me),
_verify_only(false), _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); build_and_optimize(LoopOptsVerify);
} }
@ -1320,8 +1351,54 @@ private:
return C->live_nodes() > threshold; 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; bool _created_loop_node;
public: public:
uint nodes_required() const { return _nodes_required; }
void set_created_loop_node() { _created_loop_node = true; } void set_created_loop_node() { _created_loop_node = true; }
bool created_loop_node() { return _created_loop_node; } bool created_loop_node() { return _created_loop_node; }
void register_new_node( Node *n, Node *blk ); 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; 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 // This kit may be used for making of a reserved copy of a loop before this loop
// goes under non-reversible changes. // goes under non-reversible changes.
// //
@ -1410,14 +1543,11 @@ class CountedLoopReserveKit {
};// class CountedLoopReserveKit };// class CountedLoopReserveKit
inline Node* IdealLoopTree::tail() { inline Node* IdealLoopTree::tail() {
// Handle lazy update of _tail field // Handle lazy update of _tail field.
Node *n = _tail; if (_tail->in(0) == NULL) {
//while( !n->in(0) ) // Skip dead CFG nodes _tail = _phase->get_ctrl(_tail);
//n = n->in(1); }
if (n->in(0) == NULL) return _tail;
n = _phase->get_ctrl(n);
_tail = n;
return n;
} }

View File

@ -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"); assert(!loop->is_member(get_loop(use_c)), "should be outside loop");
get_loop(use_c)->_body.push(n_clone); get_loop(use_c)->_body.push(n_clone);
_igvn.register_new_node_with_optimizer(n_clone); _igvn.register_new_node_with_optimizer(n_clone);
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("loop exit cloning old: %d new: %d newbb: %d", n->_idx, n_clone->_idx, get_ctrl(n_clone)->_idx); 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)); set_ctrl(n_clone, get_ctrl(n));
sink_list.push(n_clone); sink_list.push(n_clone);
not_peel <<= n_clone->_idx; // add n_clone to not_peel set. not_peel <<= n_clone->_idx; // add n_clone to not_peel set.
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("special not_peeled cloning old: %d new: %d", n->_idx, n_clone->_idx); 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_CatchProj ||
opc == Op_Jump || opc == Op_Jump ||
opc == Op_JumpProj) { opc == Op_JumpProj) {
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("\nExit control too complex: lp: %d", head->_idx); 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; return false;
} }
#if !defined(PRODUCT) #ifndef PRODUCT
if (TraceLoopOpts) { if (TraceLoopOpts) {
tty->print("PartialPeel "); tty->print("PartialPeel ");
loop->dump_head(); loop->dump_head();
@ -3131,6 +3131,10 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) {
Node_List worklist(area); Node_List worklist(area);
Node_List sink_list(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 // Set of cfg nodes to peel are those that are executable from
// the head through last_peel. // the head through last_peel.
assert(worklist.size() == 0, "should be empty"); 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 (use->is_Phi()) old_phi_cnt++;
} }
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("\npeeled list"); 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; uint cloned_for_outside_use = 0;
for (i = 0; i < peel_list.size();) { for (i = 0; i < peel_list.size();) {
Node* n = peel_list.at(i); Node* n = peel_list.at(i);
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) n->dump(); if (TracePartialPeeling) n->dump();
#endif #endif
bool incr = true; 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. not_peel <<= n->_idx; // add n to not_peel set.
peel_list.remove(i); peel_list.remove(i);
incr = false; incr = false;
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("sink to not_peeled region: %d newbb: %d", tty->print_cr("sink to not_peeled region: %d newbb: %d",
n->_idx, get_ctrl(n)->_idx); 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 (new_phi_cnt > old_phi_cnt + PartialPeelNewPhiDelta) {
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("\nToo many new phis: %d old %d new cmpi: %c", 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'); 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(); C->set_major_progress();
loop->record_for_igvn(); loop->record_for_igvn();
#if !defined(PRODUCT) #ifndef PRODUCT
if (TracePartialPeeling) { if (TracePartialPeeling) {
tty->print_cr("\nafter partial peel one iteration"); tty->print_cr("\nafter partial peel one iteration");
Node_List wl(area); Node_List wl(area);
@ -3429,10 +3433,10 @@ void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) {
Node *exit = cle->proj_out(false); Node *exit = cle->proj_out(false);
Node *phi = cl->phi(); Node *phi = cl->phi();
// Check for the special case of folks using the pre-incremented // Check for the special case when using the pre-incremented trip-counter on
// trip-counter on the fall-out path (forces the pre-incremented // the fall-out path (forces the pre-incremented and post-incremented trip
// and post-incremented trip counter to be live at the same time). // counter to be live at the same time). Fix this by adjusting to use the
// Fix this by adjusting to use the post-increment trip counter. // post-increment trip counter.
bool progress = true; bool progress = true;
while (progress) { while (progress) {

View File

@ -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). // Try harder before giving up. Unify base pointers with casts (e.g., raw/non-raw pointers).
intptr_t st_off = 0; intptr_t st_off = 0;
Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_off); Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_off);
if (ld_base == NULL) return NULL; if (ld_base == NULL) return NULL;
if (st_base == NULL) return NULL; if (st_base == NULL) return NULL;
if (ld_base->uncast() != st_base->uncast()) return NULL; if (!ld_base->eqv_uncast(st_base, /*keep_deps=*/true)) return NULL;
if (ld_off != st_off) return NULL; if (ld_off != st_off) return NULL;
if (ld_off == Type::OffsetBot) return NULL; if (ld_off == Type::OffsetBot) return NULL;
// Same base, same offset. // Same base, same offset.
// Possible improvement for arrays: check index value instead of absolute 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.) // (Actually, we haven't yet proven the Q's are the same.)
// In other words, we are loading from a casted version of // In other words, we are loading from a casted version of
// the same pointer-and-offset that we stored to. // 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. // Thus, we are able to replace L by V.
} }
// Now prove that we have a LoadQ matched to a StoreQ, for some Q. // Now prove that we have a LoadQ matched to a StoreQ, for some Q.

View File

@ -891,13 +891,15 @@ int Node::disconnect_inputs(Node *n, Compile* C) {
//-----------------------------uncast--------------------------------------- //-----------------------------uncast---------------------------------------
// %%% Temporary, until we sort out CheckCastPP vs. CastPP. // %%% Temporary, until we sort out CheckCastPP vs. CastPP.
// Strip away casting. (It is depth-limited.) // 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: // Should be inline:
//return is_ConstraintCast() ? uncast_helper(this) : (Node*) this; //return is_ConstraintCast() ? uncast_helper(this) : (Node*) this;
if (is_ConstraintCast()) if (is_ConstraintCast()) {
return uncast_helper(this); return uncast_helper(this, keep_deps);
else } else {
return (Node*) this; return (Node*) this;
}
} }
// Find out of current node that matches opcode. // 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------------------------------------- //---------------------------uncast_helper-------------------------------------
Node* Node::uncast_helper(const Node* p) { Node* Node::uncast_helper(const Node* p, bool keep_deps) {
#ifdef ASSERT #ifdef ASSERT
uint depth_count = 0; uint depth_count = 0;
const Node* orig_p = p; const Node* orig_p = p;
@ -947,6 +949,9 @@ Node* Node::uncast_helper(const Node* p) {
if (p == NULL || p->req() != 2) { if (p == NULL || p->req() != 2) {
break; break;
} else if (p->is_ConstraintCast()) { } else if (p->is_ConstraintCast()) {
if (keep_deps && p->as_ConstraintCast()->carry_dependency()) {
break; // stop at casts with dependencies
}
p = p->in(1); p = p->in(1);
} else { } else {
break; break;

View File

@ -456,10 +456,10 @@ protected:
void setup_is_top(); void setup_is_top();
// Strip away casting. (It is depth-limited.) // 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. // Return whether two Nodes are equivalent, after stripping casting.
bool eqv_uncast(const Node* n) const { bool eqv_uncast(const Node* n, bool keep_deps = false) const {
return (this->uncast() == n->uncast()); return (this->uncast(keep_deps) == n->uncast(keep_deps));
} }
// Find out of current node that matches opcode. // 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); bool has_out_with(int opcode1, int opcode2, int opcode3, int opcode4);
private: 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 // Add an output edge to the end of the list
void add_out( Node *n ) { 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. // value, if it appears (by local graph inspection) to be computed by a simple conditional.
bool is_iteratively_computed(); bool is_iteratively_computed();
// Determine if a node is Counted loop induction variable. // Determine if a node is a counted loop induction variable.
// The method is defined in loopnode.cpp. // NOTE: The method is defined in "loopnode.cpp".
const Node* is_loop_iv() const; bool is_cloop_ind_var() const;
// Return a node with opcode "opc" and same inputs as "this" if one can // Return a node with opcode "opc" and same inputs as "this" if one can
// be found; Otherwise return NULL; // be found; Otherwise return NULL;

View File

@ -88,6 +88,10 @@ protected:
ciMethod* caller_method, ciMethod* caller_method,
JVMState* jvms, JVMState* jvms,
WarmCallInfo* wci_result); 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, void print_inlining(ciMethod* callee_method, int caller_bci,
ciMethod* caller_method, bool success) const; ciMethod* caller_method, bool success) const;

View File

@ -114,31 +114,37 @@ const Type* SubNode::Value(PhaseGVN* phase) const {
} }
//============================================================================= //=============================================================================
//------------------------------Helper function-------------------------------- //------------------------------Helper function--------------------------------
static bool ok_to_convert(Node* inc, Node* iv) {
// Do not collapse (x+c0)-y if "+" is a loop increment, because the static bool is_cloop_increment(Node* inc) {
// "-" is loop invariant and collapsing extends the live-range of "x" precond(inc->Opcode() == Op_AddI || inc->Opcode() == Op_AddL);
// to overlap with the "+", forcing another register to be used in
// the loop. if (!inc->in(1)->is_Phi()) {
// This test will be clearer with '&&' (apply DeMorgan's rule) return false;
// but I like the early cutouts that happen here. }
const PhiNode *phi; const PhiNode* phi = inc->in(1)->as_Phi();
if( ( !inc->in(1)->is_Phi() ||
!(phi=inc->in(1)->as_Phi()) || if (phi->is_copy() || !phi->region()->is_CountedLoop()) {
phi->is_copy() || return false;
!phi->region()->is_CountedLoop() || }
inc != phi->region()->as_CountedLoop()->incr() )
&& return 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;
}
} }
// 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------------------------------------------ //------------------------------Ideal------------------------------------------
Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){ Node *SubINode::Ideal(PhaseGVN *phase, bool can_reshape){
Node *in1 = in(1); Node *in1 = in(1);

View File

@ -145,7 +145,7 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) {
// Skip any loops already optimized by slp // Skip any loops already optimized by slp
if (cl->is_vectorized_loop()) return; if (cl->is_vectorized_loop()) return;
if (cl->do_unroll_only()) return; if (cl->is_unroll_only()) return;
if (cl->is_main_loop()) { if (cl->is_main_loop()) {
// Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit)))) // Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))

View File

@ -254,7 +254,7 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
return _tag_map; return _tag_map;
} }
JvmtiTagMap* acquire_tag_map() { JvmtiTagMap* tag_map_acquire() {
return OrderAccess::load_acquire(&_tag_map); return OrderAccess::load_acquire(&_tag_map);
} }

View File

@ -514,7 +514,7 @@ void JvmtiTagMap::destroy_entry(JvmtiTagHashmapEntry* entry) {
// returns the tag map for the given environments. If the tag map // returns the tag map for the given environments. If the tag map
// doesn't exist then it is created. // doesn't exist then it is created.
JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) { 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) { if (tag_map == NULL) {
MutexLocker mu(JvmtiThreadState_lock); MutexLocker mu(JvmtiThreadState_lock);
tag_map = ((JvmtiEnvBase*)env)->tag_map(); 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()) { if (JvmtiEnv::environments_might_exist()) {
JvmtiEnvIterator it; JvmtiEnvIterator it;
for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) { 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()) { if (tag_map != NULL && !tag_map->is_empty()) {
tag_map->do_weak_oops(is_alive, f); tag_map->do_weak_oops(is_alive, f);
} }

View File

@ -1080,6 +1080,24 @@ WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring
return result; return result;
WB_END 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)) WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
jmethodID jmid = reflected_method_to_jmid(thread, env, method); jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION(env); CHECK_JNI_EXCEPTION(env);
@ -2209,6 +2227,8 @@ static JNINativeMethod methods[] = {
CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation},
{CC"enqueueInitializerForCompilation0", {CC"enqueueInitializerForCompilation0",
CC"(Ljava/lang/Class;I)Z", (void*)&WB_EnqueueInitializerForCompilation}, CC"(Ljava/lang/Class;I)Z", (void*)&WB_EnqueueInitializerForCompilation},
{CC"markMethodProfiled",
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_MarkMethodProfiled},
{CC"clearMethodState0", {CC"clearMethodState0",
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
{CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation},

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -499,6 +499,7 @@ protected:
JavaThread* _requesting_thread; JavaThread* _requesting_thread;
BiasedLocking::Condition _status_code; BiasedLocking::Condition _status_code;
traceid _biased_locker_id; traceid _biased_locker_id;
uint64_t _safepoint_id;
public: public:
VM_RevokeBias(Handle* obj, JavaThread* requesting_thread) VM_RevokeBias(Handle* obj, JavaThread* requesting_thread)
@ -506,14 +507,16 @@ public:
, _objs(NULL) , _objs(NULL)
, _requesting_thread(requesting_thread) , _requesting_thread(requesting_thread)
, _status_code(BiasedLocking::NOT_BIASED) , _status_code(BiasedLocking::NOT_BIASED)
, _biased_locker_id(0) {} , _biased_locker_id(0)
, _safepoint_id(0) {}
VM_RevokeBias(GrowableArray<Handle>* objs, JavaThread* requesting_thread) VM_RevokeBias(GrowableArray<Handle>* objs, JavaThread* requesting_thread)
: _obj(NULL) : _obj(NULL)
, _objs(objs) , _objs(objs)
, _requesting_thread(requesting_thread) , _requesting_thread(requesting_thread)
, _status_code(BiasedLocking::NOT_BIASED) , _status_code(BiasedLocking::NOT_BIASED)
, _biased_locker_id(0) {} , _biased_locker_id(0)
, _safepoint_id(0) {}
virtual VMOp_Type type() const { return VMOp_RevokeBias; } virtual VMOp_Type type() const { return VMOp_RevokeBias; }
@ -545,6 +548,7 @@ public:
if (biased_locker != NULL) { if (biased_locker != NULL) {
_biased_locker_id = JFR_THREAD_ID(biased_locker); _biased_locker_id = JFR_THREAD_ID(biased_locker);
} }
_safepoint_id = SafepointSynchronize::safepoint_counter();
clean_up_cached_monitor_info(); clean_up_cached_monitor_info();
return; return;
} else { } else {
@ -560,6 +564,10 @@ public:
traceid biased_locker() const { traceid biased_locker() const {
return _biased_locker_id; return _biased_locker_id;
} }
uint64_t safepoint_id() const {
return _safepoint_id;
}
}; };
@ -581,16 +589,14 @@ public:
virtual void doit() { virtual void doit() {
_status_code = bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread); _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(); clean_up_cached_monitor_info();
} }
};
template <typename E> bool is_bulk_rebias() const {
static void set_safepoint_id(E* event) { return _bulk_rebias;
assert(event != NULL, "invariant"); }
// Subtract 1 to match the id of events committed inside the safepoint };
event->set_safepointId(SafepointSynchronize::safepoint_counter() - 1);
}
static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Klass* k) { static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Klass* k) {
assert(event != NULL, "invariant"); assert(event != NULL, "invariant");
@ -600,24 +606,25 @@ static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Kla
event->commit(); 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(event != NULL, "invariant");
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
assert(revoke != NULL, "invariant"); assert(op != NULL, "invariant");
assert(event->should_commit(), "invariant"); assert(event->should_commit(), "invariant");
event->set_lockClass(k); event->set_lockClass(k);
set_safepoint_id(event); event->set_safepointId(op->safepoint_id());
event->set_previousOwner(revoke->biased_locker()); event->set_previousOwner(op->biased_locker());
event->commit(); 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(event != NULL, "invariant");
assert(k != NULL, "invariant"); assert(k != NULL, "invariant");
assert(op != NULL, "invariant");
assert(event->should_commit(), "invariant"); assert(event->should_commit(), "invariant");
event->set_revokedClass(k); event->set_revokedClass(k);
event->set_disableBiasing(disabled_bias); event->set_disableBiasing(!op->is_bulk_rebias());
set_safepoint_id(event); event->set_safepointId(op->safepoint_id());
event->commit(); event->commit();
} }
@ -729,7 +736,7 @@ BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attem
attempt_rebias); attempt_rebias);
VMThread::execute(&bulk_revoke); VMThread::execute(&bulk_revoke);
if (event.should_commit()) { 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(); return bulk_revoke.status_code();
} }

View File

@ -674,8 +674,7 @@ JRT_LEAF(BasicType, Deoptimization::unpack_frames(JavaThread* thread, int exec_m
int top_frame_expression_stack_adjustment = 0; int top_frame_expression_stack_adjustment = 0;
methodHandle mh(thread, iframe->interpreter_frame_method()); methodHandle mh(thread, iframe->interpreter_frame_method());
OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask); OopMapCache::compute_one_oop_map(mh, iframe->interpreter_frame_bci(), &mask);
BytecodeStream str(mh); BytecodeStream str(mh, iframe->interpreter_frame_bci());
str.set_start(iframe->interpreter_frame_bci());
int max_bci = mh->code_size(); int max_bci = mh->code_size();
// Get to the next bytecode if possible // Get to the next bytecode if possible
assert(str.bci() < max_bci, "bci in interpreter frame out of bounds"); assert(str.bci() < max_bci, "bci in interpreter frame out of bounds");

View File

@ -526,11 +526,31 @@ void vm_exit(int code) {
vm_direct_exit(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 (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 // Fire off a VM_Exit operation to bring VM to a safepoint and exit
VM_Exit op(code); 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); VMThread::execute(&op);
// should never reach here; but in case something wrong with VM Thread. // should never reach here; but in case something wrong with VM Thread.
vm_direct_exit(code); vm_direct_exit(code);

View File

@ -1926,3 +1926,11 @@ void ObjectMonitor::Initialize() {
DEBUG_ONLY(InitDone = true;) 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()));
}

View File

@ -139,6 +139,7 @@ class ObjectMonitor {
friend class ObjectSynchronizer; friend class ObjectSynchronizer;
friend class ObjectWaiter; friend class ObjectWaiter;
friend class VMStructs; friend class VMStructs;
JVMCI_ONLY(friend class JVMCIVMStructs;)
volatile markOop _header; // displaced object header word - mark volatile markOop _header; // displaced object header word - mark
void* volatile _object; // backward object pointer - strong root void* volatile _object; // backward object pointer - strong root
@ -291,6 +292,9 @@ class ObjectMonitor {
void notify(TRAPS); void notify(TRAPS);
void notifyAll(TRAPS); void notifyAll(TRAPS);
void print() const { print_on(tty); }
void print_on(outputStream* st) const;
// Use the following at your own risk // Use the following at your own risk
intptr_t complete_exit(TRAPS); intptr_t complete_exit(TRAPS);
void reenter(intptr_t recursions, TRAPS); void reenter(intptr_t recursions, TRAPS);

View File

@ -1575,18 +1575,15 @@ bool jvmci_counters_include(JavaThread* thread) {
return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread(); return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread();
} }
void JavaThread::collect_counters(JVMCIEnv* jvmci_env, JVMCIPrimitiveArray array) { void JavaThread::collect_counters(jlong* array, int length) {
if (JVMCICounterSize > 0) { assert(length == JVMCICounterSize, "wrong value");
JavaThreadIteratorWithHandle jtiwh; for (int i = 0; i < length; i++) {
int len = jvmci_env->get_length(array); array[i] = _jvmci_old_thread_counters[i];
for (int i = 0; i < len; i++) { }
jvmci_env->put_long_at(array, i, _jvmci_old_thread_counters[i]); for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) {
} if (jvmci_counters_include(tp)) {
for (; JavaThread *tp = jtiwh.next(); ) { for (int i = 0; i < length; i++) {
if (jvmci_counters_include(tp)) { array[i] += tp->_jvmci_counters[i];
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]);
}
} }
} }
} }

View File

@ -1152,7 +1152,7 @@ class JavaThread: public Thread {
public: public:
static jlong* _jvmci_old_thread_counters; static jlong* _jvmci_old_thread_counters;
static void collect_counters(JVMCIEnv* JVMCIENV, JVMCIPrimitiveArray array); static void collect_counters(jlong* array, int length);
private: private:
#endif // INCLUDE_JVMCI #endif // INCLUDE_JVMCI

View File

@ -353,6 +353,16 @@ CompileTask* TieredThresholdPolicy::select_task(CompileQueue* compile_queue) {
TieredStopAtLevel > CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile &&
max_method != NULL && is_method_profiled(max_method)) { max_method != NULL && is_method_profiled(max_method)) {
max_task->set_comp_level(CompLevel_limited_profile); 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) { if (PrintTieredEvents) {
print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level());
} }

View File

@ -30,6 +30,7 @@
#include "gc/shared/isGCActiveMark.hpp" #include "gc/shared/isGCActiveMark.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "logging/logStream.hpp" #include "logging/logStream.hpp"
#include "logging/logConfiguration.hpp"
#include "memory/heapInspection.hpp" #include "memory/heapInspection.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/symbol.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 (thr->is_Compiler_thread()) {
#if INCLUDE_JVMCI #if INCLUDE_JVMCI
CompilerThread* ct = (CompilerThread*) thr; 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++; num_active_compiler_thread++;
} else { } else {
// When using a compiler in a JVMCI shared library, it's possible // A JVMCI compiler thread never accesses VM data structures
// for one compiler thread to grab a lock in the shared library, // while in _thread_in_native state so there's no need to wait
// enter HotSpot and go to sleep on the shutdown safepoint. Another // for it and potentially add a 300 millisecond delay to VM
// JVMCI shared library compiler thread can then attempt to grab the // shutdown.
// lock and thus never make progress. num_active--;
} }
#else #else
num_active_compiler_thread++; num_active_compiler_thread++;
@ -469,6 +470,16 @@ int VM_Exit::wait_for_threads_in_native_to_block() {
} }
void VM_Exit::doit() { 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(); CompileBroker::set_should_block();
// Wait for a short period for threads in native to block. Any thread // Wait for a short period for threads in native to block. Any thread
@ -480,10 +491,17 @@ void VM_Exit::doit() {
set_vm_exited(); 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 // cleanup globals resources before exiting. exit_globals() currently
// cleans up outputStream resources and PerfMemory resources. // cleans up outputStream resources and PerfMemory resources.
exit_globals(); exit_globals();
LogConfiguration::finalize();
// Check for exit hook // Check for exit hook
exit_hook_t exit_hook = Arguments::exit_hook(); exit_hook_t exit_hook = Arguments::exit_hook();
if (exit_hook != NULL) { if (exit_hook != NULL) {

View File

@ -63,6 +63,9 @@ do { \
// For backward compatibility. // For backward compatibility.
#define assert(p, ...) vmassert(p, __VA_ARGS__) #define assert(p, ...) vmassert(p, __VA_ARGS__)
#define precond(p) assert(p, "precond")
#define postcond(p) assert(p, "postcond")
#ifndef ASSERT #ifndef ASSERT
#define vmassert_status(p, status, msg) #define vmassert_status(p, status, msg)
#else #else

View File

@ -75,7 +75,7 @@ import static java.util.function.Predicate.not;
* System.out.println("abc"); * System.out.println("abc");
* String cde = "cde"; * String cde = "cde";
* System.out.println("abc" + cde); * System.out.println("abc" + cde);
* String c = "abc".substring(2,3); * String c = "abc".substring(2, 3);
* String d = cde.substring(1, 2); * String d = cde.substring(1, 2);
* </pre></blockquote> * </pre></blockquote>
* <p> * <p>
@ -2160,27 +2160,48 @@ public final class String
* @since 1.5 * @since 1.5
*/ */
public String replace(CharSequence target, CharSequence replacement) { public String replace(CharSequence target, CharSequence replacement) {
String tgtStr = target.toString(); String trgtStr = target.toString();
String replStr = replacement.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 thisLen = length();
int trgtLen = trgtStr.length();
int replLen = replStr.length();
int newLenHint = thisLen - tgtLen + replStr.length(); if (trgtLen > 0) {
if (newLenHint < 0) { if (trgtLen == 1 && replLen == 1) {
throw new OutOfMemoryError(); 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();
} }
/** /**

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 { 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) { public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) { if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index); throw new StringIndexOutOfBoundsException(index);
@ -304,7 +312,7 @@ final class StringLatin1 {
} }
if (i < len) { if (i < len) {
if (canEncode(newChar)) { if (canEncode(newChar)) {
byte buf[] = new byte[len]; byte[] buf = StringConcatHelper.newArray(len);
for (int j = 0; j < i; j++) { // TBD arraycopy? for (int j = 0; j < i; j++) { // TBD arraycopy?
buf[j] = value[j]; buf[j] = value[j];
} }
@ -330,6 +338,64 @@ final class StringLatin1 {
return null; // for string to return this; 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 // case insensitive
public static boolean regionMatchesCI(byte[] value, int toffset, public static boolean regionMatchesCI(byte[] value, int toffset,
byte[] other, int ooffset, int len) { byte[] other, int ooffset, int len) {

View File

@ -574,7 +574,7 @@ final class StringUTF16 {
} }
} }
if (i < len) { if (i < len) {
byte buf[] = new byte[value.length]; byte[] buf = new byte[value.length];
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++) {
putChar(buf, j, getChar(value, j)); // TBD:arraycopy? putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
} }
@ -582,21 +582,145 @@ final class StringUTF16 {
char c = getChar(value, i); char c = getChar(value, i);
putChar(buf, i, c == oldChar ? newChar : c); putChar(buf, i, c == oldChar ? newChar : c);
i++; i++;
} }
// Check if we should try to compress to latin1 // Check if we should try to compress to latin1
if (String.COMPACT_STRINGS && if (String.COMPACT_STRINGS &&
!StringLatin1.canEncode(oldChar) && !StringLatin1.canEncode(oldChar) &&
StringLatin1.canEncode(newChar)) { StringLatin1.canEncode(newChar)) {
byte[] val = compress(buf, 0, len); byte[] val = compress(buf, 0, len);
if (val != null) { if (val != null) {
return new String(val, LATIN1); return new String(val, LATIN1);
} }
} }
return new String(buf, UTF16); return new String(buf, UTF16);
} }
return null; 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, public static boolean regionMatchesCI(byte[] value, int toffset,
byte[] other, int ooffset, int len) { byte[] other, int ooffset, int len) {
int last = toffset + len; int last = toffset + len;
@ -1430,6 +1554,15 @@ final class StringUTF16 {
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; 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 // Used by trusted callers. Assumes all necessary bounds checks have
// been done by the caller. // been done by the caller.

View File

@ -213,7 +213,7 @@ public interface ClassDesc
* @param moreNestedNames the unqualified name(s) of the remaining levels of * @param moreNestedNames the unqualified name(s) of the remaining levels of
* nested class * nested class
* @return a {@linkplain ClassDesc} describing the 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 * @throws IllegalStateException if this {@linkplain ClassDesc} does not
* describe a class or interface type * describe a class or interface type
* @throws IllegalArgumentException if the nested class name is invalid * @throws IllegalArgumentException if the nested class name is invalid
@ -221,6 +221,11 @@ public interface ClassDesc
default ClassDesc nested(String firstNestedName, String... moreNestedNames) { default ClassDesc nested(String firstNestedName, String... moreNestedNames) {
if (!isClassOrInterface()) if (!isClassOrInterface())
throw new IllegalStateException("Outer class is not a class or interface type"); 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 return moreNestedNames.length == 0
? nested(firstNestedName) ? nested(firstNestedName)
: nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", ""))); : nested(firstNestedName + Stream.of(moreNestedNames).collect(joining("$", "$", "")));

View File

@ -32,6 +32,7 @@ import java.lang.reflect.InvocationTargetException;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.Collections; import java.util.Collections;
@ -81,6 +82,7 @@ class ServerSocket implements java.io.Closeable {
* @since 12 * @since 12
*/ */
protected ServerSocket(SocketImpl impl) { protected ServerSocket(SocketImpl impl) {
Objects.requireNonNull(impl);
this.impl = impl; this.impl = impl;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; URLStreamHandlerFactory fac;
boolean checkedWithFactory = false; 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 // Use the factory (if any). Volatile read makes
// URLStreamHandlerFactory appear fully initialized to current thread. // URLStreamHandlerFactory appear fully initialized to current thread.
fac = factory; fac = factory;
@ -1440,7 +1441,8 @@ public final class URL implements java.io.Serializable {
// Check with factory if another thread set a // Check with factory if another thread set a
// factory since our last check // factory since our last check
if (!checkedWithFactory && (fac = factory) != null) { if (overrideableProtocol && !checkedWithFactory &&
(fac = factory) != null) {
handler2 = fac.createURLStreamHandler(protocol); handler2 = fac.createURLStreamHandler(protocol);
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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"} * Suppose there is a provider identified by the scheme {@code "memory"}
* installed: * installed:
* <pre> * <pre>
* Map&lt;String,String&gt; env = new HashMap&lt;&gt;(); * FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"),
* env.put("capacity", "16G"); * Map.of("capacity", "16G", "blockSize", "4k"));
* env.put("blockSize", "4k");
* FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
* </pre> * </pre>
* *
* @param uri * @param uri
@ -365,14 +363,13 @@ public final class FileSystems {
* systems where the contents of one or more files is treated as a file * systems where the contents of one or more files is treated as a file
* system. * system.
* *
* <p> This method iterates over the {@link FileSystemProvider#installedProviders() * <p> This method first attempts to locate an installed provider in exactly
* installed} providers. It invokes, in turn, each provider's {@link * the same manner as the {@link #newFileSystem(Path, Map, ClassLoader)
* FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method * newFileSystem(Path, Map, ClassLoader)} method with an empty map. If none
* with an empty map. If a provider returns a file system then the iteration * of the installed providers return a {@code FileSystem} then an attempt is
* terminates and the file system is returned. If none of the installed * made to locate the provider using the given class loader. If a provider
* providers return a {@code FileSystem} then an attempt is made to locate * returns a file system then the lookup terminates and the file system is
* the provider using the given class loader. If a provider returns a file * returned.
* system then the lookup terminates and the file system is returned.
* *
* @param path * @param path
* the path to the file * the path to the file
@ -395,11 +392,132 @@ public final class FileSystems {
public static FileSystem newFileSystem(Path path, public static FileSystem newFileSystem(Path path,
ClassLoader loader) ClassLoader loader)
throws IOException 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) if (path == null)
throw new NullPointerException(); throw new NullPointerException();
Map<String,?> env = Collections.emptyMap();
// check installed providers // check installed providers
for (FileSystemProvider provider: FileSystemProvider.installedProviders()) { for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
try { try {

View File

@ -62,10 +62,11 @@ public final class Objects {
* Returns {@code true} if the arguments are equal to each other * Returns {@code true} if the arguments are equal to each other
* and {@code false} otherwise. * and {@code false} otherwise.
* Consequently, if both arguments are {@code null}, {@code true} * Consequently, if both arguments are {@code null}, {@code true}
* is returned and if exactly one argument is {@code null}, {@code * is returned. Otherwise, if the first argument is not {@code
* false} is returned. Otherwise, equality is determined by using * null}, equality is determined by calling the {@link
* the {@link Object#equals equals} method of the first * Object#equals equals} method of the first argument with the
* argument. * second argument of this method. Otherwise, {@code false} is
* returned.
* *
* @param a an object * @param a an object
* @param b an object to be compared with {@code a} for equality * @param b an object to be compared with {@code a} for equality

View File

@ -1678,7 +1678,13 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
return; return;
int j = i; int j = i;
i += 2; 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); System.arraycopy(temp, 0, newtemp, 0, j);
boolean inQuote = true; boolean inQuote = true;

View File

@ -826,6 +826,10 @@ public final class SSLSocketImpl
// reading lock // reading lock
private final ReentrantLock readLock = new ReentrantLock(); private final ReentrantLock readLock = new ReentrantLock();
// closing status
private volatile boolean isClosing;
private volatile boolean hasDepleted;
AppInputStream() { AppInputStream() {
this.appDataIsAvailable = false; this.appDataIsAvailable = false;
this.buffer = ByteBuffer.allocate(4096); this.buffer = ByteBuffer.allocate(4096);
@ -871,8 +875,7 @@ public final class SSLSocketImpl
* and returning "-1" on non-fault EOF status. * and returning "-1" on non-fault EOF status.
*/ */
@Override @Override
public int read(byte[] b, int off, int len) public int read(byte[] b, int off, int len) throws IOException {
throws IOException {
if (b == null) { if (b == null) {
throw new NullPointerException("the target buffer is null"); throw new NullPointerException("the target buffer is null");
} else if (off < 0 || len < 0 || len > b.length - off) { } 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"); 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. // Read the available bytes at first.
// //
// Note that the receiving and processing of post-handshake message // Note that the receiving and processing of post-handshake message
// are also synchronized with the read lock. // are also synchronized with the read lock.
readLock.lock(); readLock.lock();
try { 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(); int remains = available();
if (remains > 0) { if (remains > 0) {
int howmany = Math.min(remains, len); int howmany = Math.min(remains, len);
@ -938,7 +969,17 @@ public final class SSLSocketImpl
return -1; return -1;
} }
} finally { } 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. * socket gracefully, without impact the performance too much.
*/ */
private void deplete() { private void deplete() {
if (conContext.isInboundClosed()) { if (conContext.isInboundClosed() || isClosing) {
return; return;
} }
readLock.lock(); isClosing = true;
try { if (readLock.tryLock()) {
// double check
if (conContext.isInboundClosed()) {
return;
}
if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) {
return;
}
SSLSocketInputRecord socketInputRecord =
(SSLSocketInputRecord)conContext.inputRecord;
try { try {
socketInputRecord.deplete( readLockedDeplete();
conContext.isNegotiated && (getSoTimeout() > 0)); } finally {
} catch (IOException ioe) { readLock.unlock();
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { }
SSLLogger.warning( }
"input stream close depletion failed", ioe); }
}
/**
* 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 { } finally {
readLock.unlock(); hasDepleted = true;
} }
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -73,15 +73,23 @@ class UnixFileAttributeViews {
boolean haveFd = false; boolean haveFd = false;
boolean useFutimes = false; boolean useFutimes = false;
boolean useLutimes = false;
int fd = -1; int fd = -1;
try { try {
fd = file.openForAttributeAccess(followLinks); if (!followLinks) {
if (fd != -1) { useLutimes = lutimesSupported() &&
haveFd = true; UnixFileAttributes.get(file, false).isSymbolicLink();
useFutimes = futimesSupported(); }
if (!useLutimes) {
fd = file.openForAttributeAccess(followLinks);
if (fd != -1) {
haveFd = true;
useFutimes = futimesSupported();
}
} }
} catch (UnixException x) { } catch (UnixException x) {
if (x.errno() != UnixConstants.ENXIO) { if (!(x.errno() == UnixConstants.ENXIO ||
(x.errno() == UnixConstants.ELOOP && useLutimes))) {
x.rethrowAsIOException(file); x.rethrowAsIOException(file);
} }
} }
@ -112,6 +120,8 @@ class UnixFileAttributeViews {
try { try {
if (useFutimes) { if (useFutimes) {
futimes(fd, accessValue, modValue); futimes(fd, accessValue, modValue);
} else if (useLutimes) {
lutimes(file, accessValue, modValue);
} else { } else {
utimes(file, accessValue, modValue); utimes(file, accessValue, modValue);
} }
@ -131,6 +141,8 @@ class UnixFileAttributeViews {
try { try {
if (useFutimes) { if (useFutimes) {
futimes(fd, accessValue, modValue); futimes(fd, accessValue, modValue);
} else if (useLutimes) {
lutimes(file, accessValue, modValue);
} else { } else {
utimes(file, accessValue, modValue); utimes(file, accessValue, modValue);
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; 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) static void utimes(UnixPath path, long times0, long times1)
throws UnixException throws UnixException
@ -417,10 +417,26 @@ class UnixNativeDispatcher {
throws UnixException; 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; 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) * DIR *opendir(const char* dirname)
*/ */
@ -578,9 +594,10 @@ class UnixNativeDispatcher {
/** /**
* Capabilities * 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_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; private static final int capabilities;
/** /**
@ -597,6 +614,13 @@ class UnixNativeDispatcher {
return (capabilities & SUPPORTS_FUTIMES) != 0; return (capabilities & SUPPORTS_FUTIMES) != 0;
} }
/**
* Supports lutimes
*/
static boolean lutimesSupported() {
return (capabilities & SUPPORTS_LUTIMES) != 0;
}
/** /**
* Supports file birth (creation) time attribute * Supports file birth (creation) time attribute
*/ */

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 unlinkat_func(int, const char*, int);
typedef int renameat_func(int, const char*, int, const char*); typedef int renameat_func(int, const char*, int, const char*);
typedef int futimesat_func(int, const char *, const struct timeval *); typedef int futimesat_func(int, const char *, const struct timeval *);
typedef int lutimes_func(const char *, const struct timeval *);
typedef DIR* fdopendir_func(int); typedef DIR* fdopendir_func(int);
static openat64_func* my_openat64_func = NULL; 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 unlinkat_func* my_unlinkat_func = NULL;
static renameat_func* my_renameat_func = NULL; static renameat_func* my_renameat_func = NULL;
static futimesat_func* my_futimesat_func = NULL; static futimesat_func* my_futimesat_func = NULL;
static lutimes_func* my_lutimes_func = NULL;
static fdopendir_func* my_fdopendir_func = NULL; static fdopendir_func* my_fdopendir_func = NULL;
/** /**
@ -269,7 +271,10 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
#endif #endif
my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat"); my_unlinkat_func = (unlinkat_func*) dlsym(RTLD_DEFAULT, "unlinkat");
my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat"); my_renameat_func = (renameat_func*) dlsym(RTLD_DEFAULT, "renameat");
#ifndef _ALLBSD_SOURCE
my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat"); my_futimesat_func = (futimesat_func*) dlsym(RTLD_DEFAULT, "futimesat");
my_lutimes_func = (lutimes_func*) dlsym(RTLD_DEFAULT, "lutimes");
#endif
#if defined(_AIX) #if defined(_AIX)
my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64"); my_fdopendir_func = (fdopendir_func*) dlsym(RTLD_DEFAULT, "fdopendir64");
#else #else
@ -282,13 +287,16 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this)
my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper; my_fstatat64_func = (fstatat64_func*)&fstatat64_wrapper;
#endif #endif
/* supports futimes or futimesat */ /* supports futimes or futimesat and/or lutimes */
#ifdef _ALLBSD_SOURCE #ifdef _ALLBSD_SOURCE
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES; capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;
#else #else
if (my_futimesat_func != NULL) if (my_futimesat_func != NULL)
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES; capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_FUTIMES;
if (my_lutimes_func != NULL)
capabilities |= sun_nio_fs_UnixNativeDispatcher_SUPPORTS_LUTIMES;
#endif #endif
/* supports openat, etc. */ /* supports openat, etc. */
@ -675,7 +683,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint file
RESTARTABLE(futimes(filedes, &times[0]), err); RESTARTABLE(futimes(filedes, &times[0]), err);
#else #else
if (my_futimesat_func == NULL) { if (my_futimesat_func == NULL) {
JNU_ThrowInternalError(env, "my_ftimesat_func is NULL"); JNU_ThrowInternalError(env, "my_futimesat_func is NULL");
return; return;
} }
RESTARTABLE((*my_futimesat_func)(filedes, NULL, &times[0]), err); RESTARTABLE((*my_futimesat_func)(filedes, NULL, &times[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, &times[0]), err);
#else
if (my_lutimes_func == NULL) {
JNU_ThrowInternalError(env, "my_lutimes_func is NULL");
return;
}
RESTARTABLE((*my_lutimes_func)(path, &times[0]), err);
#endif
if (err == -1) {
throwUnixException(env, errno);
}
}
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this, Java_sun_nio_fs_UnixNativeDispatcher_opendir0(JNIEnv* env, jclass this,
jlong pathAddress) jlong pathAddress)

View File

@ -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 com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text; import org.w3c.dom.Text;
public abstract class IntegrityHmac extends SignatureAlgorithmSpi { public abstract class IntegrityHmac extends SignatureAlgorithmSpi {
@ -325,12 +326,13 @@ public abstract class IntegrityHmac extends SignatureAlgorithmSpi {
throw new IllegalArgumentException("element null"); throw new IllegalArgumentException("element null");
} }
Text hmaclength = Node n = XMLUtils.selectDsNode(element.getFirstChild(), Constants._TAG_HMACOUTPUTLENGTH, 0);
XMLUtils.selectDsNodeText(element.getFirstChild(), Constants._TAG_HMACOUTPUTLENGTH, 0); if (n != null) {
String hmacLength = XMLUtils.getFullTextChildrenFromNode(n);
if (hmaclength != null) { if (hmacLength != null && !"".equals(hmacLength)) {
this.HMACOutputLength = Integer.parseInt(hmaclength.getData()); this.HMACOutputLength = Integer.parseInt(hmacLength);
this.HMACOutputLengthSet = true; this.HMACOutputLengthSet = true;
}
} }
} }

View File

@ -33,7 +33,6 @@ import java.security.Signature;
import java.security.SignatureException; import java.security.SignatureException;
import java.security.interfaces.DSAKey; import java.security.interfaces.DSAKey;
import java.security.spec.AlgorithmParameterSpec; 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.JCEMapper;
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi; 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.signature.XMLSignatureException;
import com.sun.org.apache.xml.internal.security.utils.Constants; 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.JavaUtils;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
public class SignatureDSA extends SignatureAlgorithmSpi { public class SignatureDSA extends SignatureAlgorithmSpi {
@ -109,7 +109,7 @@ public class SignatureDSA extends SignatureAlgorithmSpi {
throws XMLSignatureException { throws XMLSignatureException {
try { try {
if (LOG.isDebugEnabled()) { 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, byte[] jcebytes = JavaUtils.convertDsaXMLDSIGtoASN1(signature,

View File

@ -33,12 +33,12 @@ import java.security.SecureRandom;
import java.security.Signature; import java.security.Signature;
import java.security.SignatureException; import java.security.SignatureException;
import java.security.spec.AlgorithmParameterSpec; 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.JCEMapper;
import com.sun.org.apache.xml.internal.security.algorithms.SignatureAlgorithmSpi; 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.XMLSignature;
import com.sun.org.apache.xml.internal.security.signature.XMLSignatureException; 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); byte[] jcebytes = SignatureECDSA.convertXMLDSIGtoASN1(signature);
if (LOG.isDebugEnabled()) { 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); return this.signatureAlgorithm.verify(jcebytes);

View File

@ -331,7 +331,7 @@ public abstract class Canonicalizer20010315 extends CanonicalizerBase {
ns.addMapping(NName, NValue, attribute); ns.addMapping(NName, NValue, attribute);
} }
} else if (XML_LANG_URI.equals(attribute.getNamespaceURI()) } else if (XML_LANG_URI.equals(attribute.getNamespaceURI())
&& (!c14n11 || c14n11 && !"id".equals(NName))) { && (!c14n11 || !"id".equals(NName))) {
xmlattrStack.addXmlnsAttr(attribute); xmlattrStack.addXmlnsAttr(attribute);
} }
} }

View File

@ -342,7 +342,7 @@ public abstract class Canonicalizer20010315Excl extends CanonicalizerBase {
protected void circumventBugIfNeeded(XMLSignatureInput input) protected void circumventBugIfNeeded(XMLSignatureInput input)
throws CanonicalizationException, ParserConfigurationException, throws CanonicalizationException, ParserConfigurationException,
IOException, SAXException { IOException, SAXException {
if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty() || inclusiveNSSet.isEmpty()) { if (!input.isNeedsToBeExpanded() || inclusiveNSSet.isEmpty()) {
return; return;
} }
Document doc = null; Document doc = null;

View File

@ -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.transforms.Transforms;
import com.sun.org.apache.xml.internal.security.utils.Constants; 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.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.SignatureElementProxy;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils; import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Attr; import org.w3c.dom.Attr;

View File

@ -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.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.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.keys.content.keyvalues.RSAKeyValue;
import com.sun.org.apache.xml.internal.security.utils.Constants; 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.SignatureElementProxy;
@ -107,9 +108,14 @@ public class KeyValue extends SignatureElementProxy implements KeyInfoContent {
appendSelf(rsa); appendSelf(rsa);
addReturnToSelf(); addReturnToSelf();
} else if (pk instanceof java.security.interfaces.ECPublicKey) {
ECKeyValue ec = new ECKeyValue(getDocument(), pk);
appendSelf(ec);
addReturnToSelf();
} else { } else {
String error = "The given PublicKey type " + pk + " is not supported. Only DSAPublicKey and " 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); throw new IllegalArgumentException(error);
} }
} }

View File

@ -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);
}
}

View File

@ -24,18 +24,18 @@ package com.sun.org.apache.xml.internal.security.keys.content.x509;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Arrays; 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.exceptions.XMLSecurityException;
import com.sun.org.apache.xml.internal.security.utils.Constants; 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.SignatureElementProxy;
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
/** /**
* Handles SubjectKeyIdentifier (SKI) for X.509v3. * 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> * Interface X509Extension</A>
*/ */
public class XMLX509SKI extends SignatureElementProxy implements XMLX509DataContent { 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); System.arraycopy(extensionValue, 4, skidValue, 0, skidValue.length);
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Base64 of SKI is " + Base64.getMimeEncoder().encodeToString(skidValue)); LOG.debug("Base64 of SKI is " + XMLUtils.encodeToString(skidValue));
} }
return skidValue; return skidValue;

View File

@ -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.DEREncodedKeyValueResolver;
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DSAKeyValueResolver; 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.KeyInfoReferenceResolver;
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RSAKeyValueResolver; import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RSAKeyValueResolver;
import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RetrievalMethodResolver; 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 DEREncodedKeyValueResolver()));
keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver())); keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver()));
keyResolverList.add(new KeyResolver(new X509DigestResolver())); keyResolverList.add(new KeyResolver(new X509DigestResolver()));
keyResolverList.add(new KeyResolver(new ECKeyValueResolver()));
resolverVector.addAll(keyResolverList); resolverVector.addAll(keyResolverList);
} }

View File

@ -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;
}
}

View File

@ -44,11 +44,12 @@ public class RSAKeyValueResolver extends KeyResolverSpi {
public PublicKey engineLookupAndResolvePublicKey( public PublicKey engineLookupAndResolvePublicKey(
Element element, String baseURI, StorageResolver storage Element element, String baseURI, StorageResolver storage
) { ) {
LOG.debug("Can I resolve {}", element.getTagName());
if (element == null) { if (element == null) {
return null; return null;
} }
LOG.debug("Can I resolve {}", element.getTagName());
boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYVALUE); boolean isKeyValue = XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYVALUE);
Element rsaKeyElement = null; Element rsaKeyElement = null;
if (isKeyValue) { if (isKeyValue) {

View File

@ -35,12 +35,12 @@ import java.security.cert.CertificateFactory;
import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Base64;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; 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.StorageResolverException;
import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolverSpi; 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 * 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();
System.out.println("Base64(SKI())= \"" System.out.println("Base64(SKI())= \""
+ Base64.getMimeEncoder().encodeToString(ski) + "\""); + XMLUtils.encodeToString(ski) + "\"");
System.out.println("cert.getSerialNumber()= \"" System.out.println("cert.getSerialNumber()= \""
+ cert.getSerialNumber().toString() + "\""); + cert.getSerialNumber().toString() + "\"");
System.out.println("cert.getSubjectX500Principal().getName()= \"" System.out.println("cert.getSubjectX500Principal().getName()= \""

Some files were not shown because too many files have changed in this diff Show More