Merge
This commit is contained in:
commit
1b03f22dff
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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) \
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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(); }
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
//
|
//
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
|
@ -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) ||
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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) \
|
||||||
|
@ -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);
|
||||||
|
@ -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;") \
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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") \
|
||||||
|
@ -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) \
|
||||||
\
|
\
|
||||||
|
@ -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(), "");
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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
@ -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-----------------------------
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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))))
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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},
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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);
|
||||||
|
@ -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()));
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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("$", "$", "")));
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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<String,String> env = new HashMap<>();
|
* 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 {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
@ -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, ×[0]), err);
|
RESTARTABLE(futimes(filedes, ×[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, ×[0]), err);
|
RESTARTABLE((*my_futimesat_func)(filedes, NULL, ×[0]), err);
|
||||||
@ -685,6 +693,34 @@ Java_sun_nio_fs_UnixNativeDispatcher_futimes(JNIEnv* env, jclass this, jint file
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_sun_nio_fs_UnixNativeDispatcher_lutimes0(JNIEnv* env, jclass this,
|
||||||
|
jlong pathAddress, jlong accessTime, jlong modificationTime)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct timeval times[2];
|
||||||
|
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||||
|
|
||||||
|
times[0].tv_sec = accessTime / 1000000;
|
||||||
|
times[0].tv_usec = accessTime % 1000000;
|
||||||
|
|
||||||
|
times[1].tv_sec = modificationTime / 1000000;
|
||||||
|
times[1].tv_usec = modificationTime % 1000000;
|
||||||
|
|
||||||
|
#ifdef _ALLBSD_SOURCE
|
||||||
|
RESTARTABLE(lutimes(path, ×[0]), err);
|
||||||
|
#else
|
||||||
|
if (my_lutimes_func == NULL) {
|
||||||
|
JNU_ThrowInternalError(env, "my_lutimes_func is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
RESTARTABLE((*my_lutimes_func)(path, ×[0]), err);
|
||||||
|
#endif
|
||||||
|
if (err == -1) {
|
||||||
|
throwUnixException(env, errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
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)
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,366 @@
|
|||||||
|
/*
|
||||||
|
* reserved comment block
|
||||||
|
* DO NOT REMOVE OR ALTER!
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package com.sun.org.apache.xml.internal.security.keys.content.keyvalues;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
import java.security.spec.ECField;
|
||||||
|
import java.security.spec.ECFieldFp;
|
||||||
|
import java.security.spec.ECParameterSpec;
|
||||||
|
import java.security.spec.ECPoint;
|
||||||
|
import java.security.spec.ECPublicKeySpec;
|
||||||
|
import java.security.spec.EllipticCurve;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.xml.crypto.MarshalException;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
import org.w3c.dom.Text;
|
||||||
|
|
||||||
|
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
|
||||||
|
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||||
|
import com.sun.org.apache.xml.internal.security.utils.I18n;
|
||||||
|
import com.sun.org.apache.xml.internal.security.utils.Signature11ElementProxy;
|
||||||
|
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||||
|
|
||||||
|
public class ECKeyValue extends Signature11ElementProxy implements KeyValueContent {
|
||||||
|
|
||||||
|
/* Supported curve, secp256r1 */
|
||||||
|
private static final Curve SECP256R1 = initializeCurve(
|
||||||
|
"secp256r1 [NIST P-256, X9.62 prime256v1]",
|
||||||
|
"1.2.840.10045.3.1.7",
|
||||||
|
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
|
||||||
|
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
|
||||||
|
"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
|
||||||
|
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
|
||||||
|
"4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
|
||||||
|
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Supported curve secp384r1 */
|
||||||
|
private static final Curve SECP384R1 = initializeCurve(
|
||||||
|
"secp384r1 [NIST P-384]",
|
||||||
|
"1.3.132.0.34",
|
||||||
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
|
||||||
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
|
||||||
|
"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
|
||||||
|
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
|
||||||
|
"3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
|
||||||
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Supported curve secp521r1 */
|
||||||
|
private static final Curve SECP521R1 = initializeCurve(
|
||||||
|
"secp521r1 [NIST P-521]",
|
||||||
|
"1.3.132.0.35",
|
||||||
|
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||||
|
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
|
||||||
|
"0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
|
||||||
|
"00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
|
||||||
|
"011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
|
||||||
|
"01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
private static Curve initializeCurve(String name, String oid,
|
||||||
|
String sfield, String a, String b,
|
||||||
|
String x, String y, String n, int h) {
|
||||||
|
BigInteger p = bigInt(sfield);
|
||||||
|
ECField field = new ECFieldFp(p);
|
||||||
|
EllipticCurve curve = new EllipticCurve(field, bigInt(a),
|
||||||
|
bigInt(b));
|
||||||
|
ECPoint g = new ECPoint(bigInt(x), bigInt(y));
|
||||||
|
return new Curve(name, oid, curve, g, bigInt(n), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor DSAKeyValue
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
* @param baseURI
|
||||||
|
* @throws XMLSecurityException
|
||||||
|
*/
|
||||||
|
public ECKeyValue(Element element, String baseURI) throws XMLSecurityException {
|
||||||
|
super(element, baseURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor DSAKeyValue
|
||||||
|
*
|
||||||
|
* @param doc
|
||||||
|
* @param key
|
||||||
|
* @throws IllegalArgumentException
|
||||||
|
*/
|
||||||
|
public ECKeyValue(Document doc, Key key) throws IllegalArgumentException {
|
||||||
|
super(doc);
|
||||||
|
|
||||||
|
addReturnToSelf();
|
||||||
|
|
||||||
|
if (key instanceof ECPublicKey) {
|
||||||
|
ECParameterSpec ecParams = ((ECPublicKey)key).getParams();
|
||||||
|
|
||||||
|
// NamedCurve
|
||||||
|
String oid = getCurveOid(ecParams);
|
||||||
|
if (oid == null) {
|
||||||
|
throw new IllegalArgumentException("Invalid ECParameterSpec");
|
||||||
|
}
|
||||||
|
|
||||||
|
Element namedCurveElement = XMLUtils.createElementInSignature11Space(getDocument(), "NamedCurve");
|
||||||
|
namedCurveElement.setAttributeNS(null, "URI", "urn:oid:" + oid);
|
||||||
|
appendSelf(namedCurveElement);
|
||||||
|
addReturnToSelf();
|
||||||
|
|
||||||
|
// PublicKey
|
||||||
|
ECPoint ecPoint = ((ECPublicKey)key).getW();
|
||||||
|
byte[] secPublicKey = encodePoint(ecPoint, ecParams.getCurve());
|
||||||
|
String encoded = XMLUtils.encodeToString(secPublicKey);
|
||||||
|
Element publicKeyElement = XMLUtils.createElementInSignature11Space(getDocument(), "PublicKey");
|
||||||
|
Text text = getDocument().createTextNode(encoded);
|
||||||
|
|
||||||
|
publicKeyElement.appendChild(text);
|
||||||
|
|
||||||
|
appendSelf(publicKeyElement);
|
||||||
|
addReturnToSelf();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Object[] exArgs = { Constants._TAG_ECKEYVALUE, key.getClass().getName() };
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(I18n.translate("KeyValue.IllegalArgument", exArgs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public PublicKey getPublicKey() throws XMLSecurityException {
|
||||||
|
try {
|
||||||
|
ECParameterSpec ecParams = null;
|
||||||
|
Element curElem = getFirstChildElement(getElement());
|
||||||
|
if (curElem == null) {
|
||||||
|
throw new MarshalException("KeyValue must contain at least one type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("ECParameters".equals(curElem.getLocalName())
|
||||||
|
&& Constants.SignatureSpec11NS.equals(curElem.getNamespaceURI())) {
|
||||||
|
throw new UnsupportedOperationException
|
||||||
|
("ECParameters not supported");
|
||||||
|
} else if ("NamedCurve".equals(curElem.getLocalName())
|
||||||
|
&& Constants.SignatureSpec11NS.equals(curElem.getNamespaceURI())) {
|
||||||
|
String uri = null;
|
||||||
|
if (curElem.hasAttributeNS(null, "URI")) {
|
||||||
|
uri = curElem.getAttributeNS(null, "URI");
|
||||||
|
}
|
||||||
|
// strip off "urn:oid"
|
||||||
|
if (uri.startsWith("urn:oid:")) {
|
||||||
|
String oid = uri.substring("urn:oid:".length());
|
||||||
|
ecParams = getECParameterSpec(oid);
|
||||||
|
if (ecParams == null) {
|
||||||
|
throw new MarshalException("Invalid curve OID");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new MarshalException("Invalid NamedCurve URI");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new MarshalException("Invalid ECKeyValue");
|
||||||
|
}
|
||||||
|
curElem = getNextSiblingElement(curElem, "PublicKey", Constants.SignatureSpec11NS);
|
||||||
|
ECPoint ecPoint = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
String content = XMLUtils.getFullTextChildrenFromNode(curElem);
|
||||||
|
ecPoint = decodePoint(XMLUtils.decode(content), ecParams.getCurve());
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw new MarshalException("Invalid EC Point", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParams);
|
||||||
|
return KeyFactory.getInstance("EC").generatePublic(spec);
|
||||||
|
} catch (NoSuchAlgorithmException ex) {
|
||||||
|
throw new XMLSecurityException(ex);
|
||||||
|
} catch (InvalidKeySpecException ex) {
|
||||||
|
throw new XMLSecurityException(ex);
|
||||||
|
} catch (MarshalException ex) {
|
||||||
|
throw new XMLSecurityException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public String getBaseLocalName() {
|
||||||
|
return Constants._TAG_ECKEYVALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element getFirstChildElement(Node node) {
|
||||||
|
Node child = node.getFirstChild();
|
||||||
|
while (child != null && child.getNodeType() != Node.ELEMENT_NODE) {
|
||||||
|
child = child.getNextSibling();
|
||||||
|
}
|
||||||
|
return (Element)child;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element getNextSiblingElement(Node node, String localName, String namespaceURI)
|
||||||
|
throws MarshalException
|
||||||
|
{
|
||||||
|
return verifyElement(getNextSiblingElement(node), localName, namespaceURI);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element getNextSiblingElement(Node node) {
|
||||||
|
Node sibling = node.getNextSibling();
|
||||||
|
while (sibling != null && sibling.getNodeType() != Node.ELEMENT_NODE) {
|
||||||
|
sibling = sibling.getNextSibling();
|
||||||
|
}
|
||||||
|
return (Element)sibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Element verifyElement(Element elem, String localName, String namespaceURI)
|
||||||
|
throws MarshalException
|
||||||
|
{
|
||||||
|
if (elem == null) {
|
||||||
|
throw new MarshalException("Missing " + localName + " element");
|
||||||
|
}
|
||||||
|
String name = elem.getLocalName();
|
||||||
|
String namespace = elem.getNamespaceURI();
|
||||||
|
if (!name.equals(localName) || namespace == null && namespaceURI != null
|
||||||
|
|| namespace != null && !namespace.equals(namespaceURI)) {
|
||||||
|
throw new MarshalException("Invalid element name: " +
|
||||||
|
namespace + ":" + name + ", expected " + namespaceURI + ":" + localName);
|
||||||
|
}
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getCurveOid(ECParameterSpec params) {
|
||||||
|
// Check that the params represent one of the supported
|
||||||
|
// curves. If there is a match, return the object identifier
|
||||||
|
// of the curve.
|
||||||
|
Curve match;
|
||||||
|
if (matchCurve(params, SECP256R1)) {
|
||||||
|
match = SECP256R1;
|
||||||
|
} else if (matchCurve(params, SECP384R1)) {
|
||||||
|
match = SECP384R1;
|
||||||
|
} else if (matchCurve(params, SECP521R1)) {
|
||||||
|
match = SECP521R1;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return match.getObjectId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean matchCurve(ECParameterSpec params, Curve curve) {
|
||||||
|
int fieldSize = params.getCurve().getField().getFieldSize();
|
||||||
|
return curve.getCurve().getField().getFieldSize() == fieldSize
|
||||||
|
&& curve.getCurve().equals(params.getCurve())
|
||||||
|
&& curve.getGenerator().equals(params.getGenerator())
|
||||||
|
&& curve.getOrder().equals(params.getOrder())
|
||||||
|
&& curve.getCofactor() == params.getCofactor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECPoint decodePoint(byte[] data, EllipticCurve curve)
|
||||||
|
throws IOException {
|
||||||
|
if (data.length == 0 || data[0] != 4) {
|
||||||
|
throw new IOException("Only uncompressed point format " +
|
||||||
|
"supported");
|
||||||
|
}
|
||||||
|
// Per ANSI X9.62, an encoded point is a 1 byte type followed by
|
||||||
|
// ceiling(LOG base 2 field-size / 8) bytes of x and the same of y.
|
||||||
|
int n = (data.length - 1) / 2;
|
||||||
|
if (n != (curve.getField().getFieldSize() + 7) >> 3) {
|
||||||
|
throw new IOException("Point does not match field size");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] xb = Arrays.copyOfRange(data, 1, 1 + n);
|
||||||
|
byte[] yb = Arrays.copyOfRange(data, n + 1, n + 1 + n);
|
||||||
|
|
||||||
|
return new ECPoint(new BigInteger(1, xb), new BigInteger(1, yb));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] encodePoint(ECPoint point, EllipticCurve curve) {
|
||||||
|
// get field size in bytes (rounding up)
|
||||||
|
int n = (curve.getField().getFieldSize() + 7) >> 3;
|
||||||
|
byte[] xb = trimZeroes(point.getAffineX().toByteArray());
|
||||||
|
byte[] yb = trimZeroes(point.getAffineY().toByteArray());
|
||||||
|
if (xb.length > n || yb.length > n) {
|
||||||
|
throw new RuntimeException("Point coordinates do not " +
|
||||||
|
"match field size");
|
||||||
|
}
|
||||||
|
byte[] b = new byte[1 + (n << 1)];
|
||||||
|
b[0] = 4; // uncompressed
|
||||||
|
System.arraycopy(xb, 0, b, n - xb.length + 1, xb.length);
|
||||||
|
System.arraycopy(yb, 0, b, b.length - yb.length, yb.length);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] trimZeroes(byte[] b) {
|
||||||
|
int i = 0;
|
||||||
|
while (i < b.length - 1 && b[i] == 0) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
return Arrays.copyOfRange(b, i, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ECParameterSpec getECParameterSpec(String oid) {
|
||||||
|
if (oid.equals(SECP256R1.getObjectId())) {
|
||||||
|
return SECP256R1;
|
||||||
|
} else if (oid.equals(SECP384R1.getObjectId())) {
|
||||||
|
return SECP384R1;
|
||||||
|
} else if (oid.equals(SECP521R1.getObjectId())) {
|
||||||
|
return SECP521R1;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class Curve extends ECParameterSpec {
|
||||||
|
private final String name;
|
||||||
|
private final String oid;
|
||||||
|
|
||||||
|
Curve(String name, String oid, EllipticCurve curve,
|
||||||
|
ECPoint g, BigInteger n, int h) {
|
||||||
|
super(curve, g, n, h);
|
||||||
|
this.name = name;
|
||||||
|
this.oid = oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getObjectId() {
|
||||||
|
return oid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BigInteger bigInt(String s) {
|
||||||
|
return new BigInteger(s, 16);
|
||||||
|
}
|
||||||
|
}
|
@ -24,18 +24,18 @@ package com.sun.org.apache.xml.internal.security.keys.content.x509;
|
|||||||
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* reserved comment block
|
||||||
|
* DO NOT REMOVE OR ALTER!
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import com.sun.org.apache.xml.internal.security.exceptions.XMLSecurityException;
|
||||||
|
import com.sun.org.apache.xml.internal.security.keys.content.keyvalues.ECKeyValue;
|
||||||
|
import com.sun.org.apache.xml.internal.security.keys.keyresolver.KeyResolverSpi;
|
||||||
|
import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver;
|
||||||
|
import com.sun.org.apache.xml.internal.security.utils.Constants;
|
||||||
|
import com.sun.org.apache.xml.internal.security.utils.XMLUtils;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
public class ECKeyValueResolver extends KeyResolverSpi {
|
||||||
|
|
||||||
|
private static final com.sun.org.slf4j.internal.Logger LOG =
|
||||||
|
com.sun.org.slf4j.internal.LoggerFactory.getLogger(ECKeyValueResolver.class);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method engineResolvePublicKey
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
* @param baseURI
|
||||||
|
* @param storage
|
||||||
|
* @return null if no {@link PublicKey} could be obtained
|
||||||
|
*/
|
||||||
|
public PublicKey engineLookupAndResolvePublicKey(
|
||||||
|
Element element, String baseURI, StorageResolver storage
|
||||||
|
) {
|
||||||
|
if (element == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Element ecKeyElement = null;
|
||||||
|
boolean isKeyValue =
|
||||||
|
XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_KEYVALUE);
|
||||||
|
if (isKeyValue) {
|
||||||
|
ecKeyElement =
|
||||||
|
XMLUtils.selectDs11Node(element.getFirstChild(), Constants._TAG_ECKEYVALUE, 0);
|
||||||
|
} else if (XMLUtils.elementIsInSignature11Space(element, Constants._TAG_ECKEYVALUE)) {
|
||||||
|
// this trick is needed to allow the RetrievalMethodResolver to eat a
|
||||||
|
// ds:ECKeyValue directly (without KeyValue)
|
||||||
|
ecKeyElement = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecKeyElement == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ECKeyValue ecKeyValue = new ECKeyValue(ecKeyElement, baseURI);
|
||||||
|
return ecKeyValue.getPublicKey();
|
||||||
|
} catch (XMLSecurityException ex) {
|
||||||
|
LOG.debug(ex.getMessage(), ex);
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public X509Certificate engineLookupResolveX509Certificate(
|
||||||
|
Element element, String baseURI, StorageResolver storage
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public javax.crypto.SecretKey engineLookupAndResolveSecretKey(
|
||||||
|
Element element, String baseURI, StorageResolver storage
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -44,11 +44,12 @@ public class RSAKeyValueResolver extends KeyResolverSpi {
|
|||||||
public PublicKey engineLookupAndResolvePublicKey(
|
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) {
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user