Merge
This commit is contained in:
commit
3560e1733c
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -121,7 +121,7 @@ ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
-buildBase $(call FixPath, $(IDE_OUTPUTDIR)/vs-output) \
|
||||
-buildSpace $(call FixPath, $(IDE_OUTPUTDIR)) \
|
||||
-makeBinary $(call FixPath, $(MAKE)) \
|
||||
-makeOutput $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-%f/libjvm) \
|
||||
-makeOutput $(call FixPath, $(JDK_OUTPUTDIR)/bin/server) \
|
||||
-absoluteInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \
|
||||
-absoluteSrcInclude $(call FixPath, $(HOTSPOT_OUTPUTDIR)/variant-server/gensrc) \
|
||||
$(EXTRACTED_DEFINES_client) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -114,8 +114,8 @@ public class WinGammaPlatformVC10 extends WinGammaPlatform {
|
||||
tag(cfg, "CodeAnalysisRuleAssemblies");
|
||||
}
|
||||
for (BuildConfig cfg : allConfigs) {
|
||||
tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile import-hotspot LOG=info");
|
||||
tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot import-hotspot LOG=info");
|
||||
tagData(cfg, "NMakeBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile hotspot LOG=info");
|
||||
tagData(cfg, "NMakeReBuildCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot hotspot LOG=info");
|
||||
tagData(cfg, "NMakeCleanCommandLine", cfg.get("MakeBinary") + " -f ../../Makefile clean-hotspot LOG=info");
|
||||
tagData(cfg, "NMakeOutput", cfg.get("MakeOutput") + Util.sep + "jvm.dll");
|
||||
tagData(cfg, "NMakePreprocessorDefinitions", Util.join(";", cfg.getDefines()));
|
||||
|
@ -192,4 +192,3 @@ JVM_AddModulePackage
|
||||
JVM_AddReadsModule
|
||||
JVM_DefineModule
|
||||
JVM_SetBootLoaderUnnamedModule
|
||||
JVM_GetModuleByPackageName
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -532,8 +532,14 @@ void LIR_Assembler::poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo*
|
||||
|
||||
void LIR_Assembler::return_op(LIR_Opr result) {
|
||||
assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == r0, "word returns are in r0,");
|
||||
|
||||
// Pop the stack before the safepoint code
|
||||
__ remove_frame(initial_frame_size_in_bytes());
|
||||
|
||||
if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check();
|
||||
}
|
||||
|
||||
address polling_page(os::get_polling_page());
|
||||
__ read_polling_page(rscratch1, polling_page, relocInfo::poll_return_type);
|
||||
__ ret(lr);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -1179,6 +1179,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
// Is marking still active?
|
||||
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
|
||||
__ ldrw(tmp, in_progress);
|
||||
} else {
|
||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
|
||||
__ ldrb(tmp, in_progress);
|
||||
}
|
||||
__ cbzw(tmp, done);
|
||||
|
||||
// Can we store original value in the thread's buffer?
|
||||
__ ldr(tmp, queue_index);
|
||||
__ cbz(tmp, runtime);
|
||||
|
@ -375,7 +375,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
|
||||
fr._unextended_sp = unextended_sp;
|
||||
|
||||
address original_pc = nm->get_original_pc(&fr);
|
||||
assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
|
||||
assert(nm->insts_contains_inclusive(original_pc),
|
||||
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -629,6 +630,7 @@ void frame::describe_pd(FrameValues& values, int frame_no) {
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_last_sp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_method);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_mdp);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_mirror);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_cache);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_locals);
|
||||
DESCRIBE_FP_OFFSET(interpreter_frame_bcp);
|
||||
|
@ -46,6 +46,9 @@
|
||||
// [pointer to locals ] = locals() locals_offset
|
||||
// [constant pool cache ] = cache() cache_offset
|
||||
|
||||
// [klass of method ] = mirror() mirror_offset
|
||||
// [padding ]
|
||||
|
||||
// [methodData ] = mdp() mdx_offset
|
||||
// [methodOop ] = method() method_offset
|
||||
|
||||
|
@ -82,7 +82,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
|
||||
address original_pc = CompiledMethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
_pc = original_pc;
|
||||
assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
|
||||
assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
|
||||
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
|
@ -53,4 +53,6 @@ const bool CCallingConventionRequiresIntsAsLongs = false;
|
||||
// evidence that it's worth doing.
|
||||
#define DEOPTIMIZE_WHEN_PATCHING
|
||||
|
||||
#define SUPPORT_RESERVED_STACK_AREA
|
||||
|
||||
#endif // CPU_AARCH64_VM_GLOBALDEFINITIONS_AARCH64_HPP
|
||||
|
@ -50,7 +50,7 @@ define_pd_global(intx, InlineFrequencyCount, 100);
|
||||
// stack if compiled for unix and LP64. To pass stack overflow tests we need
|
||||
// 20 shadow pages.
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5))
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (0)
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (1)
|
||||
|
||||
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
|
@ -619,6 +619,22 @@ void InterpreterMacroAssembler::remove_activation(
|
||||
// get sender esp
|
||||
ldr(esp,
|
||||
Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize));
|
||||
if (StackReservedPages > 0) {
|
||||
// testing if reserved zone needs to be re-enabled
|
||||
Label no_reserved_zone_enabling;
|
||||
|
||||
ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset()));
|
||||
cmp(esp, rscratch1);
|
||||
br(Assembler::LS, no_reserved_zone_enabling);
|
||||
|
||||
call_VM_leaf(
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address,
|
||||
InterpreterRuntime::throw_delayed_StackOverflowError));
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
// remove frame anchor
|
||||
leave();
|
||||
// If we're returning to interpreted code we will shortly be
|
||||
|
@ -402,6 +402,30 @@ void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::reserved_stack_check() {
|
||||
// testing if reserved zone needs to be enabled
|
||||
Label no_reserved_zone_enabling;
|
||||
|
||||
ldr(rscratch1, Address(rthread, JavaThread::reserved_stack_activation_offset()));
|
||||
cmp(sp, rscratch1);
|
||||
br(Assembler::LO, no_reserved_zone_enabling);
|
||||
|
||||
enter(); // LR and FP are live.
|
||||
lea(rscratch1, CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone));
|
||||
mov(c_rarg0, rthread);
|
||||
blr(rscratch1);
|
||||
leave();
|
||||
|
||||
// We have already removed our own frame.
|
||||
// throw_delayed_StackOverflowError will think that it's been
|
||||
// called by our caller.
|
||||
lea(rscratch1, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
|
||||
br(rscratch1);
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
|
||||
int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||
Register obj_reg,
|
||||
Register swap_reg,
|
||||
|
@ -957,6 +957,9 @@ public:
|
||||
// stack overflow + shadow pages. Also, clobbers tmp
|
||||
void bang_stack_size(Register size, Register tmp);
|
||||
|
||||
// Check for reserved stack access in method being exited (for JIT)
|
||||
void reserved_stack_check();
|
||||
|
||||
virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
|
||||
Register tmp,
|
||||
int offset);
|
||||
|
@ -4676,8 +4676,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_throw_StackOverflowError_entry =
|
||||
generate_throw_exception("StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::
|
||||
throw_StackOverflowError));
|
||||
SharedRuntime::throw_StackOverflowError));
|
||||
StubRoutines::_throw_delayed_StackOverflowError_entry =
|
||||
generate_throw_exception("delayed StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::throw_delayed_StackOverflowError));
|
||||
if (UseCRC32Intrinsics) {
|
||||
// set table address before stub generation which use it
|
||||
StubRoutines::_crc_table_adr = (address)StubRoutines::aarch64::_crc_table;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -551,6 +551,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
const Register r_index_1 = R1;
|
||||
const Register r_buffer_2 = R2;
|
||||
|
||||
Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_active()));
|
||||
Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_index()));
|
||||
Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
@ -559,6 +561,11 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
// Is marking still active?
|
||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
|
||||
__ ldrb(R1, queue_active);
|
||||
__ cbz(R1, done);
|
||||
|
||||
__ ldr(r_index_1, queue_index);
|
||||
__ ldr(r_pre_val_0, Address(SP, nb_saved_regs*wordSize));
|
||||
__ ldr(r_buffer_2, buffer);
|
||||
|
@ -364,7 +364,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
|
||||
fr._unextended_sp = unextended_sp;
|
||||
|
||||
address original_pc = nm->get_original_pc(&fr);
|
||||
assert(nm->insts_contains(original_pc), "original PC must be in nmethod");
|
||||
assert(nm->insts_contains_inclusive(original_pc),
|
||||
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
|
||||
assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
|
||||
}
|
||||
#endif
|
||||
|
@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
|
||||
address original_pc = CompiledMethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
_pc = original_pc;
|
||||
assert(_cb->as_compiled_method()->insts_contains(_pc), "original PC must be in CompiledMethod");
|
||||
assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
|
||||
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
_deopt_state = not_deoptimized;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -741,7 +741,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
Register tmp = R14;
|
||||
Register tmp2 = R15;
|
||||
|
||||
Label refill, restart;
|
||||
Label refill, restart, marking_not_active;
|
||||
int satb_q_active_byte_offset =
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_active());
|
||||
int satb_q_index_byte_offset =
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_index());
|
||||
@ -753,6 +756,16 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ std(tmp, -16, R1_SP);
|
||||
__ std(tmp2, -24, R1_SP);
|
||||
|
||||
// Is marking still active?
|
||||
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
|
||||
__ lwz(tmp, satb_q_active_byte_offset, R16_thread);
|
||||
} else {
|
||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
|
||||
__ lbz(tmp, satb_q_active_byte_offset, R16_thread);
|
||||
}
|
||||
__ cmpdi(CCR0, tmp, 0);
|
||||
__ beq(CCR0, marking_not_active);
|
||||
|
||||
__ bind(restart);
|
||||
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
|
||||
// size_t so ld_ptr is appropriate.
|
||||
@ -769,6 +782,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ std(tmp, satb_q_index_byte_offset, R16_thread);
|
||||
__ stdx(pre_val, tmp2, tmp); // [_buf + index] := <address_of_card>
|
||||
|
||||
__ bind(marking_not_active);
|
||||
// Restore temp registers and return-from-leaf.
|
||||
__ ld(tmp2, -24, R1_SP);
|
||||
__ ld(tmp, -16, R1_SP);
|
||||
|
@ -2569,7 +2569,7 @@ void MacroAssembler::rtm_retry_lock_on_abort(Register retry_count_Reg, Register
|
||||
}
|
||||
|
||||
// Spin and retry if lock is busy.
|
||||
// inputs: box_Reg (monitor address)
|
||||
// inputs: owner_addr_Reg (monitor address)
|
||||
// : retry_count_Reg
|
||||
// output: retry_count_Reg decremented by 1
|
||||
// CTR is killed
|
||||
@ -2577,15 +2577,22 @@ void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register o
|
||||
Label SpinLoop, doneRetry;
|
||||
addic_(retry_count_Reg, retry_count_Reg, -1);
|
||||
blt(CCR0, doneRetry);
|
||||
li(R0, RTMSpinLoopCount);
|
||||
mtctr(R0);
|
||||
|
||||
if (RTMSpinLoopCount > 1) {
|
||||
li(R0, RTMSpinLoopCount);
|
||||
mtctr(R0);
|
||||
}
|
||||
|
||||
bind(SpinLoop);
|
||||
smt_yield(); // Can't use waitrsv(). No permission (SIGILL).
|
||||
bdz(retryLabel);
|
||||
ld(R0, 0, owner_addr_Reg);
|
||||
cmpdi(CCR0, R0, 0);
|
||||
bne(CCR0, SpinLoop);
|
||||
|
||||
if (RTMSpinLoopCount > 1) {
|
||||
bdz(retryLabel);
|
||||
ld(R0, 0, owner_addr_Reg);
|
||||
cmpdi(CCR0, R0, 0);
|
||||
bne(CCR0, SpinLoop);
|
||||
}
|
||||
|
||||
b(retryLabel);
|
||||
|
||||
bind(doneRetry);
|
||||
|
@ -327,7 +327,10 @@ void VM_Version::initialize() {
|
||||
warning("RTMAbortRatio must be in the range 0 to 100, resetting it to 50");
|
||||
FLAG_SET_DEFAULT(RTMAbortRatio, 50);
|
||||
}
|
||||
guarantee(RTMSpinLoopCount > 0, "unsupported");
|
||||
if (RTMSpinLoopCount < 0) {
|
||||
warning("RTMSpinLoopCount must not be a negative value, resetting it to 0");
|
||||
FLAG_SET_DEFAULT(RTMSpinLoopCount, 0);
|
||||
}
|
||||
#else
|
||||
// Only C2 does RTM locking optimization.
|
||||
// Can't continue because UseRTMLocking affects UseBiasedLocking flag
|
||||
|
@ -1105,16 +1105,16 @@ void LIR_Assembler::reg2mem(LIR_Opr from, LIR_Opr dest_opr, BasicType type,
|
||||
}
|
||||
case T_FLOAT :
|
||||
if (short_disp) {
|
||||
__ z_ste(from->as_float_reg(), disp_value, disp_reg, dest);
|
||||
__ z_ste(from->as_float_reg(), disp_value, disp_reg, dest);
|
||||
} else {
|
||||
__ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
|
||||
__ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
|
||||
}
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
if (short_disp) {
|
||||
__ z_std(from->as_double_reg(), disp_value, disp_reg, dest);
|
||||
__ z_std(from->as_double_reg(), disp_value, disp_reg, dest);
|
||||
} else {
|
||||
__ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
|
||||
__ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
|
||||
}
|
||||
break;
|
||||
default: ShouldNotReachHere();
|
||||
@ -1148,6 +1148,10 @@ void LIR_Assembler::return_op(LIR_Opr result) {
|
||||
__ restore_return_pc();
|
||||
}
|
||||
|
||||
if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check(Z_R14);
|
||||
}
|
||||
|
||||
// We need to mark the code position where the load from the safepoint
|
||||
// polling page was emitted as relocInfo::poll_return_type here.
|
||||
__ relocate(relocInfo::poll_return_type);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -784,7 +784,10 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
Register tmp = Z_R6; // Must be non-volatile because it is used to save pre_val.
|
||||
Register tmp2 = Z_R7;
|
||||
|
||||
Label refill, restart;
|
||||
Label refill, restart, marking_not_active;
|
||||
int satb_q_active_byte_offset =
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_active());
|
||||
int satb_q_index_byte_offset =
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_index());
|
||||
@ -796,6 +799,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
__ z_stg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
|
||||
// Is marking still active?
|
||||
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
|
||||
__ load_and_test_int(tmp, Address(Z_thread, satb_q_active_byte_offset));
|
||||
} else {
|
||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
|
||||
__ load_and_test_byte(tmp, Address(Z_thread, satb_q_active_byte_offset));
|
||||
}
|
||||
__ z_bre(marking_not_active); // Activity indicator is zero, so there is no marking going on currently.
|
||||
|
||||
__ bind(restart);
|
||||
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
|
||||
// size_t so ld_ptr is appropriate.
|
||||
@ -810,6 +822,7 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
__ z_stg(pre_val, 0, tmp, tmp2); // [_buf + index] := <address_of_card>
|
||||
__ z_stg(tmp, satb_q_index_byte_offset, Z_thread);
|
||||
|
||||
__ bind(marking_not_active);
|
||||
// Restore tmp registers (see assertion in G1PreBarrierStub::emit_code()).
|
||||
__ z_lg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
__ z_lg(tmp2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
|
||||
|
@ -52,4 +52,6 @@ const bool CCallingConventionRequiresIntsAsLongs = true;
|
||||
// The expected size in bytes of a cache line, used to pad data structures.
|
||||
#define DEFAULT_CACHE_LINE_SIZE 256
|
||||
|
||||
#define SUPPORT_RESERVED_STACK_AREA
|
||||
|
||||
#endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP
|
||||
|
@ -56,7 +56,7 @@ define_pd_global(intx, InlineSmallCode, 2000);
|
||||
// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
|
||||
// stack. To pass stack overflow tests we need 20 shadow pages.
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2))
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (0)
|
||||
#define DEFAULT_STACK_RESERVED_PAGES (1)
|
||||
|
||||
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
|
||||
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
|
||||
|
@ -860,16 +860,39 @@ void InterpreterMacroAssembler::remove_activation(TosState state,
|
||||
bool throw_monitor_exception,
|
||||
bool install_monitor_exception,
|
||||
bool notify_jvmti) {
|
||||
|
||||
BLOCK_COMMENT("remove_activation {");
|
||||
unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception);
|
||||
|
||||
// Save result (push state before jvmti call and pop it afterwards) and notify jvmti.
|
||||
notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI);
|
||||
|
||||
if (StackReservedPages > 0) {
|
||||
BLOCK_COMMENT("reserved_stack_check:");
|
||||
// Test if reserved zone needs to be enabled.
|
||||
Label no_reserved_zone_enabling;
|
||||
|
||||
// Compare frame pointers. There is no good stack pointer, as with stack
|
||||
// frame compression we can get different SPs when we do calls. A subsequent
|
||||
// call could have a smaller SP, so that this compare succeeds for an
|
||||
// inner call of the method annotated with ReservedStack.
|
||||
z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp)));
|
||||
z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory.
|
||||
z_brl(no_reserved_zone_enabling);
|
||||
|
||||
// Enable reserved zone again, throw stack overflow exception.
|
||||
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
|
||||
call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError));
|
||||
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
|
||||
verify_oop(Z_tos, state);
|
||||
verify_thread();
|
||||
|
||||
pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3);
|
||||
BLOCK_COMMENT("} remove_activation");
|
||||
}
|
||||
|
||||
// lock object
|
||||
|
@ -2666,6 +2666,32 @@ void MacroAssembler::bang_stack_with_offset(int offset) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::reserved_stack_check(Register return_pc) {
|
||||
// Test if reserved zone needs to be enabled.
|
||||
Label no_reserved_zone_enabling;
|
||||
assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub.");
|
||||
BLOCK_COMMENT("reserved_stack_check {");
|
||||
|
||||
z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset()));
|
||||
z_brl(no_reserved_zone_enabling);
|
||||
|
||||
// Enable reserved zone again, throw stack overflow exception.
|
||||
save_return_pc();
|
||||
push_frame_abi160(0);
|
||||
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
|
||||
pop_frame();
|
||||
restore_return_pc();
|
||||
|
||||
load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry());
|
||||
// Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc.
|
||||
z_br(Z_R1);
|
||||
|
||||
should_not_reach_here();
|
||||
|
||||
bind(no_reserved_zone_enabling);
|
||||
BLOCK_COMMENT("} reserved_stack_check");
|
||||
}
|
||||
|
||||
// Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
|
||||
void MacroAssembler::tlab_allocate(Register obj,
|
||||
Register var_size_in_bytes,
|
||||
|
@ -627,6 +627,11 @@ class MacroAssembler: public Assembler {
|
||||
// Stack overflow checking
|
||||
void bang_stack_with_offset(int offset);
|
||||
|
||||
// Check for reserved stack access in method being exited. If the reserved
|
||||
// stack area was accessed, protect it again and throw StackOverflowError.
|
||||
// Uses Z_R1.
|
||||
void reserved_stack_check(Register return_pc);
|
||||
|
||||
// Atomics
|
||||
// -- none?
|
||||
|
||||
|
@ -909,15 +909,8 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
// If this does safepoint polling, then do it here.
|
||||
bool need_polling = do_polling() && C->is_method_compilation();
|
||||
|
||||
// Touch the polling page.
|
||||
// Part 1: get the page's address.
|
||||
if (need_polling) {
|
||||
AddressLiteral pp(os::get_polling_page());
|
||||
__ load_const_optimized(Z_R1_scratch, pp);
|
||||
}
|
||||
|
||||
// Pop frame, restore return_pc, and all stuff needed by interpreter.
|
||||
// Pop frame by add insted of load (a penny saved is a penny got :-).
|
||||
// Pop frame by add instead of load (a penny saved is a penny got :-).
|
||||
int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
|
||||
int retPC_offset = frame_size_in_bytes + _z_abi16(return_pc);
|
||||
if (Displacement::is_validDisp(retPC_offset)) {
|
||||
@ -928,9 +921,14 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
__ restore_return_pc();
|
||||
}
|
||||
|
||||
// Touch the polling page,
|
||||
// part 2: touch the page now.
|
||||
if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
|
||||
__ reserved_stack_check(Z_R14);
|
||||
}
|
||||
|
||||
// Touch the polling page.
|
||||
if (need_polling) {
|
||||
AddressLiteral pp(os::get_polling_page());
|
||||
__ load_const_optimized(Z_R1_scratch, pp);
|
||||
// We need to mark the code position where the load from the safepoint
|
||||
// polling page was emitted as relocInfo::poll_return_type here.
|
||||
__ relocate(relocInfo::poll_return_type);
|
||||
@ -939,7 +937,7 @@ void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
}
|
||||
|
||||
uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
|
||||
// variable size. determine dynamically.
|
||||
// Variable size. determine dynamically.
|
||||
return MachNode::size(ra_);
|
||||
}
|
||||
|
||||
|
@ -2433,13 +2433,12 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_throw_StackOverflowError_entry =
|
||||
generate_throw_exception("StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
|
||||
StubRoutines::_throw_delayed_StackOverflowError_entry =
|
||||
generate_throw_exception("delayed StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Entry points that are platform specific.
|
||||
// Build this early so it's available for the interpreter.
|
||||
StubRoutines::_throw_StackOverflowError_entry =
|
||||
generate_throw_exception("StackOverflowError throw_exception",
|
||||
CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
|
||||
|
||||
if (UseCRC32Intrinsics) {
|
||||
// We have no CRC32 table on z/Architecture.
|
||||
|
@ -1112,16 +1112,21 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) {
|
||||
// top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state
|
||||
__ add2reg(top_frame_size,
|
||||
frame::z_top_ijava_frame_abi_size +
|
||||
frame::z_ijava_state_size +
|
||||
frame::interpreter_frame_monitor_size() * wordSize,
|
||||
frame::z_ijava_state_size +
|
||||
frame::interpreter_frame_monitor_size() * wordSize,
|
||||
max_stack);
|
||||
|
||||
// Check if there's room for the new frame...
|
||||
Register frame_size = max_stack; // Reuse the regiser for max_stack.
|
||||
__ z_lgr(frame_size, Z_SP);
|
||||
__ z_sgr(frame_size, sp_after_resize);
|
||||
__ z_agr(frame_size, top_frame_size);
|
||||
generate_stack_overflow_check(frame_size, fp/*tmp1*/);
|
||||
if (!native_call) {
|
||||
// Stack overflow check.
|
||||
// Native calls don't need the stack size check since they have no
|
||||
// expression stack and the arguments are already on the stack and
|
||||
// we only add a handful of words to the stack.
|
||||
Register frame_size = max_stack; // Reuse the regiser for max_stack.
|
||||
__ z_lgr(frame_size, Z_SP);
|
||||
__ z_sgr(frame_size, sp_after_resize);
|
||||
__ z_agr(frame_size, top_frame_size);
|
||||
generate_stack_overflow_check(frame_size, fp/*tmp1*/);
|
||||
}
|
||||
|
||||
DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP));
|
||||
__ asm_assert_eq("killed Z_R14", 0);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -694,6 +694,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
|
||||
int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) {
|
||||
int store_offset;
|
||||
if (!Assembler::is_simm13(offset + (type == T_LONG) ? wordSize : 0)) {
|
||||
assert(base != O7, "destroying register");
|
||||
assert(!unaligned, "can't handle this");
|
||||
// for offsets larger than a simm13 we setup the offset in O7
|
||||
__ set(offset, O7);
|
||||
@ -712,9 +713,12 @@ int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType
|
||||
case T_LONG :
|
||||
#ifdef _LP64
|
||||
if (unaligned || PatchALot) {
|
||||
__ srax(from_reg->as_register_lo(), 32, O7);
|
||||
// Don't use O7 here because it may be equal to 'base' (see LIR_Assembler::reg2mem)
|
||||
assert(G3_scratch != base, "can't handle this");
|
||||
assert(G3_scratch != from_reg->as_register_lo(), "can't handle this");
|
||||
__ srax(from_reg->as_register_lo(), 32, G3_scratch);
|
||||
__ stw(from_reg->as_register_lo(), base, offset + lo_word_offset_in_bytes);
|
||||
__ stw(O7, base, offset + hi_word_offset_in_bytes);
|
||||
__ stw(G3_scratch, base, offset + hi_word_offset_in_bytes);
|
||||
} else {
|
||||
__ stx(from_reg->as_register_lo(), base, offset);
|
||||
}
|
||||
@ -821,7 +825,7 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ
|
||||
case T_SHORT : __ ldsh(base, offset, to_reg->as_register()); break;
|
||||
case T_INT : __ ld(base, offset, to_reg->as_register()); break;
|
||||
case T_LONG :
|
||||
if (!unaligned) {
|
||||
if (!unaligned && !PatchALot) {
|
||||
#ifdef _LP64
|
||||
__ ldx(base, offset, to_reg->as_register_lo());
|
||||
#else
|
||||
@ -1297,7 +1301,7 @@ void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type,
|
||||
disp_reg = O7;
|
||||
}
|
||||
} else if (unaligned || PatchALot) {
|
||||
__ add(src, addr->index()->as_register(), O7);
|
||||
__ add(src, addr->index()->as_pointer_register(), O7);
|
||||
src = O7;
|
||||
} else {
|
||||
disp_reg = addr->index()->as_pointer_register();
|
||||
@ -1424,7 +1428,7 @@ void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type,
|
||||
disp_reg = O7;
|
||||
}
|
||||
} else if (unaligned || PatchALot) {
|
||||
__ add(src, addr->index()->as_register(), O7);
|
||||
__ add(src, addr->index()->as_pointer_register(), O7);
|
||||
src = O7;
|
||||
} else {
|
||||
disp_reg = addr->index()->as_pointer_register();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -856,7 +856,9 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
Register tmp2 = G3_scratch;
|
||||
|
||||
Label refill, restart;
|
||||
bool with_frame = false; // I don't know if we can do with-frame.
|
||||
int satb_q_active_byte_offset =
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_active());
|
||||
int satb_q_index_byte_offset =
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_index());
|
||||
@ -864,6 +866,17 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_buf());
|
||||
|
||||
// Is marking still active?
|
||||
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
|
||||
__ ld(G2_thread, satb_q_active_byte_offset, tmp);
|
||||
} else {
|
||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
|
||||
__ ldsb(G2_thread, satb_q_active_byte_offset, tmp);
|
||||
}
|
||||
__ cmp_and_br_short(tmp, G0, Assembler::notEqual, Assembler::pt, restart);
|
||||
__ retl();
|
||||
__ delayed()->nop();
|
||||
|
||||
__ bind(restart);
|
||||
// Load the index into the SATB buffer. SATBMarkQueue::_index is a
|
||||
// size_t so ld_ptr is appropriate
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1623,6 +1623,8 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
|
||||
NOT_LP64(__ get_thread(thread);)
|
||||
|
||||
Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_active()));
|
||||
Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
SATBMarkQueue::byte_offset_of_index()));
|
||||
Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
|
||||
@ -1631,6 +1633,15 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
|
||||
Label done;
|
||||
Label runtime;
|
||||
|
||||
// Is marking still active?
|
||||
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
|
||||
__ cmpl(queue_active, 0);
|
||||
} else {
|
||||
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
|
||||
__ cmpb(queue_active, 0);
|
||||
}
|
||||
__ jcc(Assembler::equal, done);
|
||||
|
||||
// Can we store original value in the thread's buffer?
|
||||
|
||||
__ movptr(tmp, queue_index);
|
||||
|
@ -376,7 +376,8 @@ void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp
|
||||
fr._unextended_sp = unextended_sp;
|
||||
|
||||
address original_pc = nm->get_original_pc(&fr);
|
||||
assert(nm->insts_contains(original_pc), "original PC must be in CompiledMethod");
|
||||
assert(nm->insts_contains_inclusive(original_pc),
|
||||
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -75,7 +75,8 @@ inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address
|
||||
address original_pc = CompiledMethod::get_deopt_original_pc(this);
|
||||
if (original_pc != NULL) {
|
||||
_pc = original_pc;
|
||||
assert(((CompiledMethod*)_cb)->insts_contains(_pc), "original PC must be in CompiledMethod");
|
||||
assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc),
|
||||
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
|
||||
_deopt_state = is_deoptimized;
|
||||
} else {
|
||||
if (_cb->is_deoptimization_stub()) {
|
||||
|
@ -3499,12 +3499,12 @@ void MacroAssembler::movdqu(XMMRegister dst, XMMRegister src) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) {
|
||||
void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg) {
|
||||
if (reachable(src)) {
|
||||
movdqu(dst, as_Address(src));
|
||||
} else {
|
||||
lea(rscratch1, src);
|
||||
movdqu(dst, Address(rscratch1, 0));
|
||||
lea(scratchReg, src);
|
||||
movdqu(dst, Address(scratchReg, 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1085,7 +1085,7 @@ public:
|
||||
void movdqu(Address dst, XMMRegister src);
|
||||
void movdqu(XMMRegister dst, Address src);
|
||||
void movdqu(XMMRegister dst, XMMRegister src);
|
||||
void movdqu(XMMRegister dst, AddressLiteral src);
|
||||
void movdqu(XMMRegister dst, AddressLiteral src, Register scratchReg = rscratch1);
|
||||
// AVX Unaligned forms
|
||||
void vmovdqu(Address dst, XMMRegister src);
|
||||
void vmovdqu(XMMRegister dst, Address src);
|
||||
|
@ -817,7 +817,7 @@ enum {
|
||||
movl(d, Address(CTX, 4*3));
|
||||
movl(e, Address(CTX, 4*4));
|
||||
movl(f, Address(CTX, 4*5));
|
||||
movl(g, Address(CTX, 4*6));
|
||||
// load g - r10 after it is used as scratch
|
||||
movl(h, Address(CTX, 4*7));
|
||||
|
||||
pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask;
|
||||
@ -825,6 +825,8 @@ enum {
|
||||
vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip]
|
||||
vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip]
|
||||
|
||||
movl(g, Address(CTX, 4*6));
|
||||
|
||||
movq(Address(rsp, _CTX), CTX); // store
|
||||
|
||||
bind(loop0);
|
||||
@ -977,7 +979,7 @@ bind(only_one_block);
|
||||
movl(d, Address(CTX, 4*3)); // 0xa54ff53a
|
||||
movl(e, Address(CTX, 4*4)); // 0x510e527f
|
||||
movl(f, Address(CTX, 4*5)); // 0x9b05688c
|
||||
movl(g, Address(CTX, 4*6)); // 0x1f83d9ab
|
||||
// load g - r10 after use as scratch
|
||||
movl(h, Address(CTX, 4*7)); // 0x5be0cd19
|
||||
|
||||
|
||||
@ -986,6 +988,8 @@ bind(only_one_block);
|
||||
vmovdqu(SHUF_00BA, ExternalAddress(pshuffle_byte_flip_mask_addr + 32)); //[_SHUF_00BA wrt rip]
|
||||
vmovdqu(SHUF_DC00, ExternalAddress(pshuffle_byte_flip_mask_addr + 64)); //[_SHUF_DC00 wrt rip]
|
||||
|
||||
movl(g, Address(CTX, 4*6)); // 0x1f83d9ab
|
||||
|
||||
movq(Address(rsp, _CTX), CTX);
|
||||
jmpb(do_last_block);
|
||||
|
||||
@ -1154,9 +1158,8 @@ void MacroAssembler::sha512_AVX2_one_round_and_schedule(
|
||||
// Move to appropriate lanes for calculating w[16] and w[17]
|
||||
vperm2f128(xmm4, xmm0, xmm0, 0); //xmm4 = W[-16] + W[-7] + s0{ BABA }
|
||||
|
||||
address MASK_YMM_LO = StubRoutines::x86::pshuffle_byte_flip_mask_addr_sha512();
|
||||
//Move to appropriate lanes for calculating w[18] and w[19]
|
||||
vpand(xmm0, xmm0, ExternalAddress(MASK_YMM_LO + 32), AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 }
|
||||
vpand(xmm0, xmm0, xmm10, AVX_256bit); //xmm0 = W[-16] + W[-7] + s0{ DC00 }
|
||||
//Calculate w[16] and w[17] in both 128 bit lanes
|
||||
//Calculate sigma1 for w[16] and w[17] on both 128 bit lanes
|
||||
vperm2f128(xmm2, xmm7, xmm7, 17); //xmm2 = W[-2] {BABA}
|
||||
@ -1250,6 +1253,7 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
|
||||
|
||||
const XMMRegister& XFER = xmm0; // YTMP0
|
||||
const XMMRegister& BYTE_FLIP_MASK = xmm9; // ymm9
|
||||
const XMMRegister& YMM_MASK_LO = xmm10; // ymm10
|
||||
#ifdef _WIN64
|
||||
const Register& INP = rcx; //1st arg
|
||||
const Register& CTX = rdx; //2nd arg
|
||||
@ -1368,11 +1372,14 @@ void MacroAssembler::sha512_AVX2(XMMRegister msg, XMMRegister state0, XMMRegiste
|
||||
movq(d, Address(CTX, 8 * 3));
|
||||
movq(e, Address(CTX, 8 * 4));
|
||||
movq(f, Address(CTX, 8 * 5));
|
||||
movq(g, Address(CTX, 8 * 6));
|
||||
// load g - r10 after it is used as scratch
|
||||
movq(h, Address(CTX, 8 * 7));
|
||||
|
||||
pshuffle_byte_flip_mask_addr = pshuffle_byte_flip_mask_sha512;
|
||||
vmovdqu(BYTE_FLIP_MASK, ExternalAddress(pshuffle_byte_flip_mask_addr + 0)); //PSHUFFLE_BYTE_FLIP_MASK wrt rip
|
||||
vmovdqu(YMM_MASK_LO, ExternalAddress(pshuffle_byte_flip_mask_addr + 32));
|
||||
|
||||
movq(g, Address(CTX, 8 * 6));
|
||||
|
||||
bind(loop0);
|
||||
lea(TBL, ExternalAddress(K512_W));
|
||||
|
@ -3207,7 +3207,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16)
|
||||
#else
|
||||
const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64
|
||||
const Register len_reg = r10; // pick the first volatile windows register
|
||||
const Register len_reg = r11; // pick the volatile windows register
|
||||
#endif
|
||||
const Register pos = rax;
|
||||
|
||||
@ -3404,7 +3404,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16)
|
||||
#else
|
||||
const Address len_mem(rbp, 6 * wordSize); // length is on stack on Win64
|
||||
const Register len_reg = r10; // pick the first volatile windows register
|
||||
const Register len_reg = r11; // pick the volatile windows register
|
||||
#endif
|
||||
const Register pos = rax;
|
||||
|
||||
@ -3930,7 +3930,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
__ push(rbx); // Save RBX
|
||||
__ movdqu(xmm_curr_counter, Address(counter, 0x00)); // initialize counter with initial counter
|
||||
__ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()));
|
||||
__ movdqu(xmm_counter_shuf_mask, ExternalAddress(StubRoutines::x86::counter_shuffle_mask_addr()), pos); // pos as scratch
|
||||
__ pshufb(xmm_curr_counter, xmm_counter_shuf_mask); //counter is shuffled
|
||||
__ movptr(pos, 0);
|
||||
|
||||
@ -3953,7 +3953,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ movl(Address(used_addr, 0), used);
|
||||
|
||||
// key length could be only {11, 13, 15} * 4 = {44, 52, 60}
|
||||
__ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
|
||||
__ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()), rbx); // rbx as scratch
|
||||
__ movl(rbx, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
|
||||
__ cmpl(rbx, 52);
|
||||
__ jcc(Assembler::equal, L_multiBlock_loopTop[1]);
|
||||
|
@ -37,6 +37,7 @@ import jdk.tools.jaotc.binformat.Symbol.Binding;
|
||||
import jdk.tools.jaotc.binformat.Symbol.Kind;
|
||||
import jdk.tools.jaotc.binformat.elf.JELFRelocObject;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
|
||||
/**
|
||||
* A format-agnostic container class that holds various components of a binary.
|
||||
@ -257,9 +258,9 @@ public class BinaryContainer implements SymbolTable {
|
||||
* prefix {@code prefix}. It also initializes internal code container, symbol table and
|
||||
* relocation tables.
|
||||
*/
|
||||
public BinaryContainer(GraalHotSpotVMConfig config, String jvmVersion) {
|
||||
this.codeSegmentSize = config.codeSegmentSize;
|
||||
this.codeEntryAlignment = config.codeEntryAlignment;
|
||||
public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
|
||||
this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
|
||||
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
|
||||
|
||||
// read only, code
|
||||
codeContainer = new CodeContainer(".text", this);
|
||||
@ -289,30 +290,31 @@ public class BinaryContainer implements SymbolTable {
|
||||
|
||||
addGlobalSymbols();
|
||||
|
||||
recordConfiguration(config);
|
||||
recordConfiguration(graalHotSpotVMConfig, graphBuilderConfig);
|
||||
}
|
||||
|
||||
private void recordConfiguration(GraalHotSpotVMConfig config) {
|
||||
private void recordConfiguration(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig) {
|
||||
// @formatter:off
|
||||
boolean[] booleanFlags = { config.cAssertions, // Debug VM
|
||||
config.useCompressedOops,
|
||||
config.useCompressedClassPointers,
|
||||
config.compactFields,
|
||||
config.useG1GC,
|
||||
config.useCMSGC,
|
||||
config.useTLAB,
|
||||
config.useBiasedLocking,
|
||||
boolean[] booleanFlags = { graalHotSpotVMConfig.cAssertions, // Debug VM
|
||||
graalHotSpotVMConfig.useCompressedOops,
|
||||
graalHotSpotVMConfig.useCompressedClassPointers,
|
||||
graalHotSpotVMConfig.compactFields,
|
||||
graalHotSpotVMConfig.useG1GC,
|
||||
graalHotSpotVMConfig.useCMSGC,
|
||||
graalHotSpotVMConfig.useTLAB,
|
||||
graalHotSpotVMConfig.useBiasedLocking,
|
||||
TieredAOT.getValue(),
|
||||
config.enableContended,
|
||||
config.restrictContended,
|
||||
graalHotSpotVMConfig.enableContended,
|
||||
graalHotSpotVMConfig.restrictContended,
|
||||
graphBuilderConfig.omitAssertions()
|
||||
};
|
||||
|
||||
int[] intFlags = { config.narrowOopShift,
|
||||
config.narrowKlassShift,
|
||||
config.contendedPaddingWidth,
|
||||
config.fieldsAllocationStyle,
|
||||
config.objectAlignment,
|
||||
config.codeSegmentSize,
|
||||
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift,
|
||||
graalHotSpotVMConfig.getKlassEncoding().shift,
|
||||
graalHotSpotVMConfig.contendedPaddingWidth,
|
||||
graalHotSpotVMConfig.fieldsAllocationStyle,
|
||||
1 << graalHotSpotVMConfig.getOopEncoding().alignment,
|
||||
graalHotSpotVMConfig.codeSegmentSize,
|
||||
};
|
||||
// @formatter:on
|
||||
|
||||
@ -395,6 +397,10 @@ public class BinaryContainer implements SymbolTable {
|
||||
return "_aot_narrow_klass_base_address";
|
||||
}
|
||||
|
||||
public String getNarrowOopBaseAddressSymbolName() {
|
||||
return "_aot_narrow_oop_base_address";
|
||||
}
|
||||
|
||||
public String getLogOfHeapRegionGrainBytesSymbolName() {
|
||||
return "_aot_log_of_heap_region_grain_bytes";
|
||||
}
|
||||
@ -445,6 +451,7 @@ public class BinaryContainer implements SymbolTable {
|
||||
createGotSymbol(getHeapTopAddressSymbolName());
|
||||
createGotSymbol(getHeapEndAddressSymbolName());
|
||||
createGotSymbol(getNarrowKlassBaseAddressSymbolName());
|
||||
createGotSymbol(getNarrowOopBaseAddressSymbolName());
|
||||
createGotSymbol(getPollingPageSymbolName());
|
||||
createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
|
||||
createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());
|
||||
|
@ -77,10 +77,14 @@ public class AOTBackend {
|
||||
this.filters = filters;
|
||||
providers = backend.getProviders();
|
||||
codeCache = providers.getCodeCache();
|
||||
graphBuilderSuite = initGraphBuilderSuite(backend);
|
||||
graphBuilderSuite = initGraphBuilderSuite(backend, main.options.compileWithAssertions);
|
||||
highTierContext = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.ALL);
|
||||
}
|
||||
|
||||
public PhaseSuite<HighTierContext> getGraphBuilderSuite() {
|
||||
return graphBuilderSuite;
|
||||
}
|
||||
|
||||
private Suites getSuites() {
|
||||
// create suites every time, as we modify options for the compiler
|
||||
return backend.getSuites().getDefaultSuites();
|
||||
@ -146,14 +150,14 @@ public class AOTBackend {
|
||||
return backend.getRuntime().getVMConfig().cAssertions;
|
||||
}
|
||||
|
||||
private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend) {
|
||||
private static PhaseSuite<HighTierContext> initGraphBuilderSuite(HotSpotBackend backend, boolean compileWithAssertions) {
|
||||
PhaseSuite<HighTierContext> graphBuilderSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
|
||||
ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
|
||||
GraphBuilderConfiguration baseConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
|
||||
|
||||
// Use all default plugins.
|
||||
Plugins plugins = baseConfig.getPlugins();
|
||||
GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true);
|
||||
GraphBuilderConfiguration aotConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withOmitAssertions(!compileWithAssertions);
|
||||
|
||||
iterator.next();
|
||||
iterator.remove();
|
||||
|
@ -293,12 +293,18 @@ public class AOTCompiledClass {
|
||||
// Record methods holder
|
||||
methodInfo.addDependentKlassData(binaryContainer, resolvedJavaType);
|
||||
// Record inlinee classes
|
||||
for (ResolvedJavaMethod m : methodInfo.getCompilationResult().getMethods()) {
|
||||
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
|
||||
ResolvedJavaMethod[] inlinees = methodInfo.getCompilationResult().getMethods();
|
||||
if (inlinees != null) {
|
||||
for (ResolvedJavaMethod m : inlinees) {
|
||||
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) m.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
// Record classes of fields that were accessed
|
||||
for (ResolvedJavaField f : methodInfo.getCompilationResult().getFields()) {
|
||||
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
|
||||
ResolvedJavaField[] fields = methodInfo.getCompilationResult().getFields();
|
||||
if (fields != null) {
|
||||
for (ResolvedJavaField f : fields) {
|
||||
methodInfo.addDependentKlassData(binaryContainer, (HotSpotResolvedObjectType) f.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
package jdk.tools.jaotc;/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class LoadedClass {
|
||||
private final String name;
|
||||
private final Class<?> clz;
|
||||
|
||||
public LoadedClass(String name, Class<?> clz) {
|
||||
this.name = name;
|
||||
this.clz = clz;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Class<?> getLoadedClass() {
|
||||
return clz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof LoadedClass)) return false;
|
||||
|
||||
LoadedClass that = (LoadedClass) o;
|
||||
|
||||
if (name != null ? !name.equals(that.name) : that.name != null) return false;
|
||||
return clz != null ? clz.equals(that.clz) : that.clz == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name != null ? name.hashCode() : 0;
|
||||
result = 31 * result + (clz != null ? clz.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,19 +43,31 @@ import java.nio.file.Paths;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.tools.jaotc.binformat.BinaryContainer;
|
||||
import jdk.tools.jaotc.binformat.ByteContainer;
|
||||
import jdk.tools.jaotc.collect.ClassCollector;
|
||||
import jdk.tools.jaotc.collect.*;
|
||||
import jdk.tools.jaotc.collect.classname.ClassNameSourceProvider;
|
||||
import jdk.tools.jaotc.collect.directory.DirectorySourceProvider;
|
||||
import jdk.tools.jaotc.collect.jar.JarSourceProvider;
|
||||
import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
|
||||
import jdk.tools.jaotc.utils.Timer;
|
||||
|
||||
import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
|
||||
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
|
||||
import org.graalvm.compiler.java.GraphBuilderPhase;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.graalvm.compiler.runtime.RuntimeProvider;
|
||||
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
@ -120,17 +132,7 @@ public class Main implements LogPrinter {
|
||||
abstract void process(Main task, String opt, String arg) throws BadArgs;
|
||||
}
|
||||
|
||||
static Option[] recognizedOptions = {new Option(" --module <name> Module to compile", true, "--module") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.module = arg;
|
||||
}
|
||||
}, new Option(" --module-path <path> Specify where to find module to compile", true, "--module-path") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.modulepath = arg;
|
||||
}
|
||||
}, new Option(" --output <file> Output file name", true, "--output") {
|
||||
static Option[] recognizedOptions = { new Option(" --output <file> Output file name", true, "--output") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
String name = arg;
|
||||
@ -139,22 +141,48 @@ public class Main implements LogPrinter {
|
||||
}
|
||||
task.options.outputName = name;
|
||||
}
|
||||
}, new Option(" --class-name <class names> List of classes to compile", true, "--class-name", "--classname") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.files.addAll(ClassSearch.makeList(ClassNameSourceProvider.TYPE, arg));
|
||||
}
|
||||
}, new Option(" --jar <jarfiles> List of jar files to compile", true, "--jar") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.files.addAll(ClassSearch.makeList(JarSourceProvider.TYPE, arg));
|
||||
}
|
||||
}, new Option(" --module <modules> List of modules to compile", true, "--module") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.files.addAll(ClassSearch.makeList(ModuleSourceProvider.TYPE, arg));
|
||||
}
|
||||
}, new Option(" --directory <dirs> List of directories where to search for files to compile", true, "--directory") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.files.addAll(ClassSearch.makeList(DirectorySourceProvider.TYPE, arg));
|
||||
}
|
||||
}, new Option(" --search-path <dirs> List of directories where to search for specified files", true, "--search-path") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
String[] elements = arg.split(":");
|
||||
task.options.searchPath.add(elements);
|
||||
}
|
||||
}, new Option(" --compile-commands <file> Name of file with compile commands", true, "--compile-commands") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.methodList = arg;
|
||||
}
|
||||
}, new Option(" --compile-for-tiered Generated profiling code for tiered compilation", false, "--compile-for-tiered") {
|
||||
}, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
TieredAOT.setValue(true);
|
||||
}
|
||||
}, new Option(" --classpath <path> Specify where to find user class files", true, "--classpath", "--class-path") {
|
||||
}, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
task.options.classpath = arg;
|
||||
task.options.compileWithAssertions = true;
|
||||
}
|
||||
}, new Option(" --threads <number> Number of compilation threads to be used", true, "--threads") {
|
||||
}, new Option(" --compile-threads <number> Number of compilation threads to be used", true, "--compile-threads", "--threads") {
|
||||
@Override
|
||||
void process(Main task, String opt, String arg) {
|
||||
int threads = Integer.parseInt(arg);
|
||||
@ -213,27 +241,27 @@ public class Main implements LogPrinter {
|
||||
}};
|
||||
|
||||
public static class Options {
|
||||
public List<String> files = new LinkedList<>();
|
||||
public String module = null;
|
||||
public String modulepath = "modules";
|
||||
public List<SearchFor> files = new LinkedList<>();
|
||||
public String outputName = "unnamed";
|
||||
public String methodList;
|
||||
public String classpath = ".";
|
||||
public List<ClassSource> sources = new ArrayList<>();
|
||||
public SearchPath searchPath = new SearchPath();
|
||||
|
||||
/**
|
||||
* We don't see scaling beyond 16 threads.
|
||||
*/
|
||||
private static final int COMPILER_THREADS = 16;
|
||||
|
||||
int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
|
||||
public int threads = Integer.min(COMPILER_THREADS, Runtime.getRuntime().availableProcessors());
|
||||
|
||||
public boolean ignoreClassLoadingErrors;
|
||||
public boolean exitOnError;
|
||||
boolean info;
|
||||
boolean verbose;
|
||||
boolean debug;
|
||||
boolean help;
|
||||
boolean version;
|
||||
public boolean info;
|
||||
public boolean verbose;
|
||||
public boolean debug;
|
||||
public boolean help;
|
||||
public boolean version;
|
||||
public boolean compileWithAssertions;
|
||||
}
|
||||
|
||||
/* package */final Options options = new Options();
|
||||
@ -275,7 +303,9 @@ public class Main implements LogPrinter {
|
||||
|
||||
printlnInfo("Compiling " + options.outputName + "...");
|
||||
final long start = System.currentTimeMillis();
|
||||
run();
|
||||
if (!run()) {
|
||||
return EXIT_ABNORMAL;
|
||||
}
|
||||
final long end = System.currentTimeMillis();
|
||||
printlnInfo("Total time: " + (end - start) + " ms");
|
||||
|
||||
@ -318,17 +348,34 @@ public class Main implements LogPrinter {
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private void run() throws Exception {
|
||||
private boolean run() throws Exception {
|
||||
openLog();
|
||||
|
||||
try {
|
||||
CompilationSpec compilationRestrictions = collectSpecifiedMethods();
|
||||
|
||||
Set<Class<?>> classesToCompile;
|
||||
Set<Class<?>> classesToCompile = new HashSet<>();
|
||||
|
||||
try (Timer t = new Timer(this, "")) {
|
||||
ClassCollector collector = new ClassCollector(this.options, this);
|
||||
classesToCompile = collector.collectClassesToCompile();
|
||||
FileSupport fileSupport = new FileSupport();
|
||||
ClassSearch lookup = new ClassSearch();
|
||||
lookup.addProvider(new ModuleSourceProvider());
|
||||
lookup.addProvider(new ClassNameSourceProvider(fileSupport));
|
||||
lookup.addProvider(new JarSourceProvider());
|
||||
lookup.addProvider(new DirectorySourceProvider(fileSupport));
|
||||
|
||||
List<LoadedClass> found = null;
|
||||
try {
|
||||
found = lookup.search(options.files, options.searchPath);
|
||||
} catch (InternalError e) {
|
||||
reportError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (LoadedClass loadedClass : found) {
|
||||
classesToCompile.add(loadedClass.getLoadedClass());
|
||||
}
|
||||
|
||||
printInfo(classesToCompile.size() + " classes found");
|
||||
}
|
||||
|
||||
@ -356,6 +403,11 @@ public class Main implements LogPrinter {
|
||||
AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
|
||||
classes = compiler.compileClasses(classes);
|
||||
|
||||
GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
|
||||
PhaseSuite<HighTierContext> graphBuilderSuite = aotBackend.getGraphBuilderSuite();
|
||||
ListIterator<BasePhase<? super HighTierContext>> iterator = graphBuilderSuite.findPhase(GraphBuilderPhase.class);
|
||||
GraphBuilderConfiguration graphBuilderConfig = ((GraphBuilderPhase) iterator.previous()).getGraphBuilderConfig();
|
||||
|
||||
// Free memory!
|
||||
try (Timer t = options.verbose ? new Timer(this, "Freeing memory") : null) {
|
||||
printMemoryUsage();
|
||||
@ -364,7 +416,7 @@ public class Main implements LogPrinter {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
BinaryContainer binaryContainer = new BinaryContainer(runtime.getVMConfig(), JVM_VERSION);
|
||||
BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
|
||||
DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
|
||||
dataBuilder.prepareData();
|
||||
|
||||
@ -446,6 +498,7 @@ public class Main implements LogPrinter {
|
||||
} finally {
|
||||
closeLog();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addMethods(AOTCompiledClass aotClass, ResolvedJavaMethod[] methods, CompilationSpec compilationRestrictions, GraalFilters filters) {
|
||||
@ -509,7 +562,7 @@ public class Main implements LogPrinter {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
options.files.add(arg);
|
||||
options.files.add(new SearchFor(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -570,6 +623,12 @@ public class Main implements LogPrinter {
|
||||
log.flush();
|
||||
}
|
||||
|
||||
private void reportError(Throwable e) {
|
||||
log.println("Error: " + e.getMessage());
|
||||
e.printStackTrace(log);
|
||||
log.flush();
|
||||
}
|
||||
|
||||
private void reportError(String key, Object... args) {
|
||||
printError(MessageFormat.format(key, args));
|
||||
}
|
||||
@ -580,17 +639,17 @@ public class Main implements LogPrinter {
|
||||
}
|
||||
|
||||
private void showUsage() {
|
||||
log.println("Usage: " + PROGNAME + " <options> list...");
|
||||
log.println("Usage: " + PROGNAME + " <options> list");
|
||||
log.println("use --help for a list of possible options");
|
||||
}
|
||||
|
||||
private void showHelp() {
|
||||
log.println("Usage: " + PROGNAME + " <options> <--module name> | <list...>");
|
||||
log.println("Usage: " + PROGNAME + " <options> list");
|
||||
log.println();
|
||||
log.println(" list A list of class files, jar files or directories which");
|
||||
log.println(" contains class files.");
|
||||
log.println(" list A : separated list of class names, modules, jar files");
|
||||
log.println(" or directories which contain class files.");
|
||||
log.println();
|
||||
log.println("where possible options include:");
|
||||
log.println("where options include:");
|
||||
for (Option o : recognizedOptions) {
|
||||
String name = o.aliases[0].substring(1); // there must always be at least one name
|
||||
name = name.charAt(0) == '-' ? name.substring(1) : name;
|
||||
|
@ -48,6 +48,7 @@ enum MarkId {
|
||||
HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"),
|
||||
HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"),
|
||||
NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"),
|
||||
NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"),
|
||||
CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"),
|
||||
LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"),
|
||||
INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED");
|
||||
|
@ -57,6 +57,7 @@ class MarkProcessor {
|
||||
case HEAP_TOP_ADDRESS:
|
||||
case HEAP_END_ADDRESS:
|
||||
case NARROW_KLASS_BASE_ADDRESS:
|
||||
case NARROW_OOP_BASE_ADDRESS:
|
||||
case CRC_TABLE_ADDRESS:
|
||||
case LOG_OF_HEAP_REGION_GRAIN_BYTES:
|
||||
case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
|
||||
@ -78,6 +79,9 @@ class MarkProcessor {
|
||||
case NARROW_KLASS_BASE_ADDRESS:
|
||||
vmSymbolName = binaryContainer.getNarrowKlassBaseAddressSymbolName();
|
||||
break;
|
||||
case NARROW_OOP_BASE_ADDRESS:
|
||||
vmSymbolName = binaryContainer.getNarrowOopBaseAddressSymbolName();
|
||||
break;
|
||||
case CRC_TABLE_ADDRESS:
|
||||
vmSymbolName = binaryContainer.getCrcTableAddressSymbolName();
|
||||
break;
|
||||
|
@ -1,332 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
import jdk.tools.jaotc.LogPrinter;
|
||||
import jdk.tools.jaotc.Main;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.*;
|
||||
|
||||
import static java.nio.file.FileVisitResult.CONTINUE;
|
||||
|
||||
public class ClassCollector {
|
||||
private final Main.Options options;
|
||||
private final LogPrinter log;
|
||||
|
||||
public ClassCollector(Main.Options options, LogPrinter log) {
|
||||
this.options = options;
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all class names passed by the user.
|
||||
*
|
||||
* @return array list of classes
|
||||
*/
|
||||
public Set<Class<?>> collectClassesToCompile() {
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
List<String> filesToScan = new LinkedList<>(options.files);
|
||||
|
||||
if (options.module != null) {
|
||||
classes.addAll(scanModule(filesToScan));
|
||||
}
|
||||
|
||||
classes.addAll(scanFiles(filesToScan));
|
||||
return classes;
|
||||
}
|
||||
|
||||
private Set<Class<?>> scanModule(List<String> filesToScan) {
|
||||
String module = options.module;
|
||||
// Search module in standard JDK installation.
|
||||
Path dir = getModuleDirectory(options.modulepath, module);
|
||||
|
||||
if (Files.isDirectory(dir)) {
|
||||
return loadFromModuleDirectory(dir);
|
||||
} else {
|
||||
findFilesToScan(filesToScan, module);
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Class<?>> loadFromModuleDirectory(Path dir) {
|
||||
log.printInfo("Scanning module: " + dir + " ...");
|
||||
log.printlnVerbose(" "); // Break line
|
||||
|
||||
FileSystemFinder finder = new FileSystemFinder(dir, pathname -> entryIsClassFile(pathname.toString()));
|
||||
Set<Class<?>> cls = loadWithClassLoader(() -> ClassLoader.getSystemClassLoader(), dir, finder);
|
||||
log.printlnInfo(" " + cls.size() + " classes loaded.");
|
||||
return cls;
|
||||
}
|
||||
|
||||
private void findFilesToScan(List<String> filesToScan, String module) {
|
||||
// Try to search regular directory, .jar or .class files
|
||||
Path path = Paths.get(options.modulepath, module);
|
||||
|
||||
if (Files.isDirectory(path)) {
|
||||
filesToScan.add(".");
|
||||
options.classpath = path.toString();
|
||||
} else if (path.endsWith(".jar") || path.endsWith(".class")) {
|
||||
filesToScan.add(path.toString());
|
||||
} else {
|
||||
path = Paths.get(options.modulepath, module + ".jar");
|
||||
if (Files.exists(path)) {
|
||||
filesToScan.add(path.toString());
|
||||
} else {
|
||||
path = Paths.get(options.modulepath, module + ".class");
|
||||
if (Files.exists(path)) {
|
||||
filesToScan.add(path.toString());
|
||||
} else {
|
||||
throw new InternalError("Expecting a .class, .jar or directory: " + path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean entryIsClassFile(String entry) {
|
||||
return entry.endsWith(".class") && !entry.endsWith("module-info.class");
|
||||
}
|
||||
|
||||
private Set<Class<?>> scanFiles(List<String> filesToScan) {
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
for (String fileName : filesToScan) {
|
||||
Set<Class<?>> loaded = scanFile(fileName);
|
||||
log.printlnInfo(" " + loaded.size() + " classes loaded.");
|
||||
classes.addAll(loaded);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
interface ClassLoaderFactory {
|
||||
ClassLoader create() throws IOException;
|
||||
}
|
||||
|
||||
private Set<Class<?>> loadWithClassLoader(ClassLoaderFactory factory, Path root, FileSystemFinder finder) {
|
||||
ClassLoader loader = null;
|
||||
try {
|
||||
loader = factory.create();
|
||||
return loadClassFiles(root, finder, loader);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
} finally {
|
||||
if (loader instanceof AutoCloseable) {
|
||||
try {
|
||||
((AutoCloseable) loader).close();
|
||||
} catch (Exception e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Class<?>> scanFile(String fileName) {
|
||||
log.printInfo("Scanning: " + fileName + " ...");
|
||||
log.printlnVerbose(" "); // Break line
|
||||
|
||||
if (fileName.endsWith(".jar")) {
|
||||
return loadFromJarFile(fileName);
|
||||
} else if (fileName.endsWith(".class")) {
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
loadFromClassFile(fileName, classes);
|
||||
return classes;
|
||||
} else {
|
||||
return scanClassPath(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Class<?>> loadFromJarFile(String fileName) {
|
||||
FileSystem fs = makeFileSystem(fileName);
|
||||
FileSystemFinder finder = new FileSystemFinder(fs.getPath("/"), pathname -> entryIsClassFile(pathname.toString()));
|
||||
return loadWithClassLoader(() -> URLClassLoader.newInstance(buildUrls(fileName)), fs.getPath("/"), finder);
|
||||
}
|
||||
|
||||
private void loadFromClassFile(String fileName, Set<Class<?>> classes) {
|
||||
Class<?> result;
|
||||
File file = new File(options.classpath);
|
||||
try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
|
||||
result = loadClassFile(loader, fileName);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
Class<?> c = result;
|
||||
addClass(classes, fileName, c);
|
||||
}
|
||||
|
||||
private Set<Class<?>> scanClassPath(String fileName) {
|
||||
Path classPath = Paths.get(options.classpath);
|
||||
if (!Files.exists(classPath)) {
|
||||
throw new InternalError("Path does not exist: " + classPath);
|
||||
}
|
||||
if (!Files.isDirectory(classPath)) {
|
||||
throw new InternalError("Path must be a directory: " + classPath);
|
||||
}
|
||||
|
||||
// Combine class path and file name and see what it is.
|
||||
Path combinedPath = Paths.get(options.classpath + File.separator + fileName);
|
||||
if (combinedPath.endsWith(".class")) {
|
||||
throw new InternalError("unimplemented");
|
||||
} else if (Files.isDirectory(combinedPath)) {
|
||||
return scanDirectory(classPath, combinedPath);
|
||||
} else {
|
||||
throw new InternalError("Expecting a .class, .jar or directory: " + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private FileSystem makeFileSystem(String fileName) {
|
||||
try {
|
||||
return FileSystems.newFileSystem(makeJarFileURI(fileName), new HashMap<>());
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private URI makeJarFileURI(String fileName) {
|
||||
try {
|
||||
return new URI("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/");
|
||||
} catch (URISyntaxException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private PathMatcher combine(PathMatcher m1, PathMatcher m2) {
|
||||
return path -> m1.matches(path) && m2.matches(path);
|
||||
}
|
||||
|
||||
private Set<Class<?>> scanDirectory(Path classPath, Path combinedPath) {
|
||||
String dir = options.classpath;
|
||||
|
||||
FileSystem fileSystem = FileSystems.getDefault();
|
||||
PathMatcher matcher = fileSystem.getPathMatcher("glob:" + "*.class");
|
||||
FileSystemFinder finder = new FileSystemFinder(combinedPath,
|
||||
combine(matcher, pathname -> entryIsClassFile(pathname.toString())));
|
||||
|
||||
File file = new File(dir);
|
||||
try (URLClassLoader loader = URLClassLoader.newInstance(buildUrls(file))) {
|
||||
return loadClassFiles(classPath, finder, loader);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Class<?>> loadClassFiles(Path root, FileSystemFinder finder, ClassLoader loader) {
|
||||
Set<Class<?>> classes = new HashSet<>();
|
||||
for (Path name : finder.done()) {
|
||||
// Now relativize to the class path so we get the actual class names.
|
||||
String entry = root.relativize(name).normalize().toString();
|
||||
Class<?> c = loadClassFile(loader, entry);
|
||||
addClass(classes, entry, c);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
private void addClass(Set<Class<?>> classes, String name, Class<?> c) {
|
||||
if (c != null) {
|
||||
classes.add(c);
|
||||
log.printlnVerbose(" loaded " + name);
|
||||
}
|
||||
}
|
||||
|
||||
private URL[] buildUrls(String fileName) throws MalformedURLException {
|
||||
return new URL[]{ new URL("jar:file:" + Paths.get(fileName).toAbsolutePath() + "!/") };
|
||||
}
|
||||
|
||||
private URL[] buildUrls(File file) throws MalformedURLException {
|
||||
return new URL[] {file.toURI().toURL() };
|
||||
}
|
||||
|
||||
private Path getModuleDirectory(String modulepath, String module) {
|
||||
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
|
||||
return fs.getPath(modulepath, module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a class with the given file name from the specified {@link URLClassLoader}.
|
||||
*/
|
||||
private Class<?> loadClassFile(final ClassLoader loader, final String fileName) {
|
||||
int start = 0;
|
||||
if (fileName.startsWith("/")) {
|
||||
start = 1;
|
||||
}
|
||||
String className = fileName.substring(start, fileName.length() - ".class".length());
|
||||
className = className.replace('/', '.');
|
||||
try {
|
||||
return loader.loadClass(className);
|
||||
} catch (Throwable e) {
|
||||
// If we are running in JCK mode we ignore all exceptions.
|
||||
if (options.ignoreClassLoadingErrors) {
|
||||
log.printError(className + ": " + e);
|
||||
return null;
|
||||
}
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FileVisitor} implementation to find class files recursively.
|
||||
*/
|
||||
private static class FileSystemFinder extends SimpleFileVisitor<Path> {
|
||||
private final ArrayList<Path> fileNames = new ArrayList<>();
|
||||
private final PathMatcher filter;
|
||||
|
||||
FileSystemFinder(Path combinedPath, PathMatcher filter) {
|
||||
this.filter = filter;
|
||||
try {
|
||||
Files.walkFileTree(combinedPath, this);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the glob pattern against the file name.
|
||||
*/
|
||||
void find(Path file) {
|
||||
Path name = file.getFileName();
|
||||
if (name != null && filter.matches(name)) {
|
||||
fileNames.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
List<Path> done() {
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
find(file);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
find(dir);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
import jdk.tools.jaotc.LoadedClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ClassSearch {
|
||||
private List<SourceProvider> providers = new ArrayList<>();
|
||||
|
||||
public void addProvider(SourceProvider provider) {
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
public List<LoadedClass> search(List<SearchFor> search, SearchPath searchPath) {
|
||||
List<LoadedClass> loaded = new ArrayList<>();
|
||||
|
||||
List<ClassSource> sources = new ArrayList<>();
|
||||
|
||||
for (SearchFor entry : search) {
|
||||
sources.add(findSource(entry, searchPath));
|
||||
}
|
||||
|
||||
for (ClassSource source : sources) {
|
||||
source.eachClass((name, loader) -> loaded.add(loadClass(name, loader)));
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
private LoadedClass loadClass(String name, ClassLoader loader) {
|
||||
try {
|
||||
Class<?> clzz = loader.loadClass(name);
|
||||
return new LoadedClass(name, clzz);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new InternalError("Failed to load with: " + loader, e);
|
||||
}
|
||||
}
|
||||
|
||||
private ClassSource findSource(SearchFor searchFor, SearchPath searchPath) {
|
||||
ClassSource found = null;
|
||||
|
||||
for (SourceProvider provider : providers) {
|
||||
if (!searchFor.isUnknown() && !provider.supports(searchFor.getType())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ClassSource source = provider.findSource(searchFor.getName(), searchPath);
|
||||
if (source != null) {
|
||||
if (found != null) {
|
||||
throw new InternalError("Multiple possible sources: " + source + " and: " + found);
|
||||
}
|
||||
found = source;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == null) {
|
||||
throw new InternalError("Failed to find: " + searchFor.toString());
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
public static List<SearchFor> makeList(String type, String argument) {
|
||||
List<SearchFor> list = new ArrayList<>();
|
||||
String[] elements = argument.split(":");
|
||||
for (String element : elements) {
|
||||
list.add(new SearchFor(element, type));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public interface ClassSource {
|
||||
static boolean pathIsClassFile(Path entry) {
|
||||
String fileName = entry.getFileName().toString();
|
||||
return fileName.endsWith(".class") && !fileName.endsWith("module-info.class");
|
||||
}
|
||||
|
||||
static String makeClassName(Path path) {
|
||||
String fileName = path.toString();
|
||||
|
||||
if (!fileName.endsWith(".class")) {
|
||||
throw new IllegalArgumentException("File doesn't end with .class: '" + fileName + "'");
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
if (fileName.startsWith("/")) {
|
||||
start = 1;
|
||||
}
|
||||
|
||||
String className = fileName.substring(start, fileName.length() - ".class".length());
|
||||
className = className.replace('/', '.');
|
||||
return className;
|
||||
}
|
||||
|
||||
void eachClass(BiConsumer<String, ClassLoader> consumer);
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class FileSupport {
|
||||
public boolean exists(Path path) {
|
||||
return Files.exists(path);
|
||||
}
|
||||
|
||||
public boolean isDirectory(Path path) {
|
||||
return Files.isDirectory(path);
|
||||
}
|
||||
|
||||
private FileSystem makeJarFileSystem(Path path) {
|
||||
try {
|
||||
return FileSystems.newFileSystem(makeJarFileURI(path), new HashMap<>());
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private URI makeJarFileURI(Path path) {
|
||||
try {
|
||||
return new URI("jar:file:" + path.toAbsolutePath() + "!/");
|
||||
} catch (URISyntaxException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader createClassLoader(Path path, ClassLoader parent) {
|
||||
try {
|
||||
return URLClassLoader.newInstance(buildUrls(path), parent);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ClassLoader createClassLoader(Path path) throws MalformedURLException {
|
||||
return URLClassLoader.newInstance(buildUrls(path));
|
||||
}
|
||||
|
||||
private URL[] buildUrls(Path path) throws MalformedURLException {
|
||||
return new URL[] { path.toUri().toURL() };
|
||||
}
|
||||
|
||||
public Path getJarFileSystemRoot(Path jarFile) {
|
||||
FileSystem fileSystem = makeJarFileSystem(jarFile);
|
||||
return fileSystem.getPath("/");
|
||||
}
|
||||
|
||||
public boolean isAbsolute(Path entry) {
|
||||
return entry.isAbsolute();
|
||||
}
|
||||
|
||||
public Path getSubDirectory(FileSystem fileSystem, Path root, Path path) throws IOException {
|
||||
DirectoryStream<Path> paths = fileSystem.provider().newDirectoryStream(root,null);
|
||||
for (Path entry : paths) {
|
||||
Path relative = root.relativize(entry);
|
||||
if (relative.equals(path)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static java.nio.file.FileVisitResult.CONTINUE;
|
||||
|
||||
/**
|
||||
* {@link FileVisitor} implementation to find class files recursively.
|
||||
*/
|
||||
public class FileSystemFinder extends SimpleFileVisitor<Path> implements Iterable<Path> {
|
||||
private final ArrayList<Path> fileNames = new ArrayList<>();
|
||||
private final PathMatcher filter;
|
||||
|
||||
public FileSystemFinder(Path combinedPath, PathMatcher filter) {
|
||||
this.filter = filter;
|
||||
try {
|
||||
Files.walkFileTree(combinedPath, this);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the glob pattern against the file name.
|
||||
*/
|
||||
private void find(Path file) {
|
||||
Path name = file.getFileName();
|
||||
if (name != null && filter.matches(name)) {
|
||||
fileNames.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
|
||||
find(file);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
|
||||
find(dir);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Iterator<Path> iterator() {
|
||||
return fileNames.iterator();
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
public class SearchFor {
|
||||
private final String name;
|
||||
private final String type;
|
||||
|
||||
public SearchFor(String name) {
|
||||
this(name, "unknown");
|
||||
}
|
||||
|
||||
public SearchFor(String name, String type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isUnknown() {
|
||||
return "unknown".equals(type);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + ":" + name;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SearchPath {
|
||||
private final List<Path> searchPaths = new ArrayList<>();
|
||||
private final FileSupport fileSupport;
|
||||
|
||||
public SearchPath() {
|
||||
this(new FileSupport());
|
||||
}
|
||||
|
||||
public SearchPath(FileSupport fileSupport) {
|
||||
this.fileSupport = fileSupport;
|
||||
}
|
||||
|
||||
public Path find(FileSystem fileSystem, Path entry, String... defaults) {
|
||||
if (isAbsolute(entry)) {
|
||||
if (exists(entry)) {
|
||||
return entry;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (exists(entry)) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
for (String searchPath : defaults) {
|
||||
Path newPath = fileSystem.getPath(searchPath, entry.toString());
|
||||
if (exists(newPath)) {
|
||||
return newPath;
|
||||
}
|
||||
}
|
||||
|
||||
for (Path searchPath : searchPaths) {
|
||||
Path newPath = fileSystem.getPath(searchPath.toString(), entry.toString());
|
||||
if (exists(newPath)) {
|
||||
return newPath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isAbsolute(Path entry) {
|
||||
return fileSupport.isAbsolute(entry);
|
||||
}
|
||||
|
||||
private boolean exists(Path entry) {
|
||||
return fileSupport.exists(entry);
|
||||
}
|
||||
|
||||
public void add(String... paths) {
|
||||
for (String name : paths) {
|
||||
Path path = Paths.get(name);
|
||||
searchPaths.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect;
|
||||
|
||||
public interface SourceProvider {
|
||||
ClassSource findSource(String name, SearchPath searchPath);
|
||||
|
||||
boolean supports(String type);
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.classname;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class ClassNameSource implements ClassSource {
|
||||
private final String name;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClassNameSource(String name, ClassLoader classLoader) {
|
||||
this.name = name;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eachClass(BiConsumer<String, ClassLoader> consumer) {
|
||||
consumer.accept(name, classLoader);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.classname;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSupport;
|
||||
import jdk.tools.jaotc.collect.SearchPath;
|
||||
import jdk.tools.jaotc.collect.SourceProvider;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class ClassNameSourceProvider implements SourceProvider {
|
||||
public final static String TYPE = "classname";
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClassNameSourceProvider(FileSupport fileSupport) {
|
||||
String classPath = System.getProperty("java.class.path");
|
||||
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
|
||||
if (classPath != null && !classPath.isEmpty()) {
|
||||
classLoader = systemClassLoader;
|
||||
} else {
|
||||
Path path = Paths.get(".").toAbsolutePath();
|
||||
classLoader = fileSupport.createClassLoader(path, systemClassLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassSource findSource(String name, SearchPath searchPath) {
|
||||
try {
|
||||
classLoader.loadClass(name);
|
||||
return new ClassNameSource(name, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String type) {
|
||||
return TYPE.equals(type);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.directory;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSystemFinder;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class DirectorySource implements ClassSource {
|
||||
private final Path directoryPath;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public DirectorySource(Path directoryPath, ClassLoader classLoader) {
|
||||
this.directoryPath = directoryPath;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eachClass(BiConsumer<String, ClassLoader> consumer) {
|
||||
FileSystemFinder finder = new FileSystemFinder(directoryPath, ClassSource::pathIsClassFile);
|
||||
|
||||
for (Path path : finder) {
|
||||
consumer.accept(ClassSource.makeClassName(directoryPath.relativize(path).normalize()), classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "directory:" + directoryPath.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.directory;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSupport;
|
||||
import jdk.tools.jaotc.collect.SearchPath;
|
||||
import jdk.tools.jaotc.collect.SourceProvider;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class DirectorySourceProvider implements SourceProvider {
|
||||
private final FileSupport fileSupport;
|
||||
private final FileSystem fileSystem;
|
||||
public final static String TYPE = "directory";
|
||||
|
||||
public DirectorySourceProvider(FileSupport fileSupport) {
|
||||
this.fileSupport = fileSupport;
|
||||
fileSystem = FileSystems.getDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassSource findSource(String name, SearchPath searchPath) {
|
||||
Path directoryPath = fileSystem.getPath(name);
|
||||
|
||||
if (!fileSupport.exists(directoryPath)) {
|
||||
return null;
|
||||
}
|
||||
if (!fileSupport.isDirectory(directoryPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
ClassLoader classLoader = fileSupport.createClassLoader(directoryPath);
|
||||
return new DirectorySource(directoryPath, classLoader);
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String type) {
|
||||
return TYPE.equals(type);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.jar;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSystemFinder;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class JarFileSource implements ClassSource {
|
||||
private final Path jarFile;
|
||||
private final Path jarRootPath;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
|
||||
public JarFileSource(Path jarFile, Path jarRootPath, ClassLoader classLoader) {
|
||||
this.jarFile = jarFile;
|
||||
this.jarRootPath = jarRootPath;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public void eachClass(BiConsumer<String, ClassLoader> consumer) {
|
||||
FileSystemFinder finder = new FileSystemFinder(jarRootPath, ClassSource::pathIsClassFile);
|
||||
|
||||
for (Path path : finder) {
|
||||
consumer.accept(ClassSource.makeClassName(jarRootPath.relativize(path).normalize()), classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "jar:" + jarFile.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.jar;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSupport;
|
||||
import jdk.tools.jaotc.collect.SearchPath;
|
||||
import jdk.tools.jaotc.collect.SourceProvider;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.ProviderNotFoundException;
|
||||
|
||||
public class JarSourceProvider implements SourceProvider {
|
||||
private final FileSystem fileSystem;
|
||||
private final FileSupport fileSupport;
|
||||
public final static String TYPE = "jar";
|
||||
|
||||
public JarSourceProvider() {
|
||||
this(new FileSupport());
|
||||
}
|
||||
|
||||
public JarSourceProvider(FileSupport fileSupport) {
|
||||
this.fileSupport = fileSupport;
|
||||
fileSystem = FileSystems.getDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassSource findSource(String name, SearchPath searchPath) {
|
||||
Path fileName = fileSystem.getPath(name);
|
||||
Path jarFile = searchPath.find(fileSystem, fileName);
|
||||
|
||||
if (!validPath(jarFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createSource(jarFile);
|
||||
}
|
||||
|
||||
private ClassSource createSource(Path jarFile) {
|
||||
try {
|
||||
Path jarRootPath = fileSupport.getJarFileSystemRoot(jarFile);
|
||||
if (jarRootPath == null) {
|
||||
return null;
|
||||
}
|
||||
ClassLoader classLoader = fileSupport.createClassLoader(jarFile);
|
||||
return new JarFileSource(jarFile, jarRootPath, classLoader);
|
||||
} catch (ProviderNotFoundException | MalformedURLException e) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String type) {
|
||||
return TYPE.equals(type);
|
||||
}
|
||||
|
||||
private boolean validPath(Path jarFile) {
|
||||
return jarFile != null && !fileSupport.isDirectory(jarFile);
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.module;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSystemFinder;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class ModuleSource implements ClassSource {
|
||||
private final Path modulePath;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ModuleSource(Path modulePath, ClassLoader classLoader) {
|
||||
this.modulePath = modulePath;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eachClass(BiConsumer<String, ClassLoader> consumer) {
|
||||
FileSystemFinder finder = new FileSystemFinder(modulePath, ClassSource::pathIsClassFile);
|
||||
|
||||
for (Path path : finder) {
|
||||
consumer.accept(ClassSource.makeClassName(modulePath.relativize(path).normalize()), classLoader);
|
||||
}
|
||||
}
|
||||
|
||||
public Path getModulePath() {
|
||||
return modulePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "module:" + modulePath.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.tools.jaotc.collect.module;
|
||||
|
||||
import jdk.tools.jaotc.collect.ClassSource;
|
||||
import jdk.tools.jaotc.collect.FileSupport;
|
||||
import jdk.tools.jaotc.collect.SearchPath;
|
||||
import jdk.tools.jaotc.collect.SourceProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class ModuleSourceProvider implements SourceProvider {
|
||||
private final FileSystem fileSystem;
|
||||
private final ClassLoader classLoader;
|
||||
private final FileSupport fileSupport;
|
||||
public final static String TYPE = "module";
|
||||
|
||||
public ModuleSourceProvider() {
|
||||
this(FileSystems.getFileSystem(URI.create("jrt:/")), ClassLoader.getSystemClassLoader(), new FileSupport());
|
||||
}
|
||||
|
||||
public ModuleSourceProvider(FileSystem fileSystem, ClassLoader classLoader, FileSupport fileSupport) {
|
||||
this.fileSystem = fileSystem;
|
||||
this.classLoader = classLoader;
|
||||
this.fileSupport = fileSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassSource findSource(String name, SearchPath searchPath) {
|
||||
Path path = fileSystem.getPath(name);
|
||||
Path dir = fileSystem.getPath("modules");
|
||||
|
||||
if (dir == null || !fileSupport.isDirectory(dir)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Path found = findModuleDirectory(dir, path);
|
||||
|
||||
if (found == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ModuleSource(found, classLoader);
|
||||
}
|
||||
|
||||
private Path findModuleDirectory(Path root, Path path) {
|
||||
try {
|
||||
return fileSupport.getSubDirectory(fileSystem, root, path);
|
||||
} catch (IOException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(String type) {
|
||||
return TYPE.equals(type);
|
||||
}
|
||||
}
|
@ -100,15 +100,19 @@ final class CompilerToVM {
|
||||
native long getExceptionTableStart(HotSpotResolvedJavaMethodImpl method);
|
||||
|
||||
/**
|
||||
* Determines if {@code method} can be inlined. A method may not be inlinable for a number of
|
||||
* reasons such as:
|
||||
* <ul>
|
||||
* <li>a CompileOracle directive may prevent inlining or compilation of methods</li>
|
||||
* <li>the method may have a bytecode breakpoint set</li>
|
||||
* <li>the method may have other bytecode features that require special handling by the VM</li>
|
||||
* </ul>
|
||||
* Determines whether {@code method} is currently compilable by the JVMCI compiler being used by
|
||||
* the VM. This can return false if JVMCI compilation failed earlier for {@code method}, a
|
||||
* breakpoint is currently set in {@code method} or {@code method} contains other bytecode
|
||||
* features that require special handling by the VM.
|
||||
*/
|
||||
native boolean canInlineMethod(HotSpotResolvedJavaMethodImpl method);
|
||||
native boolean isCompilable(HotSpotResolvedJavaMethodImpl method);
|
||||
|
||||
/**
|
||||
* Determines if {@code method} is targeted by a VM directive (e.g.,
|
||||
* {@code -XX:CompileCommand=dontinline,<pattern>}) or annotation (e.g.,
|
||||
* {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
|
||||
*/
|
||||
native boolean hasNeverInlineDirective(HotSpotResolvedJavaMethodImpl method);
|
||||
|
||||
/**
|
||||
* Determines if {@code method} should be inlined at any cost. This could be because:
|
||||
|
@ -49,13 +49,6 @@ public interface HotSpotResolvedJavaMethod extends ResolvedJavaMethod {
|
||||
*/
|
||||
boolean isForceInline();
|
||||
|
||||
/**
|
||||
* Returns true if this method has a {@code DontInline} annotation.
|
||||
*
|
||||
* @return true if DontInline annotation present, false otherwise
|
||||
*/
|
||||
boolean isDontInline();
|
||||
|
||||
/**
|
||||
* Returns true if this method has a {@code ReservedStackAccess} annotation.
|
||||
*
|
||||
|
@ -298,15 +298,6 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
||||
return (getFlags() & config().methodFlagsForceInline) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this method has a {@code DontInline} annotation.
|
||||
*
|
||||
* @return true if DontInline annotation present, false otherwise
|
||||
*/
|
||||
public boolean isDontInline() {
|
||||
return (getFlags() & config().methodFlagsDontInline) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this method has a {@code ReservedStackAccess} annotation.
|
||||
*
|
||||
@ -582,10 +573,15 @@ final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSp
|
||||
|
||||
@Override
|
||||
public boolean canBeInlined() {
|
||||
if (isDontInline()) {
|
||||
if (hasNeverInlineDirective()) {
|
||||
return false;
|
||||
}
|
||||
return compilerToVM().canInlineMethod(this);
|
||||
return compilerToVM().isCompilable(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNeverInlineDirective() {
|
||||
return compilerToVM().hasNeverInlineDirective(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -346,6 +346,13 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
|
||||
*/
|
||||
boolean canBeInlined();
|
||||
|
||||
/**
|
||||
* Determines if this method is targeted by a VM directive (e.g.,
|
||||
* {@code -XX:CompileCommand=dontinline,<pattern>}) or VM recognized annotation (e.g.,
|
||||
* {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
|
||||
*/
|
||||
boolean hasNeverInlineDirective();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the inlining of this method should be forced.
|
||||
*/
|
||||
|
@ -638,6 +638,7 @@ suite = {
|
||||
"annotationProcessors" : [
|
||||
"GRAAL_NODEINFO_PROCESSOR",
|
||||
"GRAAL_REPLACEMENTS_VERIFIER",
|
||||
"GRAAL_OPTIONS_PROCESSOR",
|
||||
],
|
||||
"workingSets" : "Graal,Graph",
|
||||
},
|
||||
|
@ -116,6 +116,7 @@ public class Debug {
|
||||
public static final int INFO_LOG_LEVEL = 2;
|
||||
public static final int VERBOSE_LOG_LEVEL = 3;
|
||||
public static final int DETAILED_LOG_LEVEL = 4;
|
||||
public static final int VERY_DETAILED_LOG_LEVEL = 5;
|
||||
|
||||
public static boolean isDumpEnabled(int dumpLevel) {
|
||||
return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel);
|
||||
|
@ -267,10 +267,15 @@ public class AMD64HotSpotBackend extends HotSpotHostBackend {
|
||||
|
||||
if (config.useCompressedClassPointers) {
|
||||
Register register = r10;
|
||||
AMD64HotSpotMove.decodeKlassPointer(asm, register, providers.getRegisters().getHeapBaseRegister(), src, config.getKlassEncoding());
|
||||
if (config.narrowKlassBase != 0) {
|
||||
// The heap base register was destroyed above, so restore it
|
||||
asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
|
||||
AMD64HotSpotMove.decodeKlassPointer(crb, asm, register, providers.getRegisters().getHeapBaseRegister(), src, config);
|
||||
if (GeneratePIC.getValue()) {
|
||||
asm.movq(providers.getRegisters().getHeapBaseRegister(), asm.getPlaceholder(-1));
|
||||
crb.recordMark(config.MARKID_NARROW_OOP_BASE_ADDRESS);
|
||||
} else {
|
||||
if (config.narrowKlassBase != 0) {
|
||||
// The heap base register was destroyed above, so restore it
|
||||
asm.movq(providers.getRegisters().getHeapBaseRegister(), config.narrowOopBase);
|
||||
}
|
||||
}
|
||||
asm.cmpq(inlineCacheKlass, register);
|
||||
} else {
|
||||
|
@ -265,14 +265,21 @@ public class AMD64HotSpotMove {
|
||||
}
|
||||
}
|
||||
|
||||
public static void decodeKlassPointer(AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, CompressEncoding encoding) {
|
||||
public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) {
|
||||
CompressEncoding encoding = config.getKlassEncoding();
|
||||
masm.movl(register, address);
|
||||
if (encoding.shift != 0) {
|
||||
assert encoding.alignment == encoding.shift : "Decode algorithm is wrong";
|
||||
masm.shlq(register, encoding.alignment);
|
||||
}
|
||||
if (encoding.base != 0) {
|
||||
masm.movq(scratch, encoding.base);
|
||||
if (GeneratePIC.getValue() || encoding.base != 0) {
|
||||
if (GeneratePIC.getValue()) {
|
||||
masm.movq(scratch, masm.getPlaceholder(-1));
|
||||
crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
|
||||
} else {
|
||||
assert encoding.base != 0;
|
||||
masm.movq(scratch, encoding.base);
|
||||
}
|
||||
masm.addq(register, scratch);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot;
|
||||
|
||||
import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
|
||||
|
||||
public class AOTGraalHotSpotVMConfig extends GraalHotSpotVMConfig {
|
||||
private final CompressEncoding aotOopEncoding;
|
||||
private final CompressEncoding aotKlassEncoding;
|
||||
|
||||
public AOTGraalHotSpotVMConfig(HotSpotVMConfigStore store) {
|
||||
super(store);
|
||||
// In AOT, force the shift to be always equal to alignment therefore avoiding zero-shift.
|
||||
CompressEncoding vmOopEncoding = super.getOopEncoding();
|
||||
aotOopEncoding = new CompressEncoding(vmOopEncoding.base, vmOopEncoding.alignment, vmOopEncoding.alignment);
|
||||
CompressEncoding vmKlassEncoding = super.getKlassEncoding();
|
||||
aotKlassEncoding = new CompressEncoding(vmKlassEncoding.base, vmKlassEncoding.alignment, vmKlassEncoding.alignment);
|
||||
assert check();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompressEncoding getOopEncoding() {
|
||||
return aotOopEncoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompressEncoding getKlassEncoding() {
|
||||
return aotKlassEncoding;
|
||||
}
|
||||
}
|
@ -479,7 +479,6 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
public final int methodCompiledEntryOffset = getFieldOffset("Method::_from_compiled_entry", Integer.class, "address");
|
||||
public final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, isJDK8 ? "nmethod*" : "CompiledMethod*");
|
||||
|
||||
public final int methodFlagsJfrTowrite = getConstant("Method::_jfr_towrite", Integer.class);
|
||||
public final int methodFlagsCallerSensitive = getConstant("Method::_caller_sensitive", Integer.class);
|
||||
public final int methodFlagsForceInline = getConstant("Method::_force_inline", Integer.class);
|
||||
public final int methodFlagsDontInline = getConstant("Method::_dont_inline", Integer.class);
|
||||
@ -773,13 +772,14 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
public final int MARKID_HEAP_TOP_ADDRESS = getConstant("CodeInstaller::HEAP_TOP_ADDRESS", Integer.class, 17);
|
||||
public final int MARKID_HEAP_END_ADDRESS = getConstant("CodeInstaller::HEAP_END_ADDRESS", Integer.class, 18);
|
||||
public final int MARKID_NARROW_KLASS_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_KLASS_BASE_ADDRESS", Integer.class, 19);
|
||||
public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 20);
|
||||
public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 21);
|
||||
public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 22);
|
||||
public final int MARKID_NARROW_OOP_BASE_ADDRESS = getConstant("CodeInstaller::NARROW_OOP_BASE_ADDRESS", Integer.class, 20);
|
||||
public final int MARKID_CRC_TABLE_ADDRESS = getConstant("CodeInstaller::CRC_TABLE_ADDRESS", Integer.class, 21);
|
||||
public final int MARKID_LOG_OF_HEAP_REGION_GRAIN_BYTES = getConstant("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES", Integer.class, 22);
|
||||
public final int MARKID_INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED = getConstant("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED", Integer.class, 23);
|
||||
|
||||
// Checkstyle: resume
|
||||
|
||||
private boolean check() {
|
||||
protected boolean check() {
|
||||
for (Field f : getClass().getDeclaredFields()) {
|
||||
int modifiers = f.getModifiers();
|
||||
if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.debug.GraalDebugConfig.areScopedGlobalMetricsEnabled;
|
||||
import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugValueSummary;
|
||||
import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump;
|
||||
@ -99,7 +100,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
|
||||
HotSpotGraalRuntime(HotSpotJVMCIRuntime jvmciRuntime, CompilerConfigurationFactory compilerConfigurationFactory) {
|
||||
|
||||
HotSpotVMConfigStore store = jvmciRuntime.getConfigStore();
|
||||
config = new GraalHotSpotVMConfig(store);
|
||||
config = GeneratePIC.getValue() ? new AOTGraalHotSpotVMConfig(store) : new GraalHotSpotVMConfig(store);
|
||||
CompileTheWorldOptions.overrideWithNativeOptions(config);
|
||||
|
||||
// Only set HotSpotPrintInlining if it still has its default value (false).
|
||||
|
@ -22,7 +22,6 @@
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.meta;
|
||||
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider.FieldReadEnabledInImmutableCode;
|
||||
|
||||
@ -112,11 +111,6 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (GeneratePIC.getValue()) {
|
||||
if (field.isSynthetic() && field.getName().startsWith("$assertionsDisabled")) {
|
||||
return tryReadField(b, field, null);
|
||||
}
|
||||
}
|
||||
if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1738,9 +1738,8 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
} else {
|
||||
// Intrinsic was not applied: remove intrinsic guard
|
||||
// and restore the original receiver node in the arguments array
|
||||
for (Node node : graph.getNewNodes(intrinsicGuard.mark)) {
|
||||
GraphUtil.killCFG(node);
|
||||
}
|
||||
intrinsicGuard.lastInstr.setNext(null);
|
||||
GraphUtil.removeNewNodes(graph, intrinsicGuard.mark);
|
||||
lastInstr = intrinsicGuard.lastInstr;
|
||||
args[0] = intrinsicGuard.receiver;
|
||||
}
|
||||
|
@ -153,9 +153,7 @@ public class SimplifyingGraphDecoder extends GraphDecoder {
|
||||
}
|
||||
|
||||
for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) {
|
||||
if (!(node instanceof FixedNode) && node.hasNoUsages()) {
|
||||
GraphUtil.killCFG(node);
|
||||
}
|
||||
GraphUtil.tryKillUnused(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,7 +506,7 @@ public class StructuredGraph extends Graph implements JavaMethodContext {
|
||||
for (Node successor : snapshot) {
|
||||
if (successor != null && successor.isAlive()) {
|
||||
if (successor != survivingSuccessor) {
|
||||
GraphUtil.killCFG(successor, tool);
|
||||
GraphUtil.killCFG((FixedNode) successor, tool);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -566,6 +566,9 @@ public class StructuredGraph extends Graph implements JavaMethodContext {
|
||||
reduceTrivialMerge(begin);
|
||||
} else { // convert to merge
|
||||
AbstractMergeNode merge = this.add(new MergeNode());
|
||||
for (EndNode end : begin.forwardEnds()) {
|
||||
merge.addForwardEnd(end);
|
||||
}
|
||||
this.replaceFixedWithFixed(begin, merge);
|
||||
}
|
||||
}
|
||||
@ -576,7 +579,14 @@ public class StructuredGraph extends Graph implements JavaMethodContext {
|
||||
for (PhiNode phi : merge.phis().snapshot()) {
|
||||
assert phi.valueCount() == 1;
|
||||
ValueNode singleValue = phi.valueAt(0);
|
||||
phi.replaceAtUsagesAndDelete(singleValue);
|
||||
if (phi.hasUsages()) {
|
||||
phi.replaceAtUsagesAndDelete(singleValue);
|
||||
} else {
|
||||
phi.safeDelete();
|
||||
if (singleValue != null) {
|
||||
GraphUtil.tryKillUnused(singleValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
// remove loop exits
|
||||
if (merge instanceof LoopBeginNode) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -22,18 +22,30 @@
|
||||
*/
|
||||
package org.graalvm.compiler.nodes.util;
|
||||
|
||||
import static org.graalvm.compiler.graph.Graph.Options.VerifyGraalGraphEdges;
|
||||
import static org.graalvm.compiler.nodes.util.GraphUtil.Options.VerifyKillCFGUnusedNodes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.graalvm.compiler.bytecode.Bytecode;
|
||||
import org.graalvm.compiler.code.SourceStackTraceBailoutException;
|
||||
import org.graalvm.compiler.core.common.CollectionsFactory;
|
||||
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.debug.Debug;
|
||||
import org.graalvm.compiler.graph.Graph;
|
||||
import org.graalvm.compiler.graph.Node;
|
||||
import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.graph.NodeWorkList;
|
||||
import org.graalvm.compiler.graph.Position;
|
||||
import org.graalvm.compiler.graph.iterators.NodeIterable;
|
||||
import org.graalvm.compiler.graph.spi.SimplifierTool;
|
||||
import org.graalvm.compiler.nodeinfo.InputType;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.nodes.AbstractBeginNode;
|
||||
import org.graalvm.compiler.nodes.AbstractEndNode;
|
||||
import org.graalvm.compiler.nodes.AbstractMergeNode;
|
||||
@ -48,11 +60,15 @@ import org.graalvm.compiler.nodes.ProxyNode;
|
||||
import org.graalvm.compiler.nodes.StateSplit;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.calc.FloatingNode;
|
||||
import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
|
||||
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
|
||||
import org.graalvm.compiler.nodes.spi.LimitedValueProxy;
|
||||
import org.graalvm.compiler.nodes.spi.LoweringProvider;
|
||||
import org.graalvm.compiler.nodes.spi.ValueProxy;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValue;
|
||||
|
||||
import jdk.vm.ci.code.BailoutException;
|
||||
import jdk.vm.ci.code.BytecodePosition;
|
||||
@ -64,22 +80,78 @@ import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class GraphUtil {
|
||||
|
||||
public static void killCFG(Node node, SimplifierTool tool) {
|
||||
NodeWorkList worklist = killCFG(node, tool, null);
|
||||
if (worklist != null) {
|
||||
for (Node successor : worklist) {
|
||||
killCFG(successor, tool, worklist);
|
||||
public static class Options {
|
||||
@Option(help = "Verify that there are no new unused nodes when performing killCFG", type = OptionType.Debug)//
|
||||
public static final OptionValue<Boolean> VerifyKillCFGUnusedNodes = new OptionValue<>(false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
public static void killCFG(FixedNode node, SimplifierTool tool) {
|
||||
try (Debug.Scope scope = Debug.scope("KillCFG", node)) {
|
||||
Set<Node> unusedNodes = null;
|
||||
Set<Node> unsafeNodes = null;
|
||||
Graph.NodeEventScope nodeEventScope = null;
|
||||
if (VerifyGraalGraphEdges.getValue()) {
|
||||
unsafeNodes = collectUnsafeNodes(node.graph());
|
||||
}
|
||||
if (VerifyKillCFGUnusedNodes.getValue()) {
|
||||
Set<Node> collectedUnusedNodes = unusedNodes = CollectionsFactory.newSet();
|
||||
nodeEventScope = node.graph().trackNodeEvents(new Graph.NodeEventListener() {
|
||||
@Override
|
||||
public void event(Graph.NodeEvent e, Node n) {
|
||||
if (e == Graph.NodeEvent.ZERO_USAGES && isFloatingNode(n)) {
|
||||
collectedUnusedNodes.add(n);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "Before killCFG %s", node);
|
||||
NodeWorkList worklist = killCFG(node, tool, null);
|
||||
if (worklist != null) {
|
||||
for (Node n : worklist) {
|
||||
killCFG(n, tool, worklist);
|
||||
}
|
||||
}
|
||||
if (VerifyGraalGraphEdges.getValue()) {
|
||||
Set<Node> newUnsafeNodes = collectUnsafeNodes(node.graph());
|
||||
newUnsafeNodes.removeAll(unsafeNodes);
|
||||
assert newUnsafeNodes.isEmpty() : "New unsafe nodes: " + newUnsafeNodes;
|
||||
}
|
||||
if (VerifyKillCFGUnusedNodes.getValue()) {
|
||||
nodeEventScope.close();
|
||||
unusedNodes.removeIf(n -> n.isDeleted());
|
||||
assert unusedNodes.isEmpty() : "New unused nodes: " + unusedNodes;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw Debug.handle(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all node in the graph which have non-optional inputs that are null.
|
||||
*/
|
||||
private static Set<Node> collectUnsafeNodes(Graph graph) {
|
||||
Set<Node> unsafeNodes = CollectionsFactory.newSet();
|
||||
for (Node n : graph.getNodes()) {
|
||||
for (Position pos : n.inputPositions()) {
|
||||
Node input = pos.get(n);
|
||||
if (input == null) {
|
||||
if (!pos.isInputOptional()) {
|
||||
unsafeNodes.add(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return unsafeNodes;
|
||||
}
|
||||
|
||||
private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) {
|
||||
NodeWorkList newWorklist = worklist;
|
||||
// DebugScope.forceDump(node.graph(), "kill CFG %s", node);
|
||||
if (node instanceof FixedNode) {
|
||||
newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool);
|
||||
} else {
|
||||
propagateKill(node);
|
||||
newWorklist = propagateKill(node, newWorklist);
|
||||
Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "killCFG (Floating) %s", node);
|
||||
}
|
||||
return newWorklist;
|
||||
}
|
||||
@ -93,19 +165,20 @@ public class GraphUtil {
|
||||
if (current instanceof AbstractEndNode) {
|
||||
// We reached a control flow end.
|
||||
AbstractEndNode end = (AbstractEndNode) current;
|
||||
killEnd(end, tool);
|
||||
newWorklist = killEnd(end, newWorklist, tool);
|
||||
} else if (current instanceof FixedWithNextNode) {
|
||||
next = ((FixedWithNextNode) current).next();
|
||||
// Node guaranteed to have a single successor
|
||||
FixedWithNextNode fixedWithNext = (FixedWithNextNode) current;
|
||||
assert fixedWithNext.successors().count() == 1 || fixedWithNext.successors().count() == 0;
|
||||
assert fixedWithNext.successors().first() == fixedWithNext.next();
|
||||
next = fixedWithNext.next();
|
||||
} else {
|
||||
// Normal control flow node.
|
||||
/*
|
||||
* We do not take a successor snapshot because this iterator supports concurrent
|
||||
* modifications as long as they do not change the size of the successor list. Not
|
||||
* taking a snapshot allows us to see modifications to other branches that may
|
||||
* happen while processing one branch.
|
||||
*/
|
||||
// assert node.successors().count() > 1 || node.successors().count() == 0 :
|
||||
// node.getClass();
|
||||
Iterator<Node> successors = current.successors().iterator();
|
||||
if (successors.hasNext()) {
|
||||
Node first = successors.next();
|
||||
@ -126,100 +199,158 @@ public class GraphUtil {
|
||||
}
|
||||
}
|
||||
current.replaceAtPredecessor(null);
|
||||
propagateKill(current);
|
||||
newWorklist = propagateKill(current, newWorklist);
|
||||
Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, current.graph(), "killCFGLinear %s", current);
|
||||
current = next;
|
||||
}
|
||||
Debug.dump(Debug.DETAILED_LOG_LEVEL, in.graph(), "killCFGLinear %s", in);
|
||||
return newWorklist;
|
||||
}
|
||||
|
||||
public static void killCFG(Node node) {
|
||||
public static void killCFG(FixedNode node) {
|
||||
killCFG(node, null);
|
||||
}
|
||||
|
||||
private static void killEnd(AbstractEndNode end, SimplifierTool tool) {
|
||||
/**
|
||||
* Node type used temporarily while deleting loops.
|
||||
*
|
||||
* It is used as replacement for the loop {@link PhiNode PhiNodes} in order to break data-flow
|
||||
* cycles before deleting the loop. The control-flow of the whole loop is killed before killing
|
||||
* the poison node if they are still alive.
|
||||
*/
|
||||
@NodeInfo(allowedUsageTypes = InputType.Unchecked)
|
||||
private static final class PoisonNode extends FloatingNode {
|
||||
public static final NodeClass<PoisonNode> TYPE = NodeClass.create(PoisonNode.class);
|
||||
|
||||
protected PoisonNode() {
|
||||
super(TYPE, StampFactory.forVoid());
|
||||
}
|
||||
}
|
||||
|
||||
private static NodeWorkList killEnd(AbstractEndNode end, NodeWorkList worklist, SimplifierTool tool) {
|
||||
NodeWorkList newWorklist = worklist;
|
||||
AbstractMergeNode merge = end.merge();
|
||||
if (merge != null) {
|
||||
merge.removeEnd(end);
|
||||
StructuredGraph graph = end.graph();
|
||||
if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) {
|
||||
// dead loop
|
||||
for (PhiNode phi : merge.phis().snapshot()) {
|
||||
propagateKill(phi);
|
||||
}
|
||||
LoopBeginNode begin = (LoopBeginNode) merge;
|
||||
// disconnect and delete loop ends & loop exits
|
||||
for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
|
||||
loopend.predecessor().replaceFirstSuccessor(loopend, null);
|
||||
loopend.safeDelete();
|
||||
}
|
||||
begin.removeExits();
|
||||
FixedNode loopBody = begin.next();
|
||||
if (loopBody != null) { // for small infinite loops, the body may be killed while
|
||||
// killing the loop ends
|
||||
killCFG(loopBody);
|
||||
// clean unused proxies to avoid creating new unused nodes
|
||||
for (LoopExitNode exit : begin.loopExits()) {
|
||||
for (ProxyNode vpn : exit.proxies().snapshot()) {
|
||||
tryKillUnused(vpn);
|
||||
}
|
||||
}
|
||||
begin.removeExits();
|
||||
PoisonNode poison = null;
|
||||
if (merge.phis().isNotEmpty()) {
|
||||
poison = graph.unique(new PoisonNode());
|
||||
for (PhiNode phi : merge.phis()) {
|
||||
phi.replaceAtUsages(poison);
|
||||
}
|
||||
for (PhiNode phi : merge.phis().snapshot()) {
|
||||
killWithUnusedFloatingInputs(phi);
|
||||
}
|
||||
}
|
||||
FixedNode loopBody = begin.next();
|
||||
Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, end.graph(), "killEnd (Loop) %s after initial loop cleanup", end);
|
||||
if (loopBody != null) {
|
||||
// for small infinite loops, the body may already be killed while killing the
|
||||
// LoopEnds
|
||||
newWorklist = killCFG(loopBody, tool, worklist);
|
||||
}
|
||||
FrameState frameState = begin.stateAfter();
|
||||
begin.safeDelete();
|
||||
if (frameState != null) {
|
||||
tryKillUnused(frameState);
|
||||
}
|
||||
if (poison != null && poison.isAlive()) {
|
||||
if (newWorklist == null) {
|
||||
newWorklist = graph.createNodeWorkList();
|
||||
}
|
||||
// drain the worklist to finish the loop before adding the poison
|
||||
for (Node n : newWorklist) {
|
||||
killCFG(n, tool, newWorklist);
|
||||
}
|
||||
if (poison.isAlive()) {
|
||||
newWorklist.add(poison);
|
||||
}
|
||||
}
|
||||
} else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
|
||||
// not a loop anymore
|
||||
if (tool != null) {
|
||||
merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
|
||||
for (PhiNode phi : merge.phis()) {
|
||||
tool.addToWorkList(phi.usages());
|
||||
}
|
||||
}
|
||||
graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
|
||||
} else if (merge.phiPredecessorCount() == 1) {
|
||||
// not a merge anymore
|
||||
if (tool != null) {
|
||||
merge.phis().forEach(phi -> tool.addToWorkList(phi.usages()));
|
||||
for (PhiNode phi : merge.phis()) {
|
||||
tool.addToWorkList(phi.usages());
|
||||
}
|
||||
}
|
||||
graph.reduceTrivialMerge(merge);
|
||||
}
|
||||
}
|
||||
return newWorklist;
|
||||
}
|
||||
|
||||
public static boolean isFloatingNode(Node n) {
|
||||
return !(n instanceof FixedNode);
|
||||
}
|
||||
|
||||
private static void propagateKill(Node node) {
|
||||
private static NodeWorkList propagateKill(Node node, NodeWorkList workList) {
|
||||
NodeWorkList newWorkList = workList;
|
||||
if (node != null && node.isAlive()) {
|
||||
node.markDeleted();
|
||||
|
||||
for (Node in : node.inputs()) {
|
||||
if (in.isAlive()) {
|
||||
in.removeUsage(node);
|
||||
if (in.hasNoUsages() && !(in instanceof FixedNode)) {
|
||||
killWithUnusedFloatingInputs(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<Node> usageToKill = null;
|
||||
for (Node usage : node.usages()) {
|
||||
if (usage.isAlive() && !(usage instanceof FixedNode)) {
|
||||
if (usageToKill == null) {
|
||||
usageToKill = new ArrayList<>();
|
||||
}
|
||||
usageToKill.add(usage);
|
||||
}
|
||||
}
|
||||
if (usageToKill != null) {
|
||||
for (Node usage : usageToKill) {
|
||||
if (usage.isAlive()) {
|
||||
if (usage instanceof PhiNode) {
|
||||
PhiNode phiNode = (PhiNode) usage;
|
||||
usage.replaceFirstInput(node, null);
|
||||
if (phiNode.merge() == null || !phiNode.hasValidInput()) {
|
||||
propagateKill(usage);
|
||||
}
|
||||
for (Node usage : node.usages().snapshot()) {
|
||||
assert usage.isAlive();
|
||||
if (isFloatingNode(usage)) {
|
||||
boolean addUsage = false;
|
||||
if (usage instanceof PhiNode) {
|
||||
PhiNode phi = (PhiNode) usage;
|
||||
assert phi.merge() != null;
|
||||
if (phi.merge() == node) {
|
||||
// we reach the phi directly through he merge, queue it.
|
||||
addUsage = true;
|
||||
} else {
|
||||
propagateKill(usage);
|
||||
// we reach it though a value
|
||||
assert phi.values().contains(node);
|
||||
// let that be handled when we reach the corresponding End node
|
||||
}
|
||||
} else {
|
||||
addUsage = true;
|
||||
}
|
||||
if (addUsage) {
|
||||
if (newWorkList == null) {
|
||||
newWorkList = node.graph().createNodeWorkList();
|
||||
}
|
||||
newWorkList.add(usage);
|
||||
}
|
||||
}
|
||||
usage.replaceFirstInput(node, null);
|
||||
}
|
||||
killWithUnusedFloatingInputs(node);
|
||||
}
|
||||
return newWorkList;
|
||||
}
|
||||
|
||||
private static boolean checkKill(Node node) {
|
||||
node.assertTrue(node.isAlive(), "must be alive");
|
||||
node.assertTrue(node.hasNoUsages(), "cannot kill node %s because of usages: %s", node, node.usages());
|
||||
node.assertTrue(node.predecessor() == null, "cannot kill node %s because of predecessor: %s", node, node.predecessor());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void killWithUnusedFloatingInputs(Node node) {
|
||||
assert checkKill(node);
|
||||
node.markDeleted();
|
||||
outer: for (Node in : node.inputs()) {
|
||||
if (in.isAlive()) {
|
||||
@ -227,7 +358,7 @@ public class GraphUtil {
|
||||
if (in.hasNoUsages()) {
|
||||
node.maybeNotifyZeroUsages(in);
|
||||
}
|
||||
if (!(in instanceof FixedNode)) {
|
||||
if (isFloatingNode(in)) {
|
||||
if (in.hasNoUsages()) {
|
||||
killWithUnusedFloatingInputs(in);
|
||||
} else if (in instanceof PhiNode) {
|
||||
@ -244,6 +375,35 @@ public class GraphUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all nodes created after the {@code mark}, assuming no "old" nodes point to "new"
|
||||
* nodes.
|
||||
*/
|
||||
public static void removeNewNodes(Graph graph, Graph.Mark mark) {
|
||||
assert checkNoOldToNewEdges(graph, mark);
|
||||
for (Node n : graph.getNewNodes(mark)) {
|
||||
n.markDeleted();
|
||||
for (Node in : n.inputs()) {
|
||||
in.removeUsage(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkNoOldToNewEdges(Graph graph, Graph.Mark mark) {
|
||||
for (Node old : graph.getNodes()) {
|
||||
if (graph.isNew(mark, old)) {
|
||||
break;
|
||||
}
|
||||
for (Node n : old.successors()) {
|
||||
assert !graph.isNew(mark, n) : old + " -> " + n;
|
||||
}
|
||||
for (Node n : old.inputs()) {
|
||||
assert !graph.isNew(mark, n) : old + " -> " + n;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void removeFixedWithUnusedInputs(FixedWithNextNode fixed) {
|
||||
if (fixed instanceof StateSplit) {
|
||||
FrameState stateAfter = ((StateSplit) fixed).stateAfter();
|
||||
@ -688,8 +848,9 @@ public class GraphUtil {
|
||||
|
||||
@Override
|
||||
public void deleteBranch(Node branch) {
|
||||
branch.predecessor().replaceFirstSuccessor(branch, null);
|
||||
GraphUtil.killCFG(branch, this);
|
||||
FixedNode fixedBranch = (FixedNode) branch;
|
||||
fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
|
||||
GraphUtil.killCFG(fixedBranch, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -444,8 +444,9 @@ public class CanonicalizerPhase extends BasePhase<PhaseContext> {
|
||||
|
||||
@Override
|
||||
public void deleteBranch(Node branch) {
|
||||
branch.predecessor().replaceFirstSuccessor(branch, null);
|
||||
GraphUtil.killCFG(branch, this);
|
||||
FixedNode fixedBranch = (FixedNode) branch;
|
||||
fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null);
|
||||
GraphUtil.killCFG(fixedBranch, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -632,7 +632,6 @@ void os::Aix::signal_sets_init() {
|
||||
sigaddset(&unblocked_sigs, SIGBUS);
|
||||
sigaddset(&unblocked_sigs, SIGFPE);
|
||||
sigaddset(&unblocked_sigs, SIGTRAP);
|
||||
sigaddset(&unblocked_sigs, SIGDANGER);
|
||||
sigaddset(&unblocked_sigs, SR_signum);
|
||||
|
||||
if (!ReduceSignalUsage) {
|
||||
@ -1553,6 +1552,8 @@ void os::print_signal_handlers(outputStream* st, char* buf, size_t buflen) {
|
||||
print_signal_handler(st, SHUTDOWN3_SIGNAL , buf, buflen);
|
||||
print_signal_handler(st, BREAK_SIGNAL, buf, buflen);
|
||||
print_signal_handler(st, SIGTRAP, buf, buflen);
|
||||
// We also want to know if someone else adds a SIGDANGER handler because
|
||||
// that will interfere with OOM killling.
|
||||
print_signal_handler(st, SIGDANGER, buf, buflen);
|
||||
}
|
||||
|
||||
@ -3156,7 +3157,6 @@ void os::Aix::install_signal_handlers() {
|
||||
set_signal_handler(SIGFPE, true);
|
||||
set_signal_handler(SIGTRAP, true);
|
||||
set_signal_handler(SIGXFSZ, true);
|
||||
set_signal_handler(SIGDANGER, true);
|
||||
|
||||
if (libjsig_is_loaded) {
|
||||
// Tell libjsig jvm finishes setting signal handlers.
|
||||
@ -3273,7 +3273,6 @@ void os::run_periodic_checks() {
|
||||
if (UseSIGTRAP) {
|
||||
DO_SIGNAL_CHECK(SIGTRAP);
|
||||
}
|
||||
DO_SIGNAL_CHECK(SIGDANGER);
|
||||
|
||||
// ReduceSignalUsage allows the user to override these handlers
|
||||
// see comments at the very top and jvm_solaris.h
|
||||
|
@ -778,6 +778,11 @@ void os::set_native_thread_name(const char *name) {
|
||||
// is already attached to a debugger; debugger must observe
|
||||
// the exception below to show the correct name.
|
||||
|
||||
// If there is no debugger attached skip raising the exception
|
||||
if (!IsDebuggerPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
struct {
|
||||
DWORD dwType; // must be 0x1000
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016 SAP SE. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -258,13 +258,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
}
|
||||
}
|
||||
|
||||
// Handle SIGDANGER right away. AIX would raise SIGDANGER whenever available swap
|
||||
// space falls below 30%. This is only a chance for the process to gracefully abort.
|
||||
// We can't hope to proceed after SIGDANGER since SIGKILL tailgates.
|
||||
if (sig == SIGDANGER) {
|
||||
goto report_and_die;
|
||||
}
|
||||
|
||||
if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) {
|
||||
goto run_chained_handler;
|
||||
}
|
||||
|
@ -87,6 +87,7 @@
|
||||
#define SPELL_REG_FP "rbp"
|
||||
#else
|
||||
#define REG_FP 29
|
||||
#define REG_LR 30
|
||||
|
||||
#define SPELL_REG_SP "sp"
|
||||
#define SPELL_REG_FP "x29"
|
||||
@ -182,6 +183,46 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
return frame(sp, fp, epc.pc());
|
||||
}
|
||||
|
||||
bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
|
||||
address pc = (address) os::Linux::ucontext_get_pc(uc);
|
||||
if (Interpreter::contains(pc)) {
|
||||
// interpreter performs stack banging after the fixed frame header has
|
||||
// been generated while the compilers perform it before. To maintain
|
||||
// semantic consistency between interpreted and compiled frames, the
|
||||
// method returns the Java sender of the current frame.
|
||||
*fr = os::fetch_frame_from_context(uc);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// more complex code with compiled code
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling
|
||||
return false;
|
||||
} else {
|
||||
// In compiled code, the stack banging is performed before LR
|
||||
// has been saved in the frame. LR is live, and SP and FP
|
||||
// belong to the caller.
|
||||
intptr_t* fp = os::Linux::ucontext_get_fp(uc);
|
||||
intptr_t* sp = os::Linux::ucontext_get_sp(uc);
|
||||
address pc = (address)(uc->uc_mcontext.regs[REG_LR]
|
||||
- NativeInstruction::instruction_size);
|
||||
*fr = frame(sp, fp, pc);
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
assert(!fr->is_first_frame(), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
// By default, gcc always saves frame pointer rfp on this stack. This
|
||||
// may get turned off by -fomit-frame-pointer.
|
||||
frame os::get_sender_for_C_frame(frame* fr) {
|
||||
@ -313,6 +354,24 @@ JVM_handle_linux_signal(int sig,
|
||||
if (thread->in_stack_yellow_reserved_zone(addr)) {
|
||||
thread->disable_stack_yellow_reserved_zone();
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
if (thread->in_stack_reserved_zone(addr)) {
|
||||
frame fr;
|
||||
if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be a Java frame");
|
||||
frame activation =
|
||||
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
if (activation.sp() != NULL) {
|
||||
thread->disable_stack_reserved_zone();
|
||||
if (activation.is_interpreted_frame()) {
|
||||
thread->set_reserved_stack_activation((address)(
|
||||
activation.fp() + frame::interpreter_frame_initial_sp_offset));
|
||||
} else {
|
||||
thread->set_reserved_stack_activation((address)activation.unextended_sp());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw a stack overflow exception. Guard pages will be reenabled
|
||||
// while unwinding the stack.
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
|
||||
|
@ -144,6 +144,42 @@ frame os::fetch_frame_from_context(const void* ucVoid) {
|
||||
return frame(sp, epc.pc());
|
||||
}
|
||||
|
||||
bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
|
||||
address pc = (address) os::Linux::ucontext_get_pc(uc);
|
||||
if (Interpreter::contains(pc)) {
|
||||
// Interpreter performs stack banging after the fixed frame header has
|
||||
// been generated while the compilers perform it before. To maintain
|
||||
// semantic consistency between interpreted and compiled frames, the
|
||||
// method returns the Java sender of the current frame.
|
||||
*fr = os::fetch_frame_from_context(uc);
|
||||
if (!fr->is_first_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
} else {
|
||||
// More complex code with compiled code.
|
||||
assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
|
||||
CodeBlob* cb = CodeCache::find_blob(pc);
|
||||
if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
|
||||
// Not sure where the pc points to, fallback to default
|
||||
// stack overflow handling. In compiled code, we bang before
|
||||
// the frame is complete.
|
||||
return false;
|
||||
} else {
|
||||
intptr_t* fp = os::Linux::ucontext_get_fp(uc);
|
||||
intptr_t* sp = os::Linux::ucontext_get_sp(uc);
|
||||
*fr = frame(sp, (address)*sp);
|
||||
if (!fr->is_java_frame()) {
|
||||
assert(fr->safe_for_sender(thread), "Safety check");
|
||||
assert(!fr->is_first_frame(), "Safety check");
|
||||
*fr = fr->java_sender();
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(fr->is_java_frame(), "Safety check");
|
||||
return true;
|
||||
}
|
||||
|
||||
frame os::get_sender_for_C_frame(frame* fr) {
|
||||
if (*fr->sp() == 0) {
|
||||
// fr is the last C frame.
|
||||
@ -279,13 +315,31 @@ JVM_handle_linux_signal(int sig,
|
||||
if (thread->on_local_stack(addr)) {
|
||||
// stack overflow
|
||||
if (thread->in_stack_yellow_reserved_zone(addr)) {
|
||||
thread->disable_stack_yellow_reserved_zone();
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
if (thread->in_stack_reserved_zone(addr)) {
|
||||
frame fr;
|
||||
if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
|
||||
assert(fr.is_java_frame(), "Must be a Javac frame");
|
||||
frame activation =
|
||||
SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
|
||||
if (activation.sp() != NULL) {
|
||||
thread->disable_stack_reserved_zone();
|
||||
if (activation.is_interpreted_frame()) {
|
||||
thread->set_reserved_stack_activation((address)activation.fp());
|
||||
} else {
|
||||
thread->set_reserved_stack_activation((address)activation.unextended_sp());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Throw a stack overflow exception.
|
||||
// Guard pages will be reenabled while unwinding the stack.
|
||||
thread->disable_stack_yellow_reserved_zone();
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
|
||||
} else {
|
||||
// Thread was in the vm or native code. Return and try to finish.
|
||||
thread->disable_stack_yellow_reserved_zone();
|
||||
return 1;
|
||||
}
|
||||
} else if (thread->in_stack_red_zone(addr)) {
|
||||
|
@ -89,7 +89,10 @@
|
||||
// Minimum usable stack sizes required to get to user code. Space for
|
||||
// HotSpot guard pages is added later.
|
||||
#ifdef _LP64
|
||||
size_t os::Posix::_compiler_thread_min_stack_allowed = 202 * K;
|
||||
// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler
|
||||
// threads requires a large stack with the Solaris Studio C++ compiler version 5.13
|
||||
// and product VM builds (debug builds require significantly less stack space).
|
||||
size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K;
|
||||
size_t os::Posix::_java_thread_min_stack_allowed = 48 * K;
|
||||
size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K;
|
||||
#else
|
||||
|
@ -650,6 +650,7 @@ bool InstructForm::is_wide_memory_kill(FormDict &globals) const {
|
||||
if( strcmp(_matrule->_opType,"MemBarReleaseLock") == 0 ) return true;
|
||||
if( strcmp(_matrule->_opType,"MemBarAcquireLock") == 0 ) return true;
|
||||
if( strcmp(_matrule->_opType,"MemBarStoreStore") == 0 ) return true;
|
||||
if( strcmp(_matrule->_opType,"MemBarVolatile") == 0 ) return true;
|
||||
if( strcmp(_matrule->_opType,"StoreFence") == 0 ) return true;
|
||||
if( strcmp(_matrule->_opType,"LoadFence") == 0 ) return true;
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "aot/aotCodeHeap.hpp"
|
||||
#include "aot/aotLoader.hpp"
|
||||
#include "classfile/javaAssertions.hpp"
|
||||
#include "gc/g1/heapRegion.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "interpreter/abstractInterpreter.hpp"
|
||||
@ -294,6 +295,8 @@ void AOTCodeHeap::publish_aot(const methodHandle& mh, AOTMethodData* method_data
|
||||
// When the AOT compiler compiles something big we fail to generate metadata
|
||||
// in CodeInstaller::gather_metadata. In that case the scopes_pcs_begin == scopes_pcs_end.
|
||||
// In all successful cases we always have 2 entries of scope pcs.
|
||||
log_info(aot, class, resolve)("Failed to load %s (no metadata available)", mh->name_and_sig_as_C_string());
|
||||
_code_to_aot[code_id]._state = invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -536,6 +539,7 @@ void AOTCodeHeap::link_global_lib_symbols() {
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_heap_end_address", address, (heap->supports_inline_contig_alloc() ? heap->end_addr() : NULL));
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base());
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes);
|
||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc());
|
||||
link_shared_runtime_symbols();
|
||||
@ -706,6 +710,12 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_lib->config()->_omitAssertions && JavaAssertions::enabled(kh->name()->as_C_string(), kh->class_loader() == NULL)) {
|
||||
log_trace(aot, class, load)("class %s in %s does not have java assertions in compiled code, but assertions are enabled for this execution.", kh->internal_name(), _lib->name());
|
||||
sweep_dependent_methods(klass_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
NOT_PRODUCT( aot_klasses_found++; )
|
||||
|
||||
log_trace(aot, class, load)("found %s in %s for classloader %p tid=" INTPTR_FORMAT, kh->internal_name(), _lib->name(), kh->class_loader_data(), p2i(thread));
|
||||
@ -714,7 +724,7 @@ bool AOTCodeHeap::load_klass_data(instanceKlassHandle kh, Thread* thread) {
|
||||
// Set klass's Resolve (second) got cell.
|
||||
_metaspace_got[klass_data->_got_index] = kh();
|
||||
|
||||
// Initialize global symbols of the DSO to the correspondingVM symbol values.
|
||||
// Initialize global symbols of the DSO to the corresponding VM symbol values.
|
||||
link_global_lib_symbols();
|
||||
|
||||
int methods_offset = klass_data->_compiled_methods_offset;
|
||||
|
@ -88,7 +88,7 @@ typedef struct {
|
||||
} AOTHeader;
|
||||
|
||||
typedef struct {
|
||||
enum { CONFIG_SIZE = 11 + 7 * 4 };
|
||||
enum { CONFIG_SIZE = 12 + 7 * 4 };
|
||||
int _config_size;
|
||||
int _narrowOopShift;
|
||||
int _narrowKlassShift;
|
||||
@ -108,6 +108,7 @@ typedef struct {
|
||||
bool _tieredAOT;
|
||||
bool _enableContended;
|
||||
bool _restrictContended;
|
||||
bool _omitAssertions;
|
||||
} AOTConfiguration;
|
||||
|
||||
class AOTLib : public CHeapObj<mtCode> {
|
||||
|
@ -3298,7 +3298,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
|
||||
// for osr compile, bailout if some requirements are not fulfilled
|
||||
if (osr_bci != -1) {
|
||||
BlockBegin* osr_block = blm.bci2block()->at(osr_bci);
|
||||
assert(osr_block->is_set(BlockBegin::was_visited_flag),"osr entry must have been visited for osr compile");
|
||||
if (!osr_block->is_set(BlockBegin::was_visited_flag)) {
|
||||
BAILOUT("osr entry must have been visited for osr compile");
|
||||
}
|
||||
|
||||
// check if osr entry point has empty stack - we cannot handle non-empty stacks at osr entry points
|
||||
if (!osr_block->state()->stack_is_empty()) {
|
||||
|
@ -895,8 +895,32 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
|
||||
ciMethod* target = s.get_method(ignored_will_link, &declared_signature);
|
||||
ciKlass* holder = s.get_declared_method_holder();
|
||||
assert(declared_signature != NULL, "cannot be null");
|
||||
// Push appendix argument, if one.
|
||||
if (s.has_appendix()) {
|
||||
// If the current bytecode has an attached appendix argument,
|
||||
// push an unknown object to represent that argument. (Analysis
|
||||
// of dynamic call sites, especially invokehandle calls, needs
|
||||
// the appendix argument on the stack, in addition to "regular" arguments
|
||||
// pushed onto the stack by bytecode instructions preceding the call.)
|
||||
//
|
||||
// The escape analyzer does _not_ use the ciBytecodeStream::has_appendix(s)
|
||||
// method to determine whether the current bytecode has an appendix argument.
|
||||
// The has_appendix() method obtains the appendix from the
|
||||
// ConstantPoolCacheEntry::_f1 field, which can happen concurrently with
|
||||
// resolution of dynamic call sites. Callees in the
|
||||
// ciBytecodeStream::get_method() call above also access the _f1 field;
|
||||
// interleaving the get_method() and has_appendix() calls in the current
|
||||
// method with call site resolution can lead to an inconsistent view of
|
||||
// the current method's argument count. In particular, some interleaving(s)
|
||||
// can cause the method's argument count to not include the appendix, which
|
||||
// then leads to stack over-/underflow in the escape analyzer.
|
||||
//
|
||||
// Instead of pushing the argument if has_appendix() is true, the escape analyzer
|
||||
// pushes an appendix for all call sites targeted by invokedynamic and invokehandle
|
||||
// instructions, except if the call site is the _invokeBasic intrinsic
|
||||
// (that intrinsic is always targeted by an invokehandle instruction but does
|
||||
// not have an appendix argument).
|
||||
if (target->is_loaded() &&
|
||||
Bytecodes::has_optional_appendix(s.cur_bc_raw()) &&
|
||||
target->intrinsic_id() != vmIntrinsics::_invokeBasic) {
|
||||
state.apush(unknown_obj);
|
||||
}
|
||||
// Pass in raw bytecode because we need to see invokehandle instructions.
|
||||
|
@ -136,15 +136,19 @@ class ciMethod : public ciMetadata {
|
||||
check_is_loaded();
|
||||
return _signature->size() + (_flags.is_static() ? 0 : 1);
|
||||
}
|
||||
// Report the number of elements on stack when invoking this method.
|
||||
// This is different than the regular arg_size because invokedynamic
|
||||
// has an implicit receiver.
|
||||
// Report the number of elements on stack when invoking the current method.
|
||||
// If the method is loaded, arg_size() gives precise information about the
|
||||
// number of stack elements (using the method's signature and its flags).
|
||||
// However, if the method is not loaded, the number of stack elements must
|
||||
// be determined differently, as the method's flags are not yet available.
|
||||
// The invoke_arg_size() method assumes in that case that all bytecodes except
|
||||
// invokestatic and invokedynamic have a receiver that is also pushed onto the
|
||||
// stack by the caller of the current method.
|
||||
int invoke_arg_size(Bytecodes::Code code) const {
|
||||
if (is_loaded()) {
|
||||
return arg_size();
|
||||
} else {
|
||||
int arg_size = _signature->size();
|
||||
// Add a receiver argument, maybe:
|
||||
if (code != Bytecodes::_invokestatic &&
|
||||
code != Bytecodes::_invokedynamic) {
|
||||
arg_size++;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -364,7 +364,12 @@ u1* ClassPathZipEntry::open_versioned_entry(const char* name, jint* filesize, TR
|
||||
if (verstr != NULL) {
|
||||
version = atoi(verstr);
|
||||
if (version < base_version || version > cur_ver) {
|
||||
is_multi_ver = false;
|
||||
// If the specified version is lower than the base version, the base
|
||||
// entry will be used; if the version is higher than the current
|
||||
// jdk version, the highest versioned entry will be used.
|
||||
if (version < base_version) {
|
||||
is_multi_ver = false;
|
||||
}
|
||||
// print out warning, do not use assertion here since it will continue to look
|
||||
// for proper version.
|
||||
warning("JDK%d is not supported in multiple version jars", version);
|
||||
|
@ -94,7 +94,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen
|
||||
_metaspace(NULL), _unloading(false), _klasses(NULL),
|
||||
_modules(NULL), _packages(NULL),
|
||||
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
|
||||
_next(NULL), _dependencies(dependencies), _shared_class_loader_id(-1),
|
||||
_next(NULL), _dependencies(dependencies),
|
||||
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
|
||||
Monitor::_safepoint_check_never)) {
|
||||
TRACE_INIT_ID(this);
|
||||
|
@ -204,9 +204,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
// Support for walking class loader data objects
|
||||
ClassLoaderData* _next; /// Next loader_datas created
|
||||
|
||||
// CDS
|
||||
int _shared_class_loader_id;
|
||||
|
||||
// ReadOnly and ReadWrite metaspaces (static because only on the null
|
||||
// class loader for now).
|
||||
static Metaspace* _ro_metaspace;
|
||||
@ -338,15 +335,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
Metaspace* rw_metaspace();
|
||||
void initialize_shared_metaspaces();
|
||||
|
||||
int shared_class_loader_id() const {
|
||||
return _shared_class_loader_id;
|
||||
}
|
||||
void set_shared_class_loader_id(int id) {
|
||||
assert(id >= 0, "sanity");
|
||||
assert(_shared_class_loader_id <0, "cannot be assigned more than once");
|
||||
_shared_class_loader_id = id;
|
||||
}
|
||||
|
||||
TRACE_DEFINE_TRACE_ID_METHODS;
|
||||
};
|
||||
|
||||
|
@ -163,8 +163,8 @@ void java_lang_String::compute_offsets() {
|
||||
|
||||
Klass* k = SystemDictionary::String_klass();
|
||||
compute_offset(value_offset, k, vmSymbols::value_name(), vmSymbols::byte_array_signature());
|
||||
compute_optional_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature());
|
||||
compute_optional_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature());
|
||||
compute_offset(hash_offset, k, vmSymbols::hash_name(), vmSymbols::int_signature());
|
||||
compute_offset(coder_offset, k, vmSymbols::coder_name(), vmSymbols::byte_signature());
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
@ -3977,12 +3977,8 @@ void JavaClasses::check_offsets() {
|
||||
// java.lang.String
|
||||
|
||||
CHECK_OFFSET("java/lang/String", java_lang_String, value, "[B");
|
||||
if (java_lang_String::has_hash_field()) {
|
||||
CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
|
||||
}
|
||||
if (java_lang_String::has_coder_field()) {
|
||||
CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
|
||||
}
|
||||
CHECK_OFFSET("java/lang/String", java_lang_String, hash, "I");
|
||||
CHECK_OFFSET("java/lang/String", java_lang_String, coder, "B");
|
||||
|
||||
// java.lang.Class
|
||||
|
||||
|
@ -81,15 +81,6 @@ class java_lang_String : AllStatic {
|
||||
static Handle create_from_platform_dependent_str(const char* str, TRAPS);
|
||||
static Handle char_converter(Handle java_string, jchar from_char, jchar to_char, TRAPS);
|
||||
|
||||
static bool has_hash_field() {
|
||||
assert(initialized, "Must be initialized");
|
||||
return (hash_offset > 0);
|
||||
}
|
||||
static bool has_coder_field() {
|
||||
assert(initialized, "Must be initialized");
|
||||
return (coder_offset > 0);
|
||||
}
|
||||
|
||||
static void set_compact_strings(bool value);
|
||||
|
||||
static int value_offset_in_bytes() {
|
||||
|
@ -30,10 +30,8 @@
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
|
||||
void java_lang_String::set_coder(oop string, jbyte coder) {
|
||||
assert(initialized, "Must be initialized");
|
||||
if (coder_offset > 0) {
|
||||
string->byte_field_put(coder_offset, coder);
|
||||
}
|
||||
assert(initialized && (coder_offset > 0), "Must be initialized");
|
||||
string->byte_field_put(coder_offset, coder);
|
||||
}
|
||||
|
||||
void java_lang_String::set_value_raw(oop string, typeArrayOop buffer) {
|
||||
@ -61,15 +59,11 @@ unsigned int java_lang_String::hash(oop java_string) {
|
||||
return java_string->int_field(hash_offset);
|
||||
}
|
||||
bool java_lang_String::is_latin1(oop java_string) {
|
||||
assert(initialized, "Must be initialized");
|
||||
assert(initialized && (coder_offset > 0), "Must be initialized");
|
||||
assert(is_instance(java_string), "must be java_string");
|
||||
if (coder_offset > 0) {
|
||||
jbyte coder = java_string->byte_field(coder_offset);
|
||||
assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings");
|
||||
return coder == CODER_LATIN1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
jbyte coder = java_string->byte_field(coder_offset);
|
||||
assert(CompactStrings || coder == CODER_UTF16, "Must be UTF16 without CompactStrings");
|
||||
return coder == CODER_LATIN1;
|
||||
}
|
||||
int java_lang_String::length(oop java_string) {
|
||||
assert(initialized, "Must be initialized");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -39,8 +39,6 @@
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/javaCalls.hpp"
|
||||
@ -48,17 +46,17 @@
|
||||
#include "utilities/stringUtils.hpp"
|
||||
#include "utilities/utf8.hpp"
|
||||
|
||||
static bool verify_module_name(char *module_name) {
|
||||
static bool verify_module_name(const char *module_name) {
|
||||
if (module_name == NULL) return false;
|
||||
int len = (int)strlen(module_name);
|
||||
return (len > 0 && len <= Symbol::max_length());
|
||||
}
|
||||
|
||||
bool Modules::verify_package_name(char *package_name) {
|
||||
bool Modules::verify_package_name(const char* package_name) {
|
||||
if (package_name == NULL) return false;
|
||||
int len = (int)strlen(package_name);
|
||||
return (len > 0 && len <= Symbol::max_length() &&
|
||||
UTF8::is_legal_utf8((unsigned char *)package_name, len, false) &&
|
||||
UTF8::is_legal_utf8((const unsigned char *)package_name, len, false) &&
|
||||
ClassFileParser::verify_unqualified_name(package_name, len,
|
||||
ClassFileParser::LegalClass));
|
||||
}
|
||||
@ -107,10 +105,8 @@ static ModuleEntry* get_module_entry(jobject module, TRAPS) {
|
||||
return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL);
|
||||
}
|
||||
|
||||
static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, TRAPS) {
|
||||
static PackageEntry* get_package_entry(ModuleEntry* module_entry, const char* package_name, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
if (package == NULL) return NULL;
|
||||
const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
|
||||
if (package_name == NULL) return NULL;
|
||||
TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL);
|
||||
PackageEntryTable* package_entry_table = module_entry->loader_data()->packages();
|
||||
@ -139,7 +135,8 @@ bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) {
|
||||
}
|
||||
|
||||
static void define_javabase_module(jobject module, jstring version,
|
||||
jstring location, jobjectArray packages, TRAPS) {
|
||||
jstring location, const char* const* packages,
|
||||
jsize num_packages, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
Handle module_handle(THREAD, JNIHandles::resolve(module));
|
||||
@ -164,21 +161,12 @@ static void define_javabase_module(jobject module, jstring version,
|
||||
}
|
||||
}
|
||||
|
||||
objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
|
||||
objArrayHandle packages_h(THREAD, packages_oop);
|
||||
int num_packages = (packages_h == NULL ? 0 : packages_h->length());
|
||||
|
||||
// Check that the list of packages has no duplicates and that the
|
||||
// packages are syntactically ok.
|
||||
GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages);
|
||||
for (int x = 0; x < num_packages; x++) {
|
||||
oop string_obj = packages_h->obj_at(x);
|
||||
|
||||
if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
"Bad package name for module: " JAVA_BASE_NAME);
|
||||
}
|
||||
char *package_name = java_lang_String::as_utf8_string(string_obj);
|
||||
const char *package_name = packages[x];
|
||||
if (!Modules::verify_package_name(package_name)) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Invalid package name: %s for module: " JAVA_BASE_NAME, package_name));
|
||||
@ -239,7 +227,7 @@ static void define_javabase_module(jobject module, jstring version,
|
||||
}
|
||||
}
|
||||
if (duplicate_javabase) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
THROW_MSG(vmSymbols::java_lang_InternalError(),
|
||||
"Module " JAVA_BASE_NAME " is already defined");
|
||||
}
|
||||
|
||||
@ -262,13 +250,39 @@ static void define_javabase_module(jobject module, jstring version,
|
||||
}
|
||||
}
|
||||
|
||||
// Caller needs ResourceMark.
|
||||
void throw_dup_pkg_exception(const char* module_name, PackageEntry* package, TRAPS) {
|
||||
const char* package_name = package->name()->as_C_string();
|
||||
if (package->module()->is_named()) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
|
||||
err_msg("Package %s for module %s is already in another module, %s, defined to the class loader",
|
||||
package_name, module_name, package->module()->name()->as_C_string()));
|
||||
} else {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
|
||||
err_msg("Package %s for module %s is already in the unnamed module defined to the class loader",
|
||||
package_name, module_name));
|
||||
}
|
||||
}
|
||||
|
||||
void Modules::define_module(jobject module, jstring version,
|
||||
jstring location, jobjectArray packages, TRAPS) {
|
||||
jstring location, const char* const* packages,
|
||||
jsize num_packages, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
if (module == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object");
|
||||
}
|
||||
|
||||
if (num_packages < 0) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
"num_packages must be >= 0");
|
||||
}
|
||||
|
||||
if (packages == NULL && num_packages > 0) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
"num_packages should be zero if packages is null");
|
||||
}
|
||||
|
||||
Handle module_handle(THREAD, JNIHandles::resolve(module));
|
||||
if (!java_lang_reflect_Module::is_instance(module_handle())) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
@ -283,7 +297,7 @@ void Modules::define_module(jobject module, jstring version,
|
||||
|
||||
// Special handling of java.base definition
|
||||
if (strcmp(module_name, JAVA_BASE_NAME) == 0) {
|
||||
define_javabase_module(module, version, location, packages, CHECK);
|
||||
define_javabase_module(module, version, location, packages, num_packages, CHECK);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -297,21 +311,11 @@ void Modules::define_module(jobject module, jstring version,
|
||||
}
|
||||
Handle h_loader = Handle(THREAD, loader);
|
||||
|
||||
objArrayOop packages_oop = objArrayOop(JNIHandles::resolve(packages));
|
||||
objArrayHandle packages_h(THREAD, packages_oop);
|
||||
int num_packages = (packages_h == NULL ? 0 : packages_h->length());
|
||||
|
||||
// Check that the list of packages has no duplicates and that the
|
||||
// packages are syntactically ok.
|
||||
GrowableArray<Symbol*>* pkg_list = new GrowableArray<Symbol*>(num_packages);
|
||||
for (int x = 0; x < num_packages; x++) {
|
||||
oop string_obj = packages_h->obj_at(x);
|
||||
|
||||
if (string_obj == NULL || !string_obj->is_a(SystemDictionary::String_klass())) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Bad package name for module: %s", module_name));
|
||||
}
|
||||
char *package_name = java_lang_String::as_utf8_string(string_obj);
|
||||
const char* package_name = packages[x];
|
||||
if (!verify_package_name(package_name)) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Invalid package name: %s for module: %s",
|
||||
@ -323,12 +327,15 @@ void Modules::define_module(jobject module, jstring version,
|
||||
!SystemDictionary::is_platform_class_loader(h_loader) &&
|
||||
strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
|
||||
const char* class_loader_name = SystemDictionary::loader_name(h_loader());
|
||||
StringUtils::replace_no_expand(package_name, "/", ".");
|
||||
size_t pkg_len = strlen(package_name);
|
||||
char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
|
||||
strncpy(pkg_name, package_name, pkg_len);
|
||||
StringUtils::replace_no_expand(pkg_name, "/", ".");
|
||||
const char* msg_text1 = "Class loader (instance of): ";
|
||||
const char* msg_text2 = " tried to define prohibited package name: ";
|
||||
size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
|
||||
size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1;
|
||||
char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
|
||||
jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
|
||||
jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
|
||||
}
|
||||
|
||||
@ -347,7 +354,6 @@ void Modules::define_module(jobject module, jstring version,
|
||||
// Create symbol* entry for module name.
|
||||
TempNewSymbol module_symbol = SymbolTable::new_symbol(module_name, CHECK);
|
||||
|
||||
int dupl_pkg_index = -1;
|
||||
bool dupl_modules = false;
|
||||
|
||||
// Create symbol* entry for module version.
|
||||
@ -373,6 +379,7 @@ void Modules::define_module(jobject module, jstring version,
|
||||
assert(loader_data != NULL, "class loader data shouldn't be null");
|
||||
|
||||
PackageEntryTable* package_table = NULL;
|
||||
PackageEntry* existing_pkg = NULL;
|
||||
{
|
||||
MutexLocker ml(Module_lock, THREAD);
|
||||
|
||||
@ -382,13 +389,12 @@ void Modules::define_module(jobject module, jstring version,
|
||||
|
||||
// Check that none of the packages exist in the class loader's package table.
|
||||
for (int x = 0; x < pkg_list->length(); x++) {
|
||||
if (package_table->lookup_only(pkg_list->at(x)) != NULL) {
|
||||
existing_pkg = package_table->lookup_only(pkg_list->at(x));
|
||||
if (existing_pkg != NULL) {
|
||||
// This could be because the module was already defined. If so,
|
||||
// report that error instead of the package error.
|
||||
if (module_table->lookup_only(module_symbol) != NULL) {
|
||||
dupl_modules = true;
|
||||
} else {
|
||||
dupl_pkg_index = x;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -396,9 +402,8 @@ void Modules::define_module(jobject module, jstring version,
|
||||
} // if (num_packages > 0)...
|
||||
|
||||
// Add the module and its packages.
|
||||
if (!dupl_modules && dupl_pkg_index == -1) {
|
||||
if (!dupl_modules && existing_pkg == NULL) {
|
||||
// Create the entry for this module in the class loader's module entry table.
|
||||
|
||||
ModuleEntry* module_entry = module_table->locked_create_entry_or_null(module_handle, module_symbol,
|
||||
version_symbol, location_symbol, loader_data);
|
||||
|
||||
@ -426,13 +431,10 @@ void Modules::define_module(jobject module, jstring version,
|
||||
|
||||
// any errors ?
|
||||
if (dupl_modules) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
|
||||
err_msg("Module %s is already defined", module_name));
|
||||
}
|
||||
if (dupl_pkg_index != -1) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Package %s for module %s already exists for class loader",
|
||||
pkg_list->at(dupl_pkg_index)->as_C_string(), module_name));
|
||||
} else if (existing_pkg != NULL) {
|
||||
throw_dup_pkg_exception(module_name, existing_pkg, CHECK);
|
||||
}
|
||||
|
||||
if (log_is_enabled(Debug, modules)) {
|
||||
@ -497,8 +499,8 @@ void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) {
|
||||
java_lang_reflect_Module::set_module_entry(module_handle(), unnamed_module);
|
||||
}
|
||||
|
||||
void Modules::add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS) {
|
||||
if (package == NULL) {
|
||||
void Modules::add_module_exports(jobject from_module, const char* package_name, jobject to_module, TRAPS) {
|
||||
if (package_name == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
|
||||
"package is null");
|
||||
}
|
||||
@ -526,10 +528,9 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t
|
||||
}
|
||||
}
|
||||
|
||||
PackageEntry *package_entry = get_package_entry(from_module_entry, package, CHECK);
|
||||
PackageEntry *package_entry = get_package_entry(from_module_entry, package_name, CHECK);
|
||||
ResourceMark rm(THREAD);
|
||||
if (package_entry == NULL) {
|
||||
const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Package %s not found in from_module %s",
|
||||
package_name != NULL ? package_name : "",
|
||||
@ -557,7 +558,7 @@ void Modules::add_module_exports(jobject from_module, jstring package, jobject t
|
||||
}
|
||||
|
||||
|
||||
void Modules::add_module_exports_qualified(jobject from_module, jstring package,
|
||||
void Modules::add_module_exports_qualified(jobject from_module, const char* package,
|
||||
jobject to_module, TRAPS) {
|
||||
if (to_module == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
|
||||
@ -649,21 +650,15 @@ jobject Modules::get_module(jclass clazz, TRAPS) {
|
||||
}
|
||||
|
||||
|
||||
jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) {
|
||||
jobject Modules::get_module_by_package_name(jobject loader, const char* package_name, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
assert(ModuleEntryTable::javabase_defined(),
|
||||
"Attempt to call get_module_from_pkg before " JAVA_BASE_NAME " is defined");
|
||||
|
||||
if (NULL == package) {
|
||||
if (package_name == NULL) {
|
||||
THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
|
||||
"package is null", JNI_FALSE);
|
||||
}
|
||||
const char* package_str =
|
||||
java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
|
||||
if (NULL == package_str) {
|
||||
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
"Invalid package", JNI_FALSE);
|
||||
}
|
||||
|
||||
Handle h_loader (THREAD, JNIHandles::resolve(loader));
|
||||
// Check that loader is a subclass of java.lang.ClassLoader.
|
||||
@ -672,7 +667,7 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA
|
||||
"Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE);
|
||||
}
|
||||
|
||||
if (strlen(package_str) == 0) {
|
||||
if (strlen(package_name) == 0) {
|
||||
// Return the unnamed module
|
||||
ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL);
|
||||
if (NULL == module_table) return NULL;
|
||||
@ -680,24 +675,24 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA
|
||||
return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module()));
|
||||
|
||||
} else {
|
||||
TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
|
||||
TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
|
||||
return get_module(package_sym, h_loader, CHECK_NULL);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
|
||||
jobject Modules::get_named_module(Handle h_loader, const char* package_name, TRAPS) {
|
||||
assert(ModuleEntryTable::javabase_defined(),
|
||||
"Attempt to call get_named_module before " JAVA_BASE_NAME " is defined");
|
||||
assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
|
||||
"Class loader is not a subclass of java.lang.ClassLoader");
|
||||
assert(package_str != NULL, "the package_str should not be NULL");
|
||||
assert(package_name != NULL, "the package_name should not be NULL");
|
||||
|
||||
if (strlen(package_str) == 0) {
|
||||
if (strlen(package_name) == 0) {
|
||||
return NULL;
|
||||
}
|
||||
TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
|
||||
TempNewSymbol package_sym = SymbolTable::new_symbol(package_name, CHECK_NULL);
|
||||
const PackageEntry* const pkg_entry =
|
||||
get_package_entry_by_name(package_sym, h_loader, THREAD);
|
||||
const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
|
||||
@ -723,14 +718,14 @@ jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Modules::add_module_package(jobject module, jstring package, TRAPS) {
|
||||
void Modules::add_module_package(jobject module, const char* package_name, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
|
||||
if (module == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
|
||||
"module is null");
|
||||
}
|
||||
if (package == NULL) {
|
||||
if (package_name == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
|
||||
"package is null");
|
||||
}
|
||||
@ -743,11 +738,6 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
"module cannot be an unnamed module");
|
||||
}
|
||||
char *package_name = java_lang_String::as_utf8_string(
|
||||
JNIHandles::resolve_non_null(package));
|
||||
if (package_name == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad package");
|
||||
}
|
||||
if (!verify_package_name(package_name)) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Invalid package name: %s", package_name));
|
||||
@ -760,12 +750,15 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
|
||||
!loader_data->is_platform_class_loader_data() &&
|
||||
strncmp(package_name, JAVAPKG, JAVAPKG_LEN) == 0) {
|
||||
const char* class_loader_name = SystemDictionary::loader_name(loader_data);
|
||||
StringUtils::replace_no_expand(package_name, "/", ".");
|
||||
size_t pkg_len = strlen(package_name);
|
||||
char* pkg_name = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, pkg_len);
|
||||
strncpy(pkg_name, package_name, pkg_len);
|
||||
StringUtils::replace_no_expand(pkg_name, "/", ".");
|
||||
const char* msg_text1 = "Class loader (instance of): ";
|
||||
const char* msg_text2 = " tried to define prohibited package name: ";
|
||||
size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + strlen(package_name) + 1;
|
||||
size_t len = strlen(msg_text1) + strlen(class_loader_name) + strlen(msg_text2) + pkg_len + 1;
|
||||
char* message = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, len);
|
||||
jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, package_name);
|
||||
jio_snprintf(message, len, "%s%s%s%s", msg_text1, class_loader_name, msg_text2, pkg_name);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), message);
|
||||
}
|
||||
|
||||
@ -776,31 +769,29 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
|
||||
PackageEntryTable* package_table = loader_data->packages();
|
||||
assert(package_table != NULL, "Missing package_table");
|
||||
|
||||
bool pkg_exists = false;
|
||||
PackageEntry* existing_pkg = NULL;
|
||||
{
|
||||
MutexLocker ml(Module_lock, THREAD);
|
||||
|
||||
// Check that the package does not exist in the class loader's package table.
|
||||
if (!package_table->lookup_only(pkg_symbol)) {
|
||||
existing_pkg = package_table->lookup_only(pkg_symbol);
|
||||
if (existing_pkg == NULL) {
|
||||
PackageEntry* pkg = package_table->locked_create_entry_or_null(pkg_symbol, module_entry);
|
||||
assert(pkg != NULL, "Unable to create a module's package entry");
|
||||
} else {
|
||||
pkg_exists = true;
|
||||
}
|
||||
}
|
||||
if (pkg_exists) {
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Package %s already exists for class loader", package_name));
|
||||
if (existing_pkg != NULL) {
|
||||
throw_dup_pkg_exception(module_entry->name()->as_C_string(), existing_pkg, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
// Export package in module to all unnamed modules.
|
||||
void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) {
|
||||
void Modules::add_module_exports_to_all_unnamed(jobject module, const char* package_name, TRAPS) {
|
||||
if (module == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
|
||||
"module is null");
|
||||
}
|
||||
if (package == NULL) {
|
||||
if (package_name == NULL) {
|
||||
THROW_MSG(vmSymbols::java_lang_NullPointerException(),
|
||||
"package is null");
|
||||
}
|
||||
@ -811,10 +802,9 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package,
|
||||
}
|
||||
|
||||
if (module_entry->is_named()) { // No-op for unnamed module.
|
||||
PackageEntry *package_entry = get_package_entry(module_entry, package, CHECK);
|
||||
PackageEntry *package_entry = get_package_entry(module_entry, package_name, CHECK);
|
||||
ResourceMark rm(THREAD);
|
||||
if (package_entry == NULL) {
|
||||
const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Package %s not found in module %s",
|
||||
package_name != NULL ? package_name : "",
|
||||
@ -833,10 +823,7 @@ void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package,
|
||||
package_entry->name()->as_C_string(),
|
||||
module_entry->name()->as_C_string());
|
||||
|
||||
// Mark package as exported to all unnamed modules, unless already
|
||||
// unqualifiedly exported.
|
||||
if (!package_entry->is_unqual_exported()) {
|
||||
package_entry->set_is_exported_allUnnamed();
|
||||
}
|
||||
// Mark package as exported to all unnamed modules.
|
||||
package_entry->set_is_exported_allUnnamed();
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,12 @@ public:
|
||||
// * Packages contains a duplicate package name
|
||||
// * A package already exists in another module for this class loader
|
||||
// * Module is an unnamed module
|
||||
// * num_packages is negative
|
||||
// * num_packages is non-zero when packages is null
|
||||
// NullPointerExceptions are thrown if module is null.
|
||||
static void define_module(jobject module, jstring version,
|
||||
jstring location, jobjectArray packages, TRAPS);
|
||||
jstring location, const char* const* packages,
|
||||
jsize num_packages, TRAPS);
|
||||
|
||||
// Provides the java.lang.reflect.Module for the unnamed module defined
|
||||
// to the boot loader.
|
||||
@ -72,7 +75,7 @@ public:
|
||||
// * Package is not syntactically correct
|
||||
// * Package is not defined for from_module's class loader
|
||||
// * Package is not in module from_module.
|
||||
static void add_module_exports(jobject from_module, jstring package, jobject to_module, TRAPS);
|
||||
static void add_module_exports(jobject from_module, const char* package, jobject to_module, TRAPS);
|
||||
|
||||
// This does a qualified export of package in module from_module to module
|
||||
// to_module. The format for the package name must use "/' not ".".
|
||||
@ -83,7 +86,7 @@ public:
|
||||
// * Package is not syntactically correct
|
||||
// * Package is not defined for from_module's class loader
|
||||
// * Package is not in module from_module.
|
||||
static void add_module_exports_qualified(jobject from_module, jstring package, jobject to_module, TRAPS);
|
||||
static void add_module_exports_qualified(jobject from_module, const char* package, jobject to_module, TRAPS);
|
||||
|
||||
// add_reads_module adds module to_module to the list of modules that from_module
|
||||
// can read. If from_module is the same as to_module then this is a no-op.
|
||||
@ -102,7 +105,7 @@ public:
|
||||
// NullPointerException is thrown if package is null.
|
||||
// IllegalArgumentException is thrown if loader is neither null nor a subtype of
|
||||
// java/lang/ClassLoader.
|
||||
static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS);
|
||||
static jobject get_module_by_package_name(jobject loader, const char* package, TRAPS);
|
||||
static jobject get_named_module(Handle h_loader, const char* package, TRAPS);
|
||||
|
||||
// If package is defined by loader, return the
|
||||
@ -116,16 +119,16 @@ public:
|
||||
// * Module is unnamed
|
||||
// * Package is not syntactically correct
|
||||
// * Package is already defined for module's class loader.
|
||||
static void add_module_package(jobject module, jstring package, TRAPS);
|
||||
static void add_module_package(jobject module, const char* package, TRAPS);
|
||||
|
||||
// Marks the specified package as exported to all unnamed modules.
|
||||
// If either module or package is null then NullPointerException is thrown.
|
||||
// If module or package is bad, or module is unnamed, or package is not in
|
||||
// module then IllegalArgumentException is thrown.
|
||||
static void add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS);
|
||||
static void add_module_exports_to_all_unnamed(jobject module, const char* package, TRAPS);
|
||||
|
||||
// Return TRUE if package_name is syntactically valid, false otherwise.
|
||||
static bool verify_package_name(char *package_name);
|
||||
static bool verify_package_name(const char *package_name);
|
||||
|
||||
// Return TRUE iff package is defined by loader
|
||||
static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user